From 0dc6006d7b1acfbba6790287cc3afbf34f14ef6a Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 19 Jun 2016 23:31:38 +0200 Subject: linux: update to 3.14.72, add working solidrun patch --- .../patches/3.14.69/0001-cec-hdmi.patch | 133 - .../patches/3.14.72/0001-solidrun-imx6.patch | 696919 ++++++++++++++++++ .../solidrun-imx6/patches/4.1.24/0001-xbian.patch | 314813 -------- .../arm/solidrun-imx6/patches/4.1.24/0002-rt.patch | 75 - .../solidrun-imx6/patches/4.1.26/0001-xbian.patch | 314813 ++++++++ .../arm/solidrun-imx6/patches/4.1.26/0002-rt.patch | 75 + 6 files changed, 1011807 insertions(+), 315021 deletions(-) delete mode 100644 target/arm/solidrun-imx6/patches/3.14.69/0001-cec-hdmi.patch create mode 100644 target/arm/solidrun-imx6/patches/3.14.72/0001-solidrun-imx6.patch delete mode 100644 target/arm/solidrun-imx6/patches/4.1.24/0001-xbian.patch delete mode 100644 target/arm/solidrun-imx6/patches/4.1.24/0002-rt.patch create mode 100644 target/arm/solidrun-imx6/patches/4.1.26/0001-xbian.patch create mode 100644 target/arm/solidrun-imx6/patches/4.1.26/0002-rt.patch (limited to 'target/arm/solidrun-imx6') diff --git a/target/arm/solidrun-imx6/patches/3.14.69/0001-cec-hdmi.patch b/target/arm/solidrun-imx6/patches/3.14.69/0001-cec-hdmi.patch deleted file mode 100644 index 6fbc80b00..000000000 --- a/target/arm/solidrun-imx6/patches/3.14.69/0001-cec-hdmi.patch +++ /dev/null @@ -1,133 +0,0 @@ -diff -Nur linux-3.14.45.orig/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c linux-3.14.45/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c ---- linux-3.14.45.orig/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c 2015-07-16 01:45:57.033999867 -0500 -+++ linux-3.14.45/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c 2015-07-16 01:44:12.826000821 -0500 -@@ -67,7 +67,6 @@ - u8 msg_len; - int tx_answer; - u16 latest_cec_stat; -- u8 link_status; - spinlock_t irq_lock; - struct delayed_work hdmi_cec_work; - struct mutex lock; -@@ -83,8 +82,6 @@ - - static LIST_HEAD(head); - --static int hdmi_cec_ready = 0; --static int hdmi_cec_started; - static int hdmi_cec_major; - static struct class *hdmi_cec_class; - static struct hdmi_cec_priv hdmi_cec_data; -@@ -98,7 +95,6 @@ - struct hdmi_cec_priv *hdmi_cec = data; - u16 cec_stat = 0; - unsigned long flags; -- u8 phy_stat0; - irqreturn_t ret = IRQ_HANDLED; - - spin_lock_irqsave(&hdmi_cec->irq_lock, flags); -@@ -107,7 +103,6 @@ - - cec_stat = hdmi_readb(HDMI_IH_CEC_STAT0); - hdmi_writeb(cec_stat, HDMI_IH_CEC_STAT0); -- phy_stat0 = hdmi_readb(HDMI_PHY_STAT0) & 0x02; - - if ((cec_stat & (HDMI_IH_CEC_STAT0_ERROR_INIT | \ - HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | \ -@@ -115,14 +110,7 @@ - ret = IRQ_NONE; - cec_stat = 0; - } -- if (hdmi_cec->link_status ^ phy_stat0) { -- /* HPD value changed */ -- hdmi_cec->link_status = phy_stat0; -- if (hdmi_cec->link_status) -- cec_stat |= 0x80; /* Connected */ -- else -- cec_stat |= 0x100; /* Disconnected */ -- } -+ - pr_debug("HDMI CEC interrupt received\n"); - hdmi_cec->latest_cec_stat = cec_stat ; - -@@ -315,7 +303,7 @@ - mutex_unlock(&hdmi_cec_data.lock); - return -EACCES; - } -- /* Ensure that there is only one writer who is the only listener of tx_cec_queue */ -+ /* Ensure that there is only one writer who is the unique listener of tx_cec_queue */ - if (hdmi_cec_data.tx_answer != CEC_TX_AVAIL) { - mutex_unlock(&hdmi_cec_data.lock); - return -EBUSY; -@@ -363,9 +351,6 @@ - { - u8 val; - -- if (!hdmi_cec_ready || hdmi_cec_started) -- return; -- - val = hdmi_readb(HDMI_MC_CLKDIS); - val &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; - hdmi_writeb(val, HDMI_MC_CLKDIS); -@@ -377,12 +362,7 @@ - val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL | HDMI_IH_CEC_STAT0_ARB_LOST; - hdmi_writeb(val, HDMI_CEC_MASK); - hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0); -- hdmi_cec_data.link_status = hdmi_readb(HDMI_PHY_STAT0) & 0x02; -- mutex_lock(&hdmi_cec_data.lock); - hdmi_cec_data.cec_state = true; -- mutex_unlock(&hdmi_cec_data.lock); -- -- hdmi_cec_started = 1; - } - EXPORT_SYMBOL(hdmi_cec_start_device); - -@@ -390,9 +370,6 @@ - { - u8 val; - -- if (!hdmi_cec_ready || !hdmi_cec_started) -- return; -- - hdmi_writeb(0x10, HDMI_CEC_CTRL); - val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL | HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_ARB_LOST | \ - HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | HDMI_IH_CEC_STAT0_DONE; -@@ -402,11 +379,7 @@ - val = hdmi_readb(HDMI_MC_CLKDIS); - val |= HDMI_MC_CLKDIS_CECCLK_DISABLE; - hdmi_writeb(val, HDMI_MC_CLKDIS); -- mutex_lock(&hdmi_cec_data.lock); - hdmi_cec_data.cec_state = false; -- mutex_unlock(&hdmi_cec_data.lock); -- -- hdmi_cec_started = 0; - } - EXPORT_SYMBOL(hdmi_cec_stop_device); - -@@ -481,11 +454,18 @@ - */ - static int hdmi_cec_release(struct inode *inode, struct file *filp) - { -+ struct hdmi_cec_event *event, *tmp_event; - mutex_lock(&hdmi_cec_data.lock); - if (open_count) { - open_count = 0; - hdmi_cec_data.cec_state = false; - hdmi_cec_data.Logical_address = 15; -+ -+ /* Flush eventual events which have not been read by user space */ -+ list_for_each_entry_safe(event, tmp_event, &head, list) { -+ list_del(&event->list); -+ vfree(event); -+ } - } - mutex_unlock(&hdmi_cec_data.lock); - -@@ -580,7 +560,6 @@ - INIT_DELAYED_WORK(&hdmi_cec_data.hdmi_cec_work, mxc_hdmi_cec_worker); - - dev_info(&pdev->dev, "HDMI CEC initialized\n"); -- hdmi_cec_ready = 1; - goto out; - - err_out_class: diff --git a/target/arm/solidrun-imx6/patches/3.14.72/0001-solidrun-imx6.patch b/target/arm/solidrun-imx6/patches/3.14.72/0001-solidrun-imx6.patch new file mode 100644 index 000000000..3e6393cb2 --- /dev/null +++ b/target/arm/solidrun-imx6/patches/3.14.72/0001-solidrun-imx6.patch @@ -0,0 +1,696919 @@ +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-cm-fx6.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-cm-fx6.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-cm-fx6.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-cm-fx6.dts 2016-06-19 22:11:55.009158180 +0200 +@@ -0,0 +1,21 @@ ++/* ++ * Copyright 2015 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 "imx6dl.dtsi" ++#include "imx6qdl-cm-fx6.dtsi" ++ ++/ { ++ model = "CompuLab CM-FX6"; ++ compatible = "compulab,cm-fx6", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-cubox-i.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-cubox-i.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-cubox-i.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-cubox-i.dts 2016-06-19 22:11:55.009158180 +0200 +@@ -1,5 +1,43 @@ + /* + * Copyright (C) 2014 Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. + */ + /dts-v1/; + +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl.dtsi linux-3.14.72/arch/arm/boot/dts/imx6dl.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl.dtsi 2016-06-19 22:11:55.009158180 +0200 +@@ -8,6 +8,7 @@ + * + */ + ++#include + #include "imx6dl-pinfunc.h" + #include "imx6qdl.dtsi" + +@@ -16,11 +17,37 @@ + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <0>; + next-level-cache = <&L2>; ++ operating-points = < ++ /* kHz uV */ ++ 996000 1275000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC-PU uV */ ++ 996000 1175000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++ clock-latency = <61036>; /* two CLK32 periods */ ++ clocks = <&clks IMX6QDL_CLK_ARM>, ++ <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, ++ <&clks IMX6QDL_CLK_STEP>, ++ <&clks IMX6QDL_CLK_PLL1_SW>, ++ <&clks IMX6QDL_CLK_PLL1_SYS>, ++ <&clks IMX6QDL_PLL1_BYPASS>, ++ <&clks IMX6QDL_CLK_PLL1>, ++ <&clks IMX6QDL_PLL1_BYPASS_SRC> ; ++ clock-names = "arm", "pll2_pfd2_396m", "step", ++ "pll1_sw", "pll1_sys", "pll1_bypass", "pll1", "pll1_bypass_src"; ++ arm-supply = <®_arm>; ++ pu-supply = <®_pu>; ++ soc-supply = <®_soc>; + }; + + cpu@1 { +@@ -32,40 +59,117 @@ + }; + + soc { +- ocram: sram@00900000 { ++ busfreq { ++ compatible = "fsl,imx6_busfreq"; ++ clocks = <&clks IMX6QDL_CLK_PLL2_BUS>, <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, ++ <&clks IMX6QDL_CLK_PLL2_198M>, <&clks IMX6QDL_CLK_ARM>, ++ <&clks IMX6QDL_CLK_PLL3_USB_OTG>, <&clks IMX6QDL_CLK_PERIPH>, ++ <&clks IMX6QDL_CLK_PERIPH_PRE>, <&clks IMX6QDL_CLK_PERIPH_CLK2>, ++ <&clks IMX6QDL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6QDL_CLK_OSC>, ++ <&clks IMX6QDL_CLK_AXI_ALT_SEL>, <&clks IMX6QDL_CLK_AXI_SEL> , ++ <&clks IMX6QDL_CLK_PLL3_PFD1_540M>; ++ clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", ++ "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", "axi_alt_sel", "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 IRQ_TYPE_LEVEL_HIGH>, ++ <0 10 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "irq_3d", "irq_2d"; ++ clocks = <&clks IMX6QDL_CLK_OPENVG_AXI>, <&clks IMX6QDL_CLK_GPU3D_AXI>, ++ <&clks IMX6QDL_CLK_GPU2D_CORE>, <&clks IMX6QDL_CLK_GPU3D_CORE>, ++ <&clks IMX6QDL_CLK_DUMMY>; ++ clock-names = "gpu2d_axi_clk", "gpu3d_axi_clk", ++ "gpu2d_clk", "gpu3d_clk", ++ "gpu3d_shader_clk"; ++ resets = <&src 0>, <&src 3>; ++ reset-names = "gpu3d", "gpu2d"; ++ power-domains = <&gpc 1>; ++ }; ++ ++ ocrams: sram@00900000 { ++ compatible = "fsl,lpm-sram"; ++ reg = <0x00900000 0x4000>; ++ clocks = <&clks IMX6QDL_CLK_OCRAM>; ++ }; ++ ++ ocrams_ddr: sram@00904000 { ++ compatible = "fsl,ddr-lpm-sram"; ++ reg = <0x00904000 0x1000>; ++ clocks = <&clks IMX6QDL_CLK_OCRAM>; ++ }; ++ ++ ocram: sram@00905000 { + compatible = "mmio-sram"; +- reg = <0x00900000 0x20000>; +- clocks = <&clks 142>; ++ reg = <0x00905000 0x1B000>; ++ clocks = <&clks IMX6QDL_CLK_OCRAM>; + }; + + aips1: aips-bus@02000000 { ++ vpu@02040000 { ++ iramsize = <0>; ++ }; ++ + iomuxc: iomuxc@020e0000 { + compatible = "fsl,imx6dl-iomuxc"; + }; + ++ dcic2: dcic@020e8000 { ++ clocks = <&clks IMX6QDL_CLK_DCIC1 >, ++ <&clks IMX6QDL_CLK_DCIC2>; /* DCIC2 depend on DCIC1 clock in imx6dl*/ ++ clock-names = "dcic", "disp-axi"; ++ }; ++ + pxp: pxp@020f0000 { ++ compatible = "fsl,imx6dl-pxp-dma"; + reg = <0x020f0000 0x4000>; +- interrupts = <0 98 0x04>; ++ interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_IPU2>, <&clks IMX6QDL_CLK_DUMMY>; ++ clock-names = "pxp-axi", "disp-axi"; ++ status = "disabled"; + }; + + epdc: epdc@020f4000 { ++ compatible = "fsl,imx6dl-epdc"; + reg = <0x020f4000 0x4000>; +- interrupts = <0 97 0x04>; ++ interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_IPU2>, <&clks IMX6QDL_CLK_IPU2_DI1>; ++ clock-names = "epdc_axi", "epdc_pix"; ++ status = "disabled"; + }; + + 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 IMX6QDL_CLK_HSI_TX>, <&clks IMX6QDL_CLK_VIDEO_27M>; ++ 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 IMX6DL_CLK_I2C4>; + status = "disabled"; + }; + }; +@@ -73,18 +177,18 @@ + }; + + &ldb { +- clocks = <&clks 33>, <&clks 34>, +- <&clks 39>, <&clks 40>, +- <&clks 135>, <&clks 136>; +- clock-names = "di0_pll", "di1_pll", +- "di0_sel", "di1_sel", +- "di0", "di1"; +- +- lvds-channel@0 { +- crtcs = <&ipu1 0>, <&ipu1 1>; +- }; ++ compatible = "fsl,imx6dl-ldb", "fsl,imx53-ldb"; + +- lvds-channel@1 { +- crtcs = <&ipu1 0>, <&ipu1 1>; +- }; ++ clocks = <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>, ++ <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, ++ <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, ++ <&clks IMX6QDL_CLK_LDB_DI0_DIV_3_5>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_3_5>, ++ <&clks IMX6QDL_CLK_LDB_DI0_DIV_7>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_7>, ++ <&clks IMX6QDL_CLK_LDB_DI0_DIV_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_SEL>; ++ clock-names = "ldb_di0", "ldb_di1", ++ "di0_sel", "di1_sel", ++ "di2_sel", ++ "ldb_di0_div_3_5", "ldb_di1_div_3_5", ++ "ldb_di0_div_7", "ldb_di1_div_7", ++ "ldb_di0_div_sel", "ldb_di1_div_sel"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-hummingboard2.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-hummingboard2.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-hummingboard2.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-hummingboard2.dts 2016-06-19 22:11:55.009158180 +0200 +@@ -0,0 +1,52 @@ ++/* ++ * Device Tree file for SolidRun HummingBoard2 ++ * Copyright (C) 2015 Rabeeh Khoury ++ * Based on work by Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. ++ */ ++/dts-v1/; ++ ++#include "imx6dl.dtsi" ++#include "imx6qdl-hummingboard2.dtsi" ++ ++/ { ++ model = "SolidRun HummingBoard2 Solo/DualLite"; ++ compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-hummingboard.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-hummingboard.dts 2016-06-19 22:11:55.013158022 +0200 +@@ -1,163 +1,51 @@ + /* +- * Copyright (C) 2013,2014 Russell King ++ * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) ++ * Based on dt work by Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. + */ + /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.72.orig/arch/arm/boot/dts/imx6dl-pinfunc.h linux-3.14.72/arch/arm/boot/dts/imx6dl-pinfunc.h +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-pinfunc.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-pinfunc.h 2016-06-19 22:11:55.013158022 +0200 +@@ -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 +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto.dts 2016-06-19 22:11:55.013158022 +0200 +@@ -15,3 +15,21 @@ + model = "Freescale i.MX6 DualLite/Solo SABRE Automotive Board"; + compatible = "fsl,imx6dl-sabreauto", "fsl,imx6dl"; + }; ++ ++&ldb { ++ lvds-channel@0 { ++ crtc = "ipu1-di0"; ++ }; ++ ++ lvds-channel@1 { ++ crtc = "ipu1-di1"; ++ }; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts 2016-06-19 22:11:55.013158022 +0200 +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6dl-sabreauto.dts" ++ ++&ecspi1 { ++ pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ /* pin conflict with ecspi1 */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* the uart3 depends on the i2c3, so disable it too. */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts 2016-06-19 22:11:55.013158022 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6dl-sabreauto.dts" ++ ++&flexcan1{ ++ status = "okay"; ++}; ++ ++&fec { ++ /* pin conflict with flexcan1 */ ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts 2016-06-19 22:11:55.013158022 +0200 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6dl-sabreauto.dts" ++ ++&ecspi1 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&gpmi { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* pin conflict with gpmi and weim */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; ++ ++&weim { ++ pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd.dts 2016-06-19 22:11:55.013158022 +0200 +@@ -15,3 +15,138 @@ + model = "Freescale i.MX6 DualLite SABRE Smart Device Board"; + compatible = "fsl,imx6dl-sabresd", "fsl,imx6dl"; + }; ++ ++&battery { ++ offset-charger = <1485>; ++ offset-discharger = <1464>; ++ offset-usb-charger = <1285>; ++}; ++ ++&iomuxc { ++ epdc { ++ pinctrl_epdc_0: epdcgrp-0 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A16__EPDC_DATA00 0x80000000 ++ MX6QDL_PAD_EIM_DA10__EPDC_DATA01 0x80000000 ++ MX6QDL_PAD_EIM_DA12__EPDC_DATA02 0x80000000 ++ MX6QDL_PAD_EIM_DA11__EPDC_DATA03 0x80000000 ++ MX6QDL_PAD_EIM_LBA__EPDC_DATA04 0x80000000 ++ MX6QDL_PAD_EIM_EB2__EPDC_DATA05 0x80000000 ++ MX6QDL_PAD_EIM_CS0__EPDC_DATA06 0x80000000 ++ MX6QDL_PAD_EIM_RW__EPDC_DATA07 0x80000000 ++ MX6QDL_PAD_EIM_A21__EPDC_GDCLK 0x80000000 ++ MX6QDL_PAD_EIM_A22__EPDC_GDSP 0x80000000 ++ MX6QDL_PAD_EIM_A23__EPDC_GDOE 0x80000000 ++ MX6QDL_PAD_EIM_A24__EPDC_GDRL 0x80000000 ++ MX6QDL_PAD_EIM_D31__EPDC_SDCLK_P 0x80000000 ++ MX6QDL_PAD_EIM_D27__EPDC_SDOE 0x80000000 ++ MX6QDL_PAD_EIM_DA1__EPDC_SDLE 0x80000000 ++ MX6QDL_PAD_EIM_EB1__EPDC_SDSHR 0x80000000 ++ MX6QDL_PAD_EIM_DA2__EPDC_BDR0 0x80000000 ++ MX6QDL_PAD_EIM_DA4__EPDC_SDCE0 0x80000000 ++ MX6QDL_PAD_EIM_DA5__EPDC_SDCE1 0x80000000 ++ MX6QDL_PAD_EIM_DA6__EPDC_SDCE2 0x80000000 ++ >; ++ }; ++ }; ++}; ++ ++&epdc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_epdc_0>; ++ V3P3-supply = <&V3P3_reg>; ++ VCOM-supply = <&VCOM_reg>; ++ DISPLAY-supply = <&DISPLAY_reg>; ++ status = "okay"; ++}; ++ ++&i2c3 { ++ max17135@48 { ++ compatible = "maxim,max17135"; ++ reg = <0x48>; ++ vneg_pwrup = <1>; ++ gvee_pwrup = <1>; ++ vpos_pwrup = <2>; ++ gvdd_pwrup = <1>; ++ gvdd_pwrdn = <1>; ++ vpos_pwrdn = <2>; ++ gvee_pwrdn = <1>; ++ vneg_pwrdn = <1>; ++ SENSOR-supply = <®_sensor>; ++ gpio_pmic_pwrgood = <&gpio2 21 0>; ++ gpio_pmic_vcom_ctrl = <&gpio3 17 0>; ++ gpio_pmic_wakeup = <&gpio3 20 0>; ++ gpio_pmic_v3p3 = <&gpio2 20 0>; ++ gpio_pmic_intr = <&gpio2 25 0>; ++ ++ regulators { ++ DISPLAY_reg: DISPLAY { ++ regulator-name = "DISPLAY"; ++ }; ++ ++ GVDD_reg: GVDD { ++ /* 20v */ ++ regulator-name = "GVDD"; ++ }; ++ ++ GVEE_reg: GVEE { ++ /* -22v */ ++ regulator-name = "GVEE"; ++ }; ++ ++ HVINN_reg: HVINN { ++ /* -22v */ ++ regulator-name = "HVINN"; ++ }; ++ ++ HVINP_reg: HVINP { ++ /* 20v */ ++ regulator-name = "HVINP"; ++ }; ++ ++ VCOM_reg: VCOM { ++ regulator-name = "VCOM"; ++ /* 2's-compliment, -4325000 */ ++ regulator-min-microvolt = <0xffbe0178>; ++ /* 2's-compliment, -500000 */ ++ regulator-max-microvolt = <0xfff85ee0>; ++ }; ++ ++ VNEG_reg: VNEG { ++ /* -15v */ ++ regulator-name = "VNEG"; ++ }; ++ ++ VPOS_reg: VPOS { ++ /* 15v */ ++ regulator-name = "VPOS"; ++ }; ++ ++ V3P3_reg: V3P3 { ++ regulator-name = "V3P3"; ++ }; ++ }; ++ }; ++}; ++ ++&ldb { ++ lvds-channel@0 { ++ crtc = "ipu1-di0"; ++ }; ++ ++ lvds-channel@1 { ++ crtc = "ipu1-di1"; ++ }; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&pxp { ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd-enetirq.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-enetirq.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd-enetirq.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-enetirq.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6dl-sabresd.dts" ++ ++&fec { ++ pinctrl-0 = <&pinctrl_enet &pinctrl_enet_irq>; ++ interrupts-extended = <&gpio1 6 0x04>, <&intc 0 119 0x04>; ++}; ++ ++&i2c3 { ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (C) 2013-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 ++ * 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.72.orig/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6dl-sabresd.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++}; ++ ++&gpc { ++ /* use ldo-enable, u-boot will check it and configure */ ++ fsl,ldo-bypass = <0>; ++ /* watchdog select of reset source */ ++ fsl,wdog-reset = <1>; ++}; ++ ++&wdog1 { ++ status = "okay"; ++}; ++ ++&wdog2 { ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd-pf200.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-pf200.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sabresd-pf200.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sabresd-pf200.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,13 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6dl-sabresd-ldo.dts" ++ ++&pmic { ++ compatible = "fsl,pfuze200"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sbc-fx6.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sbc-fx6.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sbc-fx6.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sbc-fx6.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,23 @@ ++/* ++* Copyright 2015 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 "imx6dl.dtsi" ++#include "imx6qdl-cm-fx6.dtsi" ++#include "imx6qdl-sb-fx6x.dtsi" ++#include "imx6qdl-sb-fx6.dtsi" ++ ++/ { ++ model = "CompuLab CM-FX6 on SBC-FX6"; ++ compatible = "compulab,cm-fx6", "compulab,sbc-fx6", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,23 @@ ++/* ++* Copyright 2015 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 "imx6dl.dtsi" ++#include "imx6qdl-cm-fx6.dtsi" ++#include "imx6qdl-sb-fx6x.dtsi" ++#include "imx6qdl-sb-fx6m.dtsi" ++ ++/ { ++ model = "CompuLab CM-FX6 on SBC-FX6m"; ++ compatible = "compulab,cm-fx6", "compulab,sbc-fx6m", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-udoo.dts linux-3.14.72/arch/arm/boot/dts/imx6dl-udoo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6dl-udoo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6dl-udoo.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,21 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * ++ * Author: Fabio Estevam ++ * Author: Ettore Chimenti ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++/dts-v1/; ++#include "imx6dl.dtsi" ++#include "imx6qdl-udoo.dtsi" ++ ++/ { ++ model = "Udoo i.MX6 Dual-lite Board"; ++ compatible = "udoo,imx6dl-udoo", "fsl,imx6dl"; ++}; ++ +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-arm2.dts linux-3.14.72/arch/arm/boot/dts/imx6q-arm2.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-arm2.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-arm2.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -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,46 +59,173 @@ + + &gpmi { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; + status = "disabled"; /* gpmi nand conflicts with SD */ ++ nand-on-flash-bbt; + }; + + &iomuxc { + 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 ++ >; ++ }; ++ ++ 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_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 ++ >; ++ }; ++ ++ 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 ++ >; ++ }; ++ ++ 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"; + status = "okay"; + }; + ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ + &usdhc3 { + cd-gpios = <&gpio6 11 0>; + 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 +233,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 +247,6 @@ + + &uart4 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart4_1>; ++ pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-arm2-hsic.dts linux-3.14.72/arch/arm/boot/dts/imx6q-arm2-hsic.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-arm2-hsic.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-arm2-hsic.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright 2015 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.72.orig/arch/arm/boot/dts/imx6q-auvidea.dts linux-3.14.72/arch/arm/boot/dts/imx6q-auvidea.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-auvidea.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-auvidea.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) ++ * Based on dt work by Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. ++ */ ++/dts-v1/; ++ ++#include "imx6q.dtsi" ++#include "imx6qdl-auvidea.dtsi" ++ ++/ { ++ model = "SolidRun HummingBoard Dual/Quad"; ++ compatible = "solidrun,hummingboard/q", "fsl,imx6q"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-cm-fx6.dts linux-3.14.72/arch/arm/boot/dts/imx6q-cm-fx6.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-cm-fx6.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-cm-fx6.dts 2016-06-19 22:11:55.017158023 +0200 +@@ -0,0 +1,21 @@ ++/* ++ * Copyright 2014 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" ++#include "imx6q-cm-fx6.dtsi" ++ ++/ { ++ model = "CompuLab CM-FX6"; ++ compatible = "compulab,cm-fx6", "fsl,imx6q"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-cm-fx6.dtsi linux-3.14.72/arch/arm/boot/dts/imx6q-cm-fx6.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-cm-fx6.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-cm-fx6.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -0,0 +1,95 @@ ++/* ++ * Copyright 2014 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 ++ */ ++ ++#include "imx6qdl-cm-fx6.dtsi" ++ ++/ { ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_sata_ldo_en: sata_ldo_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "cm_fx6_sata_ldo_en"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio2 16 0>; ++ startup-delay-us = <100>; ++ enable-active-high; ++ }; ++ ++ reg_sata_phy_slp: sata_phy_slp { ++ compatible = "regulator-fixed"; ++ regulator-name = "cm_fx6_sata_phy_slp"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio3 23 0>; ++ startup-delay-us = <100>; ++ enable-active-high; ++ vin-supply = <®_sata_ldo_en>; ++ }; ++ ++ reg_sata_nrstdly: sata_nrstdly { ++ compatible = "regulator-fixed"; ++ regulator-name = "cm_fx6_sata_nrstdly"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio6 6 0>; ++ startup-delay-us = <100>; ++ enable-active-high; ++ vin-supply = <®_sata_phy_slp>; ++ }; ++ ++ reg_sata_pwren: sata_pwren { ++ compatible = "regulator-fixed"; ++ regulator-name = "cm_fx6_sata_pwren"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio1 28 0>; ++ startup-delay-us = <100>; ++ enable-active-high; ++ vin-supply = <®_sata_nrstdly>; ++ }; ++ ++ reg_sata_nstandby1: sata_nstandby1 { ++ compatible = "regulator-fixed"; ++ regulator-name = "cm_fx6_sata_nstandby1"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio3 20 0>; ++ startup-delay-us = <100>; ++ enable-active-high; ++ vin-supply = <®_sata_pwren>; ++ }; ++ ++ reg_sata_nstandby2: sata_nstandby2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "cm_fx6_sata_nstandby2"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio5 2 0>; ++ startup-delay-us = <100>; ++ enable-active-high; ++ regulator-boot-on; ++ vin-supply = <®_sata_nstandby1>; ++ }; ++ ++ }; ++ ++}; ++ ++/* sata */ ++&sata { ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-cubox-i.dts linux-3.14.72/arch/arm/boot/dts/imx6q-cubox-i.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-cubox-i.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-cubox-i.dts 2016-06-19 22:11:55.021158011 +0200 +@@ -1,5 +1,43 @@ + /* + * Copyright (C) 2014 Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. + */ + /dts-v1/; + +@@ -13,4 +51,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.72.orig/arch/arm/boot/dts/imx6qdl-auvidea.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-auvidea.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-auvidea.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-auvidea.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -0,0 +1,393 @@ ++/* ++ * Copyright (C) 2013,2014 Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. ++ */ ++#include "imx6qdl-microsom.dtsi" ++#include "imx6qdl-microsom-ar8035.dtsi" ++ ++/ { ++ aliases { ++ mmc0 = &usdhc2; ++ mmc1 = &usdhc1; ++ mxcfb0 = &mxcfb1; ++ }; ++ ++ chosen { ++ bootargs = "quiet console=ttymxc0,115200 root=/dev/mmcblk0p2 rw"; ++ stdout-path = &uart1; ++ }; ++ ++ 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"; ++ }; ++ ++ 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>; ++ }; ++ ++ reg_usdhc2_vbus: usdhc-2-vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "USDHC2-VBUS"; ++ gpio = <&gpio4 30 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_usdhc2_pwr>; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ }; ++ ++ 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>; ++ cpu-dai = <&ssi1>; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ mipi_camera = <1>; ++ default_input = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ status = "okay"; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-hdmi"; ++ 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"; ++}; ++ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_i2c1>; ++ status = "okay"; ++ ++ /* Pro baseboard model */ ++ sgtl5000: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks IMX6QDL_CLK_CKO>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_sgtl5000>; ++ VDDA-supply = <®_3p3v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++ ++ tc358743_mipi: tc358743_mipi@0f { ++ compatible = "tc358743_mipi"; ++ reg = <0x0f>; ++ clocks = <&clks IMX6QDL_CLK_CKO>; ++ clock-names = "csi_mclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_mipi>; ++ rst-gpios = <&gpio6 15 GPIO_ACTIVE_HIGH>; ++ interrupts-extended = <&gpio2 10 IRQ_TYPE_LEVEL_LOW>; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk = <27000000>; ++ mclk_source = <0>; ++ }; ++}; ++ ++&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>; ++ }; ++}; ++ ++&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 0x1b0b1 ++ >; ++ }; ++ ++ 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_mipi: hummingboard_mipi { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x17059 ++ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x13059 ++ >; ++ }; ++ ++ pinctrl_hummingboard_pwm1: pwm1grp { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_sgtl5000: hummingboard-sgtl5000 { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 ++ MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 ++ MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 ++ MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 ++ MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 ++ >; ++ }; ++ ++ 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_pwr: hummingboard-usdhc2-pwr { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_usdhc2_aux: hummingboard-usdhc2-aux { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x13071 ++ >; ++ }; ++ ++ 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 ++ >; ++ }; ++ }; ++}; ++ ++&mipi_csi { ++ ipu_id = <0>; ++ csi_id = <0>; ++ v_channel = <0>; ++ lanes = <4>; ++ mipi_dphy_clk = /bits/ 8 <0x14>; ++ status = "okay"; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_pwm1>; ++ status = "okay"; ++}; ++ ++&pwm2 { ++ pinctrl-names = "default"; ++ 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 ++ >; ++ ++ card-external-vcc-supply = <®_usdhc2_vbus>; ++ cd-gpios = <&gpio1 4 0>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -0,0 +1,643 @@ ++/* ++ * Copyright 2014 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 ++ */ ++ ++#define MX6QDL_GPR1 0x04 0x04 0x000 0x0 0x0 ++#define MX6QDL_GPR6 0x18 0x18 0x000 0x0 0x0 ++#define MX6QDL_GPR7 0x1c 0x1c 0x000 0x0 0x0 ++ ++/ { ++ memory { ++ reg = <0x10000000 0x20000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ heartbeat-led { ++ label = "Heartbeat"; ++ gpios = <&gpio2 31 0>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_3p3v: 3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ /* regulator for usb otg */ ++ 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; ++ }; ++ ++ /* regulator1 for pcie power-on-gpio */ ++ pcie_power_on_gpio: regulator-pcie-power-on-gpio { ++ compatible = "regulator-fixed"; ++ regulator-name = "regulator-pcie-power-on-gpio"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio2 24 0>; ++ enable-active-high; ++ }; ++ ++ /* regulator for usb hub1 */ ++ reg_usb_h1_vbus: usb_h1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio7 8 0>; ++ enable-active-high; ++ }; ++ ++ /* regulator1 for wifi/bt */ ++ awnh387_npoweron: regulator-awnh387-npoweron { ++ compatible = "regulator-fixed"; ++ regulator-name = "regulator-awnh387-npoweron"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio7 12 0>; ++ enable-active-high; ++ }; ++ ++ /* regulator2 for wifi/bt */ ++ awnh387_wifi_nreset: regulator-awnh387-wifi-nreset { ++ compatible = "regulator-fixed"; ++ regulator-name = "regulator-awnh387-wifi-nreset"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio6 16 0>; ++ startup-delay-us = <10000>; ++ }; ++ ++ tsc2046reg: tsc2046-reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "tsc2046-reg"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ }; ++ ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ }; ++ ++ sound { ++ compatible = "fsl,imx-audio-wm8731"; ++ model = "wm8731-audio"; ++ ssi-controller = <&ssi2>; ++ src-port = <2>; ++ ext-port = <4>; ++ audio-codec = <&codec>; ++ audio-routing = "LOUT", "ROUT", "LLINEIN", "RLINEIN"; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-out; ++ spdif-in; ++ }; ++ ++ 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 = "disabled"; ++ }; ++ ++ mxcfb2: fb@1 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "lcd"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1920x1080M@60"; ++ default_bpp = <32>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ mxcfb3: fb@2 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str ="1366x768M-18@60"; ++ 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 ="1280x800M-18@60"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ lcd@0 { ++ compatible = "fsl,lcd"; ++ ipu_id = <0>; ++ disp_id = <0>; ++ default_ifmt = "RGB24"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_lcd>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++ ++ restart_poweroff { ++ compatible = "fsl,snvs-poweroff"; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ hog { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_GPR1 0x48400005 ++ /* ipu3 QoS */ ++ MX6QDL_GPR6 0x007f007f ++ MX6QDL_GPR7 0x007f007f ++ /* SATA PWR */ ++ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x80000000 ++ MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x80000000 ++ MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x80000000 ++ MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x80000000 ++ /* SATA CTRL */ ++ MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 ++ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 ++ MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x80000000 ++ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 ++ /* POWER_BUTTON */ ++ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 ++ >; ++ }; ++ }; ++ ++ imx6q-cm-fx6 { ++ /* pins for eth0 */ ++ 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 ++ >; ++ }; ++ ++ pinctrl_ipu1_lcd: ipu1grp-lcd { ++ fsl,pins = < ++ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x38 ++ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x38 ++ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x38 ++ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x38 ++ MX6QDL_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x80000028 ++ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x38 ++ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x38 ++ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x38 ++ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x38 ++ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x38 ++ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x38 ++ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x38 ++ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x38 ++ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x38 ++ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x38 ++ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x38 ++ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x38 ++ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x38 ++ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x38 ++ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x38 ++ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x38 ++ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x38 ++ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x38 ++ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x38 ++ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x38 ++ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x38 ++ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x38 ++ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x38 ++ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x38 ++ >; ++ }; ++ ++ /* pins for spi */ ++ pinctrl_ecspi1: ecspi1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 ++ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 ++ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 ++ MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x100b1 ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x100b1 ++ >; ++ }; ++ ++ /* pins for nand */ ++ 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 ++ >; ++ }; ++ ++ /* pins for i2c2 */ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ /* pins for i2c3 */ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ /* pins for console */ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ /* pins for usb hub1 */ ++ pinctrl_usbh1: usbh1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x80000000 ++ >; ++ }; ++ ++ /* pins for usb otg */ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 ++ >; ++ }; ++ ++ /* pins for wifi/bt */ ++ pinctrl_usdhc1: usdhc1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17071 ++ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10071 ++ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17071 ++ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17071 ++ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17071 ++ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17071 ++ >; ++ }; ++ ++ /* pins for wifi/bt */ ++ pinctrl_mrvl1: mrvl1grp { ++ fsl,pins = < ++ /* WIFI_PWR_RST */ ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 ++ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x80000000 ++ >; ++ }; ++ ++ /* pins for tsc2046 pendown */ ++ pinctrl_tsc2046: tsc2046grp { ++ fsl,pins = < ++ /* tsc2046 PENDOWN */ ++ MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x80000000 ++ >; ++ }; ++ ++ /* pins for pcie */ ++ pinctrl_pcie: pciegrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 ++ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x80000000 ++ >; ++ }; ++ ++ /* pins for spdif */ ++ pinctrl_spdif: spdifgrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_16__SPDIF_IN 0x1b0b0 ++ MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x1b0b0 ++ >; ++ }; ++ ++ /* pins for audmux */ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__AUD4_RXC 0x17059 ++ MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x17059 ++ MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x17059 ++ MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x17059 ++ MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x17059 ++ /* master mode pin */ ++ MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x17059 ++ >; ++ }; ++ ++ pinctrl_hdmi_hdcp: hdmihdcpgrp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pwm3_1: pwm3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_flexcan1_1: flexcan1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 ++ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 ++ >; ++ }; ++ }; ++}; ++ ++&cpu0 { ++ operating-points = < ++ /* kHz uV */ ++ 1248000 1300000 ++ 1200000 1275000 ++ 1128000 1275000 ++ 996000 1250000 ++ 852000 1250000 ++ 792000 1150000 ++ 396000 975000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC-PU uV */ ++ 1248000 1300000 ++ 1200000 1275000 ++ 1128000 1275000 ++ 996000 1250000 ++ 852000 1250000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++}; ++ ++/* spi */ ++&ecspi1 { ++ fsl,spi-num-chipselects = <2>; ++ cs-gpios = <&gpio2 30 0>, <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25px16", "st,m25p"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ ++ partition@0 { ++ label = "uboot"; ++ reg = <0x0 0xc0000>; ++ }; ++ ++ partition@c0000 { ++ label = "uboot environment"; ++ reg = <0xc0000 0x40000>; ++ }; ++ ++ partition@100000 { ++ label = "reserved"; ++ reg = <0x100000 0x100000>; ++ }; ++ }; ++ ++ /* touch controller */ ++ touch: tsc2046@1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_tsc2046>; ++ ++ compatible = "ti,tsc2046"; ++ vcc-supply = <&tsc2046reg>; ++ ++ reg = <1>; /* CS1 */ ++ spi-max-frequency = <1500000>; ++ ++ interrupt-parent = <&gpio2>; ++ interrupts = <15 0>; ++ pendown-gpio = <&gpio2 15 0>; ++ ++ ti,x-min = /bits/ 16 <0x0>; ++ ti,x-max = /bits/ 16 <0x0fff>; ++ ti,y-min = /bits/ 16 <0x0>; ++ ti,y-max = /bits/ 16 <0x0fff>; ++ ++ ti,x-plate-ohms = /bits/ 16 <180>; ++ ti,pressure-max = /bits/ 16 <255>; ++ ++ ti,debounce-max = /bits/ 16 <30>; ++ ti,debounce-tol = /bits/ 16 <10>; ++ ti,debounce-rep = /bits/ 16 <1>; ++ ++ linux,wakeup; ++ }; ++}; ++ ++/* eth0 */ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ status = "okay"; ++}; ++ ++/* nand */ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "okay"; ++ ++ partition@0 { ++ label = "linux"; ++ reg = <0x0 0x800000>; ++ }; ++ ++ partition@800000 { ++ label = "rootfs"; ++ reg = < 0x800000 0x0>; ++ }; ++}; ++ ++/* i2c3 */ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ eeprom@50 { ++ compatible = "at24,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ codec: wm8731@1a { ++ compatible = "wlf,wm8731"; ++ reg = <0x1a>; ++ clocks = <&clks 173>, <&clks 158>, <&clks 201>, <&clks 200>; ++ clock-names = "pll4", "imx-ssi.1", "cko", "cko2"; ++ AVDD-supply = <®_3p3v>; ++ HPVDD-supply = <®_3p3v>; ++ DCVDD-supply = <®_3p3v>; ++ DBVDD-supply = <®_3p3v>; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pcie>; ++ reset-gpio = <&gpio1 26 0>; ++ vdd-supply = <&pcie_power_on_gpio>; ++ status = "okay"; ++}; ++ ++/* console */ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart4>; ++ status = "okay"; ++}; ++ ++/* usb otg */ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ dr_mode = "otg"; ++ status = "okay"; ++}; ++ ++/* usb hub1 */ ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbh1>; ++ status = "okay"; ++}; ++ ++/* wifi/bt */ ++&usdhc1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_mrvl1>; ++ non-removable; ++ vmmc-supply = <&awnh387_npoweron>; ++ vmmc_aux-supply = <&awnh387_wifi_nreset>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-master"; ++ status = "okay"; ++}; ++ ++&hdmi_core { ++ ipu_id = <0>; ++ disp_id = <1>; ++ status = "okay"; ++}; ++ ++&hdmi_video { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_hdcp>; ++ fsl,hdcp; ++ status = "okay"; ++}; ++ ++&hdmi_audio { ++ status = "okay"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif>; ++ status = "okay"; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -1,15 +1,102 @@ + /* + * Copyright (C) 2014 Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. + */ + #include "imx6qdl-microsom.dtsi" + #include "imx6qdl-microsom-ar8035.dtsi" ++#include ++#include + + / { ++ aliases { ++ mmc0 = &usdhc2; ++ mmc1 = &usdhc1; ++ mxcfb0 = &mxcfb1; ++ }; ++ ++ chosen { ++ bootargs = "quiet console=ttymxc0,115200 root=/dev/mmcblk0p2 rw"; ++ }; ++ + 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"; ++ }; ++ ++ 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"; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-0 = <&pinctrl_gpio_key>; ++ pinctrl-names = "default"; ++ ++ button_0 { ++ label = "Button 0"; ++ gpios = <&gpio3 8 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ 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 { +@@ -48,11 +135,58 @@ + + sound-spdif { + compatible = "fsl,imx-audio-spdif"; +- model = "imx-spdif"; ++ model = "Integrated 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>; ++ }; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-hdmi"; ++ 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 { +@@ -64,11 +198,25 @@ + rtc: pcf8523@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; ++ nxp,12p5_pf; + }; + }; + + &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,21 +230,40 @@ + >; + }; + ++ 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 = ; + }; + ++ 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 = ; + }; + + pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux { + fsl,pins = < +- MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x13071 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 + >; + }; +@@ -111,9 +278,19 @@ + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; ++ ++ pinctrl_gpio_key: gpio-key { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x17059 ++ >; ++ }; + }; + }; + ++&pwm1 { ++ status = "okay"; ++}; ++ + &spdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_spdif>; +@@ -121,11 +298,15 @@ + }; + + &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"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -10,6 +10,9 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include ++#include ++ + #include "skeleton.dtsi" + + / { +@@ -24,6 +27,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 +41,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>; +@@ -72,14 +80,28 @@ + interrupt-parent = <&intc>; + ranges; + ++ caam_sm: caam-sm@00100000 { ++ compatible = "fsl,imx6q-caam-sm"; ++ reg = <0x00100000 0x3fff>; ++ }; ++ + dma_apbh: dma-apbh@00110000 { + compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"; + reg = <0x00110000 0x2000>; +- 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>; +- clocks = <&clks 106>; ++ clocks = <&clks IMX6QDL_CLK_APBH_DMA>; ++ }; ++ ++ irq_sec_vio: caam_secvio { ++ compatible = "fsl,imx6q-caam-secvio"; ++ interrupts = <0 20 0x04>; ++ secvio_src = <0x8000001d>; + }; + + gpmi: gpmi-nand@00112000 { +@@ -88,10 +110,13 @@ + #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>; ++ clocks = <&clks IMX6QDL_CLK_GPMI_IO>, ++ <&clks IMX6QDL_CLK_GPMI_APB>, ++ <&clks IMX6QDL_CLK_GPMI_BCH>, ++ <&clks IMX6QDL_CLK_GPMI_BCH_APB>, ++ <&clks IMX6QDL_CLK_PER1_BCH>; + clock-names = "gpmi_io", "gpmi_apb", "gpmi_bch", + "gpmi_bch_apb", "per1_bch"; + dmas = <&dma_apbh 0>; +@@ -103,38 +128,88 @@ + compatible = "arm,cortex-a9-twd-timer"; + reg = <0x00a00600 0x20>; + interrupts = <1 13 0xf01>; +- clocks = <&clks 15>; ++ clocks = <&clks IMX6QDL_CLK_TWD>; + }; + + 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 { + compatible = "fsl,imx6q-pcie", "snps,dw-pcie"; +- reg = <0x01ffc000 0x4000>; /* DBI */ ++ reg = <0x01ffc000 0x4000>, <0x01f00000 0x80000>; ++ reg-names = "dbi", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; +- ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* configuration space */ +- 0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */ ++ ranges = <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 = <0 120 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi"; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0x7>; ++ interrupt-map = <0 0 0 1 &intc 0 123 IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &intc 0 122 IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &intc 0 121 IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &intc 0 120 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_PCIE_REF_125M>, ++ <&clks IMX6QDL_CLK_SATA_REF_100M>, ++ <&clks IMX6QDL_CLK_LVDS1_GATE>, <&clks IMX6QDL_CLK_PCIE_AXI>; ++ clock-names = "pcie_phy", "ref_100m", "pcie_bus", "pcie"; + status = "disabled"; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; +- interrupts = <0 94 0x04>; ++ interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ hdmi_core: hdmi_core@00120000 { ++ compatible = "fsl,imx6q-hdmi-core"; ++ reg = <0x00120000 0x9000>; ++ clocks = <&clks IMX6QDL_CLK_HDMI_ISFR>, ++ <&clks IMX6QDL_CLK_HDMI_IAHB>, ++ <&clks IMX6QDL_CLK_HSI_TX>; ++ clock-names = "hdmi_isfr", "hdmi_iahb", "mipi_core"; ++ status = "disabled"; ++ }; ++ ++ hdmi_video: hdmi_video@020e0000 { ++ compatible = "fsl,imx6q-hdmi-video"; ++ reg = <0x020e0000 0x1000>; ++ reg-names = "hdmi_gpr"; ++ interrupts = <0 115 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_HDMI_ISFR>, ++ <&clks IMX6QDL_CLK_HDMI_IAHB>, ++ <&clks IMX6QDL_CLK_HSI_TX>; ++ clock-names = "hdmi_isfr", "hdmi_iahb", "mipi_core"; ++ status = "disabled"; ++ }; ++ ++ hdmi_audio: hdmi_audio@00120000 { ++ compatible = "fsl,imx6q-hdmi-audio"; ++ clocks = <&clks IMX6QDL_CLK_HDMI_ISFR>, ++ <&clks IMX6QDL_CLK_HDMI_IAHB>, ++ <&clks IMX6QDL_CLK_HSI_TX>; ++ clock-names = "hdmi_isfr", "hdmi_iahb", "mipi_core"; ++ dmas = <&sdma 2 24 0>; ++ dma-names = "tx"; ++ status = "disabled"; ++ }; ++ ++ hdmi_cec: hdmi_cec@00120000 { ++ compatible = "fsl,imx6q-hdmi-cec"; ++ interrupts = <0 115 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; + }; + + aips-bus@02000000 { /* AIPS1 */ +@@ -154,20 +229,20 @@ + 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"; +- clocks = <&clks 197>, <&clks 3>, +- <&clks 197>, <&clks 107>, +- <&clks 0>, <&clks 118>, +- <&clks 0>, <&clks 139>, +- <&clks 0>; ++ clocks = <&clks IMX6QDL_CLK_SPDIF_GCLK>, <&clks IMX6QDL_CLK_OSC>, ++ <&clks IMX6QDL_CLK_SPDIF>, <&clks IMX6QDL_CLK_ASRC>, ++ <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_ESAI_EXTAL>, ++ <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_MLB>, ++ <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_SPBA>; + clock-names = "core", "rxtx0", + "rxtx1", "rxtx2", + "rxtx3", "rxtx4", + "rxtx5", "rxtx6", +- "rxtx7"; ++ "rxtx7", "dma"; + status = "disabled"; + }; + +@@ -176,8 +251,9 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02008000 0x4000>; +- interrupts = <0 31 0x04>; +- clocks = <&clks 112>, <&clks 112>; ++ interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_ECSPI1>, ++ <&clks IMX6QDL_CLK_ECSPI1>; + clock-names = "ipg", "per"; + status = "disabled"; + }; +@@ -187,8 +263,9 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x0200c000 0x4000>; +- interrupts = <0 32 0x04>; +- clocks = <&clks 113>, <&clks 113>; ++ interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_ECSPI2>, ++ <&clks IMX6QDL_CLK_ECSPI2>; + clock-names = "ipg", "per"; + status = "disabled"; + }; +@@ -198,8 +275,9 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02010000 0x4000>; +- interrupts = <0 33 0x04>; +- clocks = <&clks 114>, <&clks 114>; ++ interrupts = <0 33 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_ECSPI3>, ++ <&clks IMX6QDL_CLK_ECSPI3>; + clock-names = "ipg", "per"; + status = "disabled"; + }; +@@ -209,8 +287,9 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02014000 0x4000>; +- interrupts = <0 34 0x04>; +- clocks = <&clks 115>, <&clks 115>; ++ interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_ECSPI4>, ++ <&clks IMX6QDL_CLK_ECSPI4>; + clock-names = "ipg", "per"; + status = "disabled"; + }; +@@ -218,8 +297,9 @@ + uart1: serial@02020000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; +- interrupts = <0 26 0x04>; +- clocks = <&clks 160>, <&clks 161>; ++ interrupts = <0 26 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_UART_IPG>, ++ <&clks IMX6QDL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; + dmas = <&sdma 25 4 0>, <&sdma 26 4 0>; + dma-names = "rx", "tx"; +@@ -227,15 +307,28 @@ + }; + + esai: esai@02024000 { ++ compatible = "fsl,imx35-esai"; + reg = <0x02024000 0x4000>; +- interrupts = <0 51 0x04>; ++ interrupts = <0 51 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_ESAI_IPG>, ++ <&clks IMX6QDL_CLK_ESAI_MEM>, ++ <&clks IMX6QDL_CLK_ESAI_EXTAL>, ++ <&clks IMX6QDL_CLK_ESAI_IPG>, ++ <&clks IMX6QDL_CLK_SPBA>; ++ clock-names = "core", "mem", "extal", "fsys", "dma"; ++ dmas = <&sdma 23 21 0>, ++ <&sdma 24 21 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; + }; + + ssi1: ssi@02028000 { + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + reg = <0x02028000 0x4000>; +- interrupts = <0 46 0x04>; +- clocks = <&clks 178>; ++ interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_SSI1_IPG>, ++ <&clks IMX6QDL_CLK_SSI1>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 37 1 0>, + <&sdma 38 1 0>; + dma-names = "rx", "tx"; +@@ -247,8 +340,10 @@ + ssi2: ssi@0202c000 { + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + reg = <0x0202c000 0x4000>; +- interrupts = <0 47 0x04>; +- clocks = <&clks 179>; ++ interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_SSI2_IPG>, ++ <&clks IMX6QDL_CLK_SSI2>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 41 1 0>, + <&sdma 42 1 0>; + dma-names = "rx", "tx"; +@@ -260,8 +355,10 @@ + ssi3: ssi@02030000 { + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + reg = <0x02030000 0x4000>; +- interrupts = <0 48 0x04>; +- clocks = <&clks 180>; ++ interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_SSI3_IPG>, ++ <&clks IMX6QDL_CLK_SSI3>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 45 1 0>, + <&sdma 46 1 0>; + dma-names = "rx", "tx"; +@@ -271,8 +368,28 @@ + }; + + asrc: asrc@02034000 { ++ compatible = "fsl,imx53-asrc"; + reg = <0x02034000 0x4000>; +- interrupts = <0 50 0x04>; ++ interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_ASRC_IPG>, ++ <&clks IMX6QDL_CLK_ASRC_MEM>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks IMX6QDL_CLK_ASRC>, <&clks 0>, <&clks 0>, ++ <&clks IMX6QDL_CLK_SPBA>; ++ clock-names = "mem", "ipg", "asrck_0", ++ "asrck_1", "asrck_2", "asrck_3", "asrck_4", ++ "asrck_5", "asrck_6", "asrck_7", "asrck_8", ++ "asrck_9", "asrck_a", "asrck_b", "asrck_c", ++ "asrck_d", "asrck_e", "asrck_f", "dma"; ++ dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, ++ <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; ++ dma-names = "rxa", "rxb", "rxc", ++ "txa", "txb", "txc"; ++ fsl,asrc-rate = <48000>; ++ fsl,asrc-width = <16>; ++ status = "okay"; + }; + + spba@0203c000 { +@@ -281,8 +398,20 @@ + }; + + 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_EDGE_RISING>, ++ <0 12 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "vpu_jpu_irq", "vpu_ipi_irq"; ++ clocks = <&clks IMX6QDL_CLK_VPU_AXI>, ++ <&clks IMX6QDL_CLK_MMDC_CH0_AXI>, ++ <&clks IMX6QDL_CLK_OCRAM>; ++ clock-names = "vpu_clk", "mmdc_ch0_axi", "ocram"; ++ iramsize = <0x21000>; ++ iram = <&ocram>; ++ resets = <&src 1>; ++ power-domains = <&gpc 1>; + }; + + aipstz@0207c000 { /* AIPSTZ1 */ +@@ -293,8 +422,9 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x02080000 0x4000>; +- interrupts = <0 83 0x04>; +- clocks = <&clks 62>, <&clks 145>; ++ interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_IPG>, ++ <&clks IMX6QDL_CLK_PWM1>; + clock-names = "ipg", "per"; + }; + +@@ -302,8 +432,9 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x02084000 0x4000>; +- interrupts = <0 84 0x04>; +- clocks = <&clks 62>, <&clks 146>; ++ interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_IPG>, ++ <&clks IMX6QDL_CLK_PWM2>; + clock-names = "ipg", "per"; + }; + +@@ -311,8 +442,9 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x02088000 0x4000>; +- interrupts = <0 85 0x04>; +- clocks = <&clks 62>, <&clks 147>; ++ interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_IPG>, ++ <&clks IMX6QDL_CLK_PWM3>; + clock-names = "ipg", "per"; + }; + +@@ -320,39 +452,48 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x0208c000 0x4000>; +- interrupts = <0 86 0x04>; +- clocks = <&clks 62>, <&clks 148>; ++ interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_IPG>, ++ <&clks IMX6QDL_CLK_PWM4>; + clock-names = "ipg", "per"; + }; + +- can1: flexcan@02090000 { ++ flexcan1: can@02090000 { + compatible = "fsl,imx6q-flexcan"; + reg = <0x02090000 0x4000>; +- interrupts = <0 110 0x04>; +- clocks = <&clks 108>, <&clks 109>; ++ interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_CAN1_IPG>, ++ <&clks IMX6QDL_CLK_CAN1_SERIAL>; + clock-names = "ipg", "per"; ++ stop-mode = <&gpr 0x34 28 0x10 17>; ++ status = "disabled"; + }; + +- can2: flexcan@02094000 { ++ flexcan2: can@02094000 { + compatible = "fsl,imx6q-flexcan"; + reg = <0x02094000 0x4000>; +- interrupts = <0 111 0x04>; +- clocks = <&clks 110>, <&clks 111>; ++ interrupts = <0 111 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_CAN2_IPG>, ++ <&clks IMX6QDL_CLK_CAN2_SERIAL>; + clock-names = "ipg", "per"; ++ stop-mode = <&gpr 0x34 29 0x10 18>; ++ status = "disabled"; + }; + + gpt: gpt@02098000 { + compatible = "fsl,imx6q-gpt", "fsl,imx31-gpt"; + reg = <0x02098000 0x4000>; +- interrupts = <0 55 0x04>; +- clocks = <&clks 119>, <&clks 120>; ++ interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_GPT_IPG>, ++ <&clks IMX6QDL_CLK_GPT_IPG_PER>; + clock-names = "ipg", "per"; + }; + + 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 +503,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 +514,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 +525,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 +536,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 +547,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 +558,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,35 +568,38 @@ + + 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>; +- clocks = <&clks 0>; ++ interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_DUMMY>; + }; + + wdog2: wdog@020c0000 { + compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; + reg = <0x020c0000 0x4000>; +- interrupts = <0 81 0x04>; +- clocks = <&clks 0>; ++ interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_DUMMY>; + status = "disabled"; + }; + + 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 +645,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; +@@ -508,6 +658,8 @@ + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; ++ regulator-allow-bypass; ++ linux,phandle = <®_arm>; + }; + + reg_pu: regulator-vddpu@140 { +@@ -515,7 +667,8 @@ + regulator-name = "vddpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; +- regulator-always-on; ++ regulator-enable-ramp-delay = <150>; ++ regulator-boot-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <9>; + anatop-vol-bit-width = <5>; +@@ -525,6 +678,7 @@ + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; ++ regulator-allow-bypass; + }; + + reg_soc: regulator-vddsoc@140 { +@@ -542,28 +696,50 @@ + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; ++ regulator-allow-bypass; ++ linux,phandle = <®_soc>; + }; + }; + + 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 IMX6QDL_CLK_PLL3_USB_OTG>; + }; + + usbphy1: usbphy@020c9000 { + compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; + reg = <0x020c9000 0x1000>; +- interrupts = <0 44 0x04>; +- clocks = <&clks 182>; ++ interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USBPHY1>; ++ fsl,anatop = <&anatop>; + }; + + usbphy2: usbphy@020ca000 { + compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; + reg = <0x020ca000 0x1000>; +- interrupts = <0 45 0x04>; +- clocks = <&clks 183>; ++ interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USBPHY2>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ usbphy_nop1: usbphy_nop1 { ++ compatible = "usb-nop-xceiv"; ++ clocks = <&clks IMX6QDL_CLK_USBPHY1>; ++ clock-names = "main_clk"; ++ }; ++ ++ usbphy_nop2: usbphy_nop2 { ++ compatible = "usb-nop-xceiv"; ++ clocks = <&clks IMX6QDL_CLK_USBPHY1>; ++ clock-names = "main_clk"; ++ }; ++ ++ caam_snvs: caam-snvs@020cc000 { ++ compatible = "fsl,imx6q-caam-snvs"; ++ reg = <0x020cc000 0x4000>; + }; + + snvs@020cc000 { +@@ -575,31 +751,42 @@ + 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>; ++ pu-supply = <®_pu>; ++ clocks = <&clks IMX6QDL_CLK_GPU3D_CORE>, ++ <&clks IMX6QDL_CLK_GPU3D_SHADER>, ++ <&clks IMX6QDL_CLK_GPU2D_CORE>, ++ <&clks IMX6QDL_CLK_GPU2D_AXI>, ++ <&clks IMX6QDL_CLK_OPENVG_AXI>, ++ <&clks IMX6QDL_CLK_VPU_AXI>; ++ #power-domain-cells = <1>; + }; + + gpr: iomuxc-gpr@020e0000 { +@@ -610,750 +797,11 @@ + 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>; + status = "disabled"; + +@@ -1369,20 +817,31 @@ + }; + + dcic1: dcic@020e4000 { ++ compatible = "fsl,imx6q-dcic"; + reg = <0x020e4000 0x4000>; +- interrupts = <0 124 0x04>; ++ interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_DCIC1>, <&clks IMX6QDL_CLK_DCIC1>; ++ clock-names = "dcic", "disp-axi"; ++ gpr = <&gpr>; ++ status = "disabled"; + }; + + dcic2: dcic@020e8000 { ++ compatible = "fsl,imx6q-dcic"; + reg = <0x020e8000 0x4000>; +- interrupts = <0 125 0x04>; ++ interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_DCIC2>, <&clks IMX6QDL_CLK_DCIC2>; ++ clock-names = "dcic", "disp-axi"; ++ gpr = <&gpr>; ++ status = "disabled"; + }; + + sdma: sdma@020ec000 { + compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma"; + reg = <0x020ec000 0x4000>; +- interrupts = <0 2 0x04>; +- clocks = <&clks 155>, <&clks 155>; ++ interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_SDMA>, ++ <&clks IMX6QDL_CLK_SDMA>; + clock-names = "ipg", "ahb"; + #dma-cells = <3>; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; +@@ -1396,9 +855,29 @@ + reg = <0x02100000 0x100000>; + ranges; + +- caam@02100000 { +- reg = <0x02100000 0x40000>; +- interrupts = <0 105 0x04 0 106 0x04>; ++ crypto: caam@2100000 { ++ compatible = "fsl,sec-v4.0"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2100000 0x40000>; ++ ranges = <0 0x2100000 0x40000>; ++ interrupt-parent = <&intc>; /* interrupts = <0 92 0x4>; */ ++ clocks = <&clks IMX6QDL_CAAM_MEM>, <&clks IMX6QDL_CAAM_ACLK>, <&clks IMX6QDL_CAAM_IPG> ,<&clks IMX6QDL_CLK_EIM_SLOW>; ++ 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 0x4>; ++ }; ++ ++ sec_jr1: jr1@2000 { ++ compatible = "fsl,sec-v4.0-job-ring"; ++ reg = <0x2000 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <0 106 0x4>; ++ }; + }; + + aipstz@0217c000 { /* AIPSTZ2 */ +@@ -1408,18 +887,19 @@ + usbotg: usb@02184000 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184000 0x200>; +- interrupts = <0 43 0x04>; +- clocks = <&clks 162>; ++ interrupts = <0 43 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USBOH3>; + fsl,usbphy = <&usbphy1>; + fsl,usbmisc = <&usbmisc 0>; ++ fsl,anatop = <&anatop>; + status = "disabled"; + }; + + usbh1: usb@02184200 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184200 0x200>; +- interrupts = <0 40 0x04>; +- clocks = <&clks 162>; ++ interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USBOH3>; + fsl,usbphy = <&usbphy2>; + fsl,usbmisc = <&usbmisc 1>; + status = "disabled"; +@@ -1428,18 +908,24 @@ + usbh2: usb@02184400 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184400 0x200>; +- interrupts = <0 41 0x04>; +- clocks = <&clks 162>; ++ interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USBOH3>; + 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>; +- clocks = <&clks 162>; ++ interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USBOH3>; + fsl,usbmisc = <&usbmisc 3>; ++ phy_type = "hsic"; ++ fsl,usbphy = <&usbphy_nop2>; ++ fsl,anatop = <&anatop>; + status = "disabled"; + }; + +@@ -1447,28 +933,43 @@ + #index-cells = <1>; + compatible = "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; +- clocks = <&clks 162>; ++ clocks = <&clks IMX6QDL_CLK_USBOH3>; + }; + + fec: ethernet@02188000 { + compatible = "fsl,imx6q-fec"; + reg = <0x02188000 0x4000>; +- interrupts = <0 118 0x04 0 119 0x04>; +- clocks = <&clks 117>, <&clks 117>, <&clks 190>; ++ interrupts-extended = ++ <&intc 0 118 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_ENET>, ++ <&clks IMX6QDL_CLK_ENET>, ++ <&clks IMX6QDL_CLK_ENET_REF>; + clock-names = "ipg", "ahb", "ptp"; ++ local-mac-address = [FF FF FF FF FF FF]; + status = "disabled"; + }; + +- mlb@0218c000 { ++ mlb: mlb@0218c000 { ++ compatible = "fsl,imx6q-mlb150"; + 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>; ++ clocks = <&clks IMX6QDL_CLK_MLB>, ++ <&clks IMX6QDL_CLK_PLL8_MLB>; ++ clock-names = "mlb", "pll8_mlb"; ++ iram = <&ocram>; ++ status = "disabled"; + }; + + usdhc1: usdhc@02190000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x02190000 0x4000>; +- interrupts = <0 22 0x04>; +- clocks = <&clks 163>, <&clks 163>, <&clks 163>; ++ interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USDHC1>, ++ <&clks IMX6QDL_CLK_USDHC1>, ++ <&clks IMX6QDL_CLK_USDHC1>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; +@@ -1477,8 +978,10 @@ + usdhc2: usdhc@02194000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x02194000 0x4000>; +- interrupts = <0 23 0x04>; +- clocks = <&clks 164>, <&clks 164>, <&clks 164>; ++ interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USDHC2>, ++ <&clks IMX6QDL_CLK_USDHC2>, ++ <&clks IMX6QDL_CLK_USDHC2>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; +@@ -1487,8 +990,10 @@ + usdhc3: usdhc@02198000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x02198000 0x4000>; +- interrupts = <0 24 0x04>; +- clocks = <&clks 165>, <&clks 165>, <&clks 165>; ++ interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USDHC3>, ++ <&clks IMX6QDL_CLK_USDHC3>, ++ <&clks IMX6QDL_CLK_USDHC3>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; +@@ -1497,8 +1002,10 @@ + usdhc4: usdhc@0219c000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x0219c000 0x4000>; +- interrupts = <0 25 0x04>; +- clocks = <&clks 166>, <&clks 166>, <&clks 166>; ++ interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_USDHC4>, ++ <&clks IMX6QDL_CLK_USDHC4>, ++ <&clks IMX6QDL_CLK_USDHC4>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; +@@ -1509,8 +1016,8 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; + reg = <0x021a0000 0x4000>; +- interrupts = <0 36 0x04>; +- clocks = <&clks 125>; ++ interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_I2C1>; + status = "disabled"; + }; + +@@ -1519,8 +1026,8 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; + reg = <0x021a4000 0x4000>; +- interrupts = <0 37 0x04>; +- clocks = <&clks 126>; ++ interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_I2C2>; + status = "disabled"; + }; + +@@ -1529,8 +1036,8 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; + reg = <0x021a8000 0x4000>; +- interrupts = <0 38 0x04>; +- clocks = <&clks 127>; ++ interrupts = <0 38 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_I2C3>; + status = "disabled"; + }; + +@@ -1538,6 +1045,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 +1062,30 @@ + weim: weim@021b8000 { + compatible = "fsl,imx6q-weim"; + reg = <0x021b8000 0x4000>; +- interrupts = <0 14 0x04>; +- clocks = <&clks 196>; ++ interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_EIM_SLOW>; + }; + +- ocotp: ocotp@021bc000 { +- compatible = "fsl,imx6q-ocotp", "syscon"; ++ ocotp: ocotp-ctrl@021bc000 { ++ compatible = "syscon"; + reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6QDL_CLK_IIM>; ++ }; ++ ++ ocotp-fuse@021bc000 { ++ compatible = "fsl,imx6q-ocotp"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6QDL_CLK_IIM>; + }; + + 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,8 +1094,20 @@ + status = "disabled"; + }; + +- mipi@021dc000 { /* MIPI-CSI */ ++ mipi_csi: mipi_csi@021dc000 { /* MIPI-CSI */ ++ compatible = "fsl,imx6q-mipi-csi2"; + reg = <0x021dc000 0x4000>; ++ interrupts = <0 100 0x04>, <0 101 0x04>; ++ clocks = <&clks IMX6QDL_CLK_HSI_TX>, ++ <&clks IMX6QDL_CLK_EMI_SEL>, ++ <&clks IMX6QDL_CLK_VIDEO_27M>; ++ /* 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"; + }; + + mipi@021e0000 { /* MIPI-DSI */ +@@ -1584,15 +1115,19 @@ + }; + + vdoa@021e4000 { ++ compatible = "fsl,imx6q-vdoa"; + reg = <0x021e4000 0x4000>; +- interrupts = <0 18 0x04>; ++ interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_VDOA>; ++ iram = <&ocram>; + }; + + uart2: serial@021e8000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021e8000 0x4000>; +- interrupts = <0 27 0x04>; +- clocks = <&clks 160>, <&clks 161>; ++ interrupts = <0 27 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_UART_IPG>, ++ <&clks IMX6QDL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; + dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; + dma-names = "rx", "tx"; +@@ -1602,8 +1137,9 @@ + uart3: serial@021ec000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021ec000 0x4000>; +- interrupts = <0 28 0x04>; +- clocks = <&clks 160>, <&clks 161>; ++ interrupts = <0 28 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_UART_IPG>, ++ <&clks IMX6QDL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; + dmas = <&sdma 29 4 0>, <&sdma 30 4 0>; + dma-names = "rx", "tx"; +@@ -1613,8 +1149,9 @@ + uart4: serial@021f0000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021f0000 0x4000>; +- interrupts = <0 29 0x04>; +- clocks = <&clks 160>, <&clks 161>; ++ interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_UART_IPG>, ++ <&clks IMX6QDL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; + dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; + dma-names = "rx", "tx"; +@@ -1624,8 +1161,9 @@ + uart5: serial@021f4000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021f4000 0x4000>; +- interrupts = <0 30 0x04>; +- clocks = <&clks 160>, <&clks 161>; ++ interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_UART_IPG>, ++ <&clks IMX6QDL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; + dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; + dma-names = "rx", "tx"; +@@ -1634,13 +1172,20 @@ + }; + + 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 IMX6QDL_CLK_IPU1>, ++ <&clks IMX6QDL_CLK_IPU1_DI0>, <&clks IMX6QDL_CLK_IPU1_DI1>, ++ <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, ++ <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>; ++ clock-names = "bus", ++ "di0", "di1", ++ "di0_sel", "di1_sel", ++ "ldb_di0", "ldb_di1"; + resets = <&src 2>; ++ bypass_reset = <0>; + }; + }; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -0,0 +1,700 @@ ++/* ++ * Device Tree file for SolidRun HummingBoard2 ++ * Copyright (C) 2015 Rabeeh Khoury ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. ++ */ ++#include "imx6qdl-microsom.dtsi" ++#include "imx6qdl-microsom-ar8035.dtsi" ++ ++/ { ++ aliases { ++ mmc0 = &usdhc2; ++ mmc1 = &usdhc1; ++ mxcfb0 = &mxcfb1; ++ mxcfb2 = &mxcfb2; ++ }; ++ ++ chosen { ++ bootargs = "quiet console=ttymxc0,115200 root=/dev/mmcblk0p2 rw"; ++ stdout-path = &uart1; ++ }; ++ ++ ir_recv: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio7 9 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_gpio7_9>; ++ linux,rc-map-name = "rc-rc6-mce"; ++ }; ++ ++ 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"; ++ }; ++ ++ mxcfb2: fb@1 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ 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_1p8v: 1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "1P8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ 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_hummingboard2_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_hummingboard2_usbotg_vbus>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ ++ reg_usbh2_vbus: usb-h2-vbus { ++ compatible = "regulator-gpio"; ++ enable-active-high; ++ enable-gpio = <&gpio2 13 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_usbh2_vbus>; ++ regulator-name = "usb_h2_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ }; ++ ++ reg_usbh3_vbus: usb-h3-vbus { ++ compatible = "regulator-gpio"; ++ enable-active-high; ++ enable-gpio = <&gpio7 10 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_usbh3_vbus>; ++ regulator-name = "usb_h3_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ }; ++ ++ reg_usdhc2_vbus: usdhc-2-vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "USDHC2-VBUS"; ++ gpio = <&gpio4 30 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_usdhc2_pwr>; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ }; ++ ++ 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>; ++ cpu-dai = <&ssi1>; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ mipi_camera = <1>; ++ default_input = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ status = "okay"; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-hdmi"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds1"; ++ status = "okay"; ++}; ++ ++&ecspi2 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio2 26 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_ecspi2>; ++ status = "okay"; ++ ++ spidev0: spi@0 { ++ compatible = "spidev"; ++ reg = <0>; ++ spi-max-frequency = <20000000>; ++ }; ++}; ++ ++&gpc { ++ fsl,cpu_pupscr_sw2iso = <0xf>; ++ fsl,cpu_pupscr_sw = <0xf>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++}; ++ ++&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_hummingboard2_hdmi>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_i2c1>; ++ status = "okay"; ++ ++ ov5640_mipi: ov5640_mipi@3c { ++ compatible = "ovti,ov5640_mipi"; ++ reg = <0x3c>; ++ clocks = <&clks IMX6QDL_CLK_CKO2>; ++ clock-names = "csi_mclk"; ++/* ++ DOVDD-supply = <®_3p3v>; ++ AVDD-supply = <®_3p3v>; ++ DVDD-supply = <®_3p3v>; ++*/ ++ pwn-gpios = <&gpio4 14 GPIO_ACTIVE_LOW>; ++ rst-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_mipi>; ++ extended-buffer; ++ }; ++ ++ rtc: pcf8523@68 { ++ compatible = "nxp,pcf8523"; ++ reg = <0x68>; ++ nxp,12p5_pf; ++ }; ++ ++ sgtl5000: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks IMX6QDL_CLK_CKO>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_sgtl5000>; ++ VDDA-supply = <®_3p3v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_i2c2>; ++ status = "okay"; ++ ++ ddc: imx6_hdmi_i2c@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_i2c3>; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ hummingboard2 { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ /* ++ * 36 pin headers GPIO description. The pins ++ * numbering as following - ++ * ++ * 3.2v 5v 74 75 ++ * 73 72 71 70 ++ * 69 68 67 66 ++ * ++ * 77 78 79 76 ++ * 65 64 61 60 ++ * 53 52 51 50 ++ * 49 48 166 132 ++ * 95 94 90 91 ++ * GND 54 24 204 ++ * ++ * The GPIO numbers can be extracted using ++ * signal name from below. ++ * Example - ++ * MX6QDL_PAD_EIM_DA10__GPIO3_IO10 is ++ * GPIO(3,10) which is (3-1)*32+10 = gpio 74 ++ * ++ * i.e. The mapping of GPIO(X,Y) to Linux gpio ++ * number is : gpio number = (X-1) * 32 + Y ++ */ ++ /* DI1_PIN15 */ ++ MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x400130b1 ++ /* DI1_PIN02 */ ++ MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x400130b1 ++ /* DISP1_DATA00 */ ++ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x400130b1 ++ /* DISP1_DATA01 */ ++ MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x400130b1 ++ /* DISP1_DATA02 */ ++ MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x400130b1 ++ /* DISP1_DATA03 */ ++ MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x400130b1 ++ /* DISP1_DATA04 */ ++ MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x400130b1 ++ /* DISP1_DATA05 */ ++ MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x400130b1 ++ /* DISP1_DATA06 */ ++ MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x400130b1 ++ /* DISP1_DATA07 */ ++ MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x400130b1 ++ /* DI1_D0_CS */ ++ MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x400130b1 ++ /* DI1_D1_CS */ ++ MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x400130b1 ++ /* DI1_PIN01 */ ++ MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x400130b1 ++ /* DI1_PIN03 */ ++ MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x400130b1 ++ /* DISP1_DATA08 */ ++ MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x400130b1 ++ /* DISP1_DATA09 */ ++ MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x400130b1 ++ /* DISP1_DATA10 */ ++ MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x400130b1 ++ /* DISP1_DATA11 */ ++ MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x400130b1 ++ /* DISP1_DATA12 */ ++ MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x400130b1 ++ /* DISP1_DATA13 */ ++ MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x400130b1 ++ /* DISP1_DATA14 */ ++ MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x400130b1 ++ /* DISP1_DATA15 */ ++ MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x400130b1 ++ /* DISP1_DATA16 */ ++ MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x400130b1 ++ /* DISP1_DATA17 */ ++ MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x400130b1 ++ /* DISP1_DATA18 */ ++ MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x400130b1 ++ /* DISP1_DATA19 */ ++ MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x400130b1 ++ /* DISP1_DATA20 */ ++ MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x400130b1 ++ /* DISP1_DATA21 */ ++ MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x400130b1 ++ /* DISP1_DATA22 */ ++ MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x400130b1 ++ /* DISP1_DATA23 */ ++ MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x400130b1 ++ /* DI1_DISP_CLK */ ++ MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x400130b1 ++ /* SPDIF_IN */ ++ MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x400130b1 ++ /* SPDIF_OUT */ ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x400130b1 ++ ++ /* MikroBUS GPIO pin number 10 */ ++ MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x400130b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_gpio7_9: hummingboard2-gpio7_9 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x80000000 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_hdmi: hummingboard2-hdmi { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_i2c1: hummingboard2-i2c1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_i2c2: hummingboard2-i2c2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_i2c3: hummingboard2-i2c3 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_mipi: hummingboard2_mipi { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x4001b8b1 ++ MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x4001b8b1 ++ MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_pcie_reset: hummingboard2-pcie-reset { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_pwm1: pwm1grp { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_sgtl5000: hummingboard2-sgtl5000 { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 ++ MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 ++ MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 ++ MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 ++ MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_usbh1_vbus: hummingboard2-usbh1-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard2_usbh2_vbus: hummingboard2-usbh2-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard2_usbh3_vbus: hummingboard2-usbh3-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard2_usbotg_id: hummingboard2-usbotg-id { ++ /* ++ * Similar to pinctrl_usbotg_2, but we want it ++ * pulled down for a fixed host connection. ++ */ ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard2_usbotg_vbus: hummingboard2-usbotg-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard2_usdhc2_pwr: hummingboard2-usdhc2-pwr { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard2_usdhc2_aux: hummingboard2-usdhc2-aux { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x13071 ++ MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_usdhc2: hummingboard2-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_hummingboard2_usdhc2_100mhz: hummingboard2-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_hummingboard2_usdhc2_200mhz: hummingboard2-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 ++ >; ++ }; ++ ++ pinctrl_hummingboard2_usdhc3: hummingboard2-usdhc3 { ++ 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 ++ MX6QDL_PAD_SD3_RST__SD3_RESET 0x17059 ++ >; ++ }; ++ pinctrl_hummingboard2_uart3: hummingboard2-uart3 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D25__UART3_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D24__UART3_RX_DATA 0x40013000 ++ >; ++ }; ++ pinctrl_hummingboard2_ecspi2: hummingboard2-ecspi2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 ++ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 ++ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 ++ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x000b1 /* CS */ ++ >; ++ }; ++ }; ++}; ++ ++&ldb { ++ status = "disabled"; ++ ++ lvds-channel@0 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ crtc = "ipu2-di0"; ++ primary; ++ ++ 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>; ++ }; ++ }; ++ }; ++}; ++ ++&mipi_csi { ++ ipu_id = <0>; ++ csi_id = <1>; ++ v_channel = <0>; ++ lanes = <2>; ++ mipi_dphy_clk = <0x14>; ++ status = "okay"; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = < ++ &pinctrl_hummingboard2_pcie_reset ++ >; ++ reset-gpio = <&gpio2 11 0>; ++ status = "okay"; ++ no-msi; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_pwm1>; ++ status = "okay"; ++}; ++ ++&pwm3 { ++ status = "disabled"; ++}; ++ ++&pwm4 { ++ status = "disabled"; ++}; ++ ++&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_hummingboard2_usbotg_id>; ++ vbus-supply = <®_usbotg_vbus>; ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = < ++ &pinctrl_hummingboard2_usdhc2_aux ++ &pinctrl_hummingboard2_usdhc2 ++ >; ++ pinctrl-1 = < ++ &pinctrl_hummingboard2_usdhc2_aux ++ &pinctrl_hummingboard2_usdhc2_100mhz ++ >; ++ pinctrl-2 = < ++ &pinctrl_hummingboard2_usdhc2_aux ++ &pinctrl_hummingboard2_usdhc2_200mhz ++ >; ++ ++ card-external-vcc-supply = <®_usdhc2_vbus>; ++ cd-gpios = <&gpio1 4 0>; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = < ++ &pinctrl_hummingboard2_usdhc3 ++ >; ++ vmmc-supply = <®_3p3v>; ++ bus-width = <8>; ++ non-removable; ++ status = "okay"; ++}; ++ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard2_uart3>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -0,0 +1,569 @@ ++/* ++ * Copyright (C) 2013,2014 Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. ++ */ ++#include "imx6qdl-microsom.dtsi" ++#include "imx6qdl-microsom-ar8035.dtsi" ++ ++/ { ++ aliases { ++ mmc0 = &usdhc2; ++ mmc1 = &usdhc1; ++ mxcfb0 = &mxcfb1; ++ mxcfb2 = &mxcfb2; ++ }; ++ ++ chosen { ++ bootargs = "quiet console=ttymxc0,115200 root=/dev/mmcblk0p2 rw"; ++ stdout-path = &uart1; ++ }; ++ ++ 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"; ++ }; ++ ++ 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"; ++ }; ++ ++ mxcfb2: fb@1 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ 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>; ++ }; ++ ++ reg_usdhc2_vbus: usdhc-2-vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "USDHC2-VBUS"; ++ gpio = <&gpio4 30 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_usdhc2_pwr>; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ }; ++ ++ 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>; ++ cpu-dai = <&ssi1>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif"; ++ model = "On-board 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>; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ mipi_camera = <1>; ++ default_input = <1>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ status = "okay"; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-hdmi"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds1"; ++ status = "okay"; ++}; ++ ++&ecspi2 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio2 26 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_ecspi2>; ++ status = "okay"; ++ ++ spidev0: spi@0 { ++ compatible = "spidev"; ++ reg = <0>; ++ spi-max-frequency = <20000000>; ++ }; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_flexcan1>; ++ status = "disabled"; ++}; ++ ++&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"; ++}; ++ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_i2c1>; ++ status = "okay"; ++ ++ /* Raspberry Pi camera rev 1.3 */ ++ ov5647_mipi: ov5647_mipi@36 { ++ compatible = "ovti,ov5647_mipi"; ++ reg = <0x36>; ++ /* Pi camera has its own 25MHz clock. */ ++ clocks = <&clks 0>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <®_3p3v>; ++ AVDD-supply = <®_3p3v>; ++ DVDD-supply = <®_3p3v>; ++ pwn-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; ++ led-gpios = <&gpio6 15 GPIO_ACTIVE_HIGH>; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk = <25000000>; ++ mclk_source = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_mipi>; ++ extended-buffer; ++ }; ++ ++ /* Pro baseboard model */ ++ rtc: pcf8523@68 { ++ compatible = "nxp,pcf8523"; ++ reg = <0x68>; ++ nxp,12p5_pf; ++ }; ++ ++ /* Pro baseboard model */ ++ sgtl5000: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks IMX6QDL_CLK_CKO>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_sgtl5000>; ++ VDDA-supply = <®_3p3v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++}; ++ ++&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>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_i2c3>; ++ status = "okay"; ++}; ++ ++&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_flexcan1: hummingboard-flexcan1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x80000000 ++ MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x80000000 ++ >; ++ }; ++ ++ pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1 ++ >; ++ }; ++ ++ 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_i2c3: hummingboard-i2c3 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard_mipi: hummingboard_mipi { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x17059 ++ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x13059 ++ >; ++ }; ++ ++ pinctrl_hummingboard_pcie_reset: hummingboard-pcie-reset { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard_pwm1: pwm1grp { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_sgtl5000: hummingboard-sgtl5000 { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 ++ MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 ++ MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 ++ MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 ++ MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 ++ >; ++ }; ++ ++ pinctrl_hummingboard_spdif: hummingboard-spdif { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_ecspi2: hummingboard_ecspi2 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 ++ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 ++ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 ++ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x000b1 /* CS */ ++ >; ++ }; ++ ++ 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_pwr: hummingboard-usdhc2-pwr { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_usdhc2_aux: hummingboard-usdhc2-aux { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x13071 ++ MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 ++ >; ++ }; ++ ++ 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_usdhc2_100mhz: hummingboard-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_hummingboard_usdhc2_200mhz: hummingboard-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 ++ >; ++ }; ++ }; ++}; ++ ++&ldb { ++ status = "disabled"; ++ ++ lvds-channel@0 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ crtc = "ipu2-di0"; ++ primary; ++ ++ 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>; ++ }; ++ }; ++ }; ++}; ++ ++&mipi_csi { ++ ipu_id = <0>; ++ csi_id = <1>; ++ v_channel = <0>; ++ lanes = <2>; ++ mipi_dphy_clk = /bits/ 8 <0x28>; ++ status = "okay"; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_pcie_reset>; ++ reset-gpio = <&gpio3 4 0>; ++ status = "okay"; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_pwm1>; ++ status = "okay"; ++}; ++ ++&pwm2 { ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_spdif>; ++ 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", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = < ++ &pinctrl_hummingboard_usdhc2_aux ++ &pinctrl_hummingboard_usdhc2 ++ >; ++ pinctrl-1 = < ++ &pinctrl_hummingboard_usdhc2_aux ++ &pinctrl_hummingboard_usdhc2_100mhz ++ >; ++ pinctrl-2 = < ++ &pinctrl_hummingboard_usdhc2_aux ++ &pinctrl_hummingboard_usdhc2_200mhz ++ >; ++ ++ card-external-vcc-supply = <®_usdhc2_vbus>; ++ cd-gpios = <&gpio1 4 0>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -3,6 +3,44 @@ + * + * This describes the hookup for an AR8035 to the iMX6 on the SolidRun + * MicroSOM. ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. + */ + &fec { + pinctrl-names = "default"; +@@ -11,13 +49,15 @@ + phy-reset-duration = <2>; + phy-reset-gpios = <&gpio4 15 0>; + status = "okay"; ++ assigned-clocks = <&clks IMX6QDL_CLK_ENET_REF>; ++ assigned-clock-rates = <25000000>; + }; + + &iomuxc { + 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 +66,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.72.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-microsom.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -1,9 +1,123 @@ + /* + * Copyright (C) 2013,2014 Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. + */ ++#include ++/ { ++ clk_sdio: sdio-clock { ++ compatible = "gpio-gate-clock"; ++ #clock-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_osc>; ++ enable-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 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>; ++ 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>; ++ }; ++ }; ++ ++ usdhc1_pwrseq: usdhc1_pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, ++ <&gpio6 0 GPIO_ACTIVE_LOW>; ++ clocks = <&clk_sdio>; ++ clock-names = "ext_clock"; ++ }; ++}; + + &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: microsom-brcm-osc { ++ 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 +125,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: 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 +153,24 @@ + status = "okay"; + }; + +-&usbotg { ++/* UART4 - Connected to optional BRCM Wifi/BT/FM */ ++&uart4 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_microsom_usbotg>; ++ pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4>; ++ 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>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>; ++ bus-width = <4>; ++ keep-power-in-suspend; ++ non-removable; ++ no-1-8-v; ++ vmmc-supply = <®_brcm>; ++ status = "okay"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 2016-06-19 22:11:55.021158011 +0200 +@@ -9,18 +9,290 @@ + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ ++#include + + / { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ }; ++ + memory { + reg = <0x10000000 0x80000000>; + }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ }; ++ ++ clocks { ++ codec_osc: anaclk2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24576000>; ++ }; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ home { ++ label = "Home"; ++ gpios = <&gpio1 11 1>; ++ gpio-key,wakeup; ++ linux,code = ; ++ }; ++ ++ back { ++ label = "Back"; ++ gpios = <&gpio1 12 1>; ++ gpio-key,wakeup; ++ linux,code = ; ++ }; ++ ++ program { ++ label = "Program"; ++ gpios = <&gpio2 12 1>; ++ gpio-key,wakeup; ++ linux,code = ; ++ }; ++ ++ volume-up { ++ label = "Volume Up"; ++ gpios = <&gpio2 15 1>; ++ gpio-key,wakeup; ++ linux,code = ; ++ }; ++ ++ volume-down { ++ label = "Volume Down"; ++ gpios = <&gpio5 14 1>; ++ gpio-key,wakeup; ++ linux,code = ; ++ }; ++ }; ++ ++ hannstar_cabc { ++ compatible = "hannstar,cabc"; ++ ++ lvds_share { ++ gpios = <&max7310_a 0 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx-sabreauto-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-in; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ 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"; ++ 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"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ sound-cs42888 { ++ compatible = "fsl,imx6-sabreauto-cs42888", ++ "fsl,imx-audio-cs42888"; ++ model = "imx-cs42888"; ++ esai-controller = <&esai>; ++ asrc-controller = <&asrc>; ++ audio-codec = <&codec>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_audio: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "cs42888_supply"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: 3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_si4763_vio1: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "vio1"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_si4763_vio2: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "vio2"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_si4763_vd: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "vd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_si4763_va: regulator@4 { ++ compatible = "regulator-fixed"; ++ reg = <4>; ++ regulator-name = "va"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_h1_vbus: usb_h1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&max7310_b 7 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_usb_otg_vbus: usb_otg_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&max7310_c 1 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_sd3_vmmc: sd3_vmmc{ ++ compatible = "regulator-fixed"; ++ regulator-name = "P3V3_SDa_SWITCHED"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio7 8 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ /* remove below line to enable this regulator */ ++ status="disabled"; ++ }; ++ }; ++ ++ sound-fm { ++ compatible = "fsl,imx-audio-si476x", ++ "fsl,imx-tuner-si476x"; ++ model = "imx-radio-si4763"; ++ ssi-controller = <&ssi2>; ++ fm-controller = <&si476x_codec>; ++ mux-int-port = <2>; ++ mux-ext-port = <5>; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&clks { ++ assigned-clocks = <&clks IMX6QDL_PLL4_BYPASS_SRC>, ++ <&clks IMX6QDL_PLL4_BYPASS>, ++ <&clks IMX6QDL_CLK_PLL4_POST_DIV>; ++ assigned-clock-parents = <&clks IMX6QDL_CLK_LVDS2_IN>, ++ <&clks IMX6QDL_PLL4_BYPASS_SRC>; ++ assigned-clock-rates = <0>, <0>, <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 { +@@ -32,16 +304,252 @@ + }; + }; + ++&esai { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_esai>; ++ assigned-clocks = <&clks IMX6QDL_CLK_ESAI_SEL>, ++ <&clks IMX6QDL_CLK_ESAI_EXTAL>; ++ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>; ++ assigned-clock-rates = <0>, <24576000>; ++ status = "okay"; ++}; ++ + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_2>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; ++ fsl,magic-packet; + status = "okay"; + }; + + &gpmi { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "disabled"; /* pin conflict with uart3 */ ++ nand-on-flash-bbt; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_egalax_int>; ++ interrupt-parent = <&gpio2>; ++ interrupts = <28 2>; ++ wakeup-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 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; ++ }; ++ }; ++ }; ++ ++ hdmi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++ ++ codec: cs42888@48 { ++ compatible = "cirrus,cs42888"; ++ reg = <0x48>; ++ clocks = <&codec_osc>; ++ clock-names = "mclk"; ++ VA-supply = <®_audio>; ++ VD-supply = <®_audio>; ++ VLS-supply = <®_audio>; ++ VLC-supply = <®_audio>; ++ }; ++ ++ si4763: si4763@63 { ++ compatible = "si4761"; ++ reg = <0x63>; ++ va-supply = <®_si4763_va>; ++ vd-supply = <®_si4763_vd>; ++ vio1-supply = <®_si4763_vio1>; ++ vio2-supply = <®_si4763_vio2>; ++ revision-a10; /* set to default A10 compatible command set */ ++ ++ si476x_codec: si476x-codec { ++ compatible = "si476x-codec"; ++ }; ++ }; ++}; ++ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ ++ adv7180: adv7180@21 { ++ compatible = "adv,adv7180"; ++ reg = <0x21>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_1>; ++ clocks = <&clks IMX6QDL_CLK_CKO>; ++ 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>; ++ }; ++ ++ max7310_a: gpio@30 { ++ compatible = "maxim,max7310"; ++ reg = <0x30>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ resets = <&max7310_reset>; ++ }; ++ ++ max7310_b: gpio@32 { ++ compatible = "maxim,max7310"; ++ reg = <0x32>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ max7310_c: gpio@34 { ++ compatible = "maxim,max7310"; ++ reg = <0x34>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ mma8451@1c { ++ compatible = "fsl,mma8451"; ++ reg = <0x1c>; ++ position = <7>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <31 8>; ++ interrupt-route = <1>; ++ }; ++ ++ mag3110@0e { ++ compatible = "fsl,mag3110"; ++ reg = <0x0e>; ++ position = <2>; ++ interrupt-parent = <&gpio2>; ++ interrupts = <29 1>; ++ }; ++ ++ isl29023@44 { ++ compatible = "fsl,isl29023"; ++ reg = <0x44>; ++ rext = <499>; ++ interrupt-parent = <&gpio5>; ++ interrupts = <17 2>; ++ }; ++}; ++ ++&mlb { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_mlb>; + status = "okay"; + }; + +@@ -49,44 +557,435 @@ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6qdl-sabreauto { ++ pinctrl_audmux: audmux { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x130b0 ++ MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x130b0 ++ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 ++ >; ++ }; ++ + pinctrl_hog: hoggrp { + fsl,pins = < +- MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 ++ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x1f059 + MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x80000000 + MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059 ++ MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x80000000 ++ MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x80000000 ++ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x80000000 ++ MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x80000000 ++ MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x80000000 ++ MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x80000000 ++ MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x17059 ++ MX6QDL_PAD_GPIO_1__GPIO1_IO01 0x17059 ++ >; ++ }; ++ ++ 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 + >; + }; +- }; + +- ecspi1 { +- pinctrl_ecspi1_sabreauto: ecspi1-sabreauto { ++ pinctrl_ecspi1_cs: ecspi1cs { + fsl,pins = < + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 + >; + }; ++ ++ pinctrl_egalax_int: egalax_intgrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB0__GPIO2_IO28 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_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_esai: esaigrp { ++ 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_flexcan1: flexcan1grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 ++ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 ++ >; ++ }; ++ ++ pinctrl_flexcan2: flexcan2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x80000000 ++ MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x80000000 ++ >; ++ }; ++ ++ pinctrl_gpio_keys: gpio_keysgrp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x1b0b0 ++ MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x1b0b0 ++ MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x1b0b0 ++ MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x1b0b0 ++ MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 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_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_ipu1_1: ipu1grp-1 { /* 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 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_mlb: mlb { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_TXD1__MLB_CLK 0x80000000 ++ MX6QDL_PAD_GPIO_6__MLB_SIG 0x80000000 ++ MX6QDL_PAD_GPIO_2__MLB_DATA 0x80000000 ++ >; ++ }; ++ ++ pinctrl_spdif: spdifgrp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 ++ >; ++ }; ++ ++ 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_uart3dte_1: uart3dtegrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_CLK__UART3_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_CMD__UART3_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x1b0b1 ++ MX6QDL_PAD_EIM_EB3__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_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc1: usdhc1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17071 ++ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10071 ++ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17071 ++ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17071 ++ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17071 ++ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17071 ++ >; ++ }; ++ ++ 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 ++ >; ++ }; ++ ++ pinctrl_hdmi_cec: hdmicecgrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_pwm3_1: pwm3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 ++ >; ++ }; + }; + }; + ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3_1>; ++ status = "okay"; ++}; ++ ++&pcie { ++ status = "okay"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif>; ++ assigned-clocks = <&clks IMX6QDL_CLK_SPDIF_SEL>, ++ <&clks IMX6QDL_CLK_SPDIF_PODF>; ++ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_PFD3_454M>; ++ assigned-clock-rates = <0>, <227368421>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ assigned-clocks = <&clks IMX6QDL_CLK_SSI2_SEL>; ++ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>; ++ assigned-clock-rates = <0>; ++ fsl,mode = "i2s-master"; ++ status = "okay"; ++}; ++ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3_1>; ++ pinctrl-assert-gpios = <&max7310_b 4 GPIO_ACTIVE_HIGH>, /* CTS */ ++ <&max7310_c 3 GPIO_ACTIVE_HIGH>; /* RXD and TXD */ ++ fsl,uart-has-rtscts; ++ status = "okay"; ++ /* for DTE mode, add below change */ ++ /* fsl,dte-mode; */ ++ /* pinctrl-0 = <&pinctrl_uart3dte_1>; */ ++}; ++ + &uart4 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart4_1>; ++ pinctrl-0 = <&pinctrl_uart4>; ++ status = "okay"; ++}; ++ ++&usdhc1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc1>; ++ cd-gpios = <&gpio1 1 0>; ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; + 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>; ++ /* ++ * Due to board issue, we can not use external regulator for card slot ++ * by default since the card power is shared with card detect pullup. ++ * Disabling the vmmc regulator will cause unexpected card detect ++ * interrupts. ++ * HW rework is needed to fix this isssue. Remove R695 first, then you ++ * can open below line to enable the using of external regulator. ++ * Then you will be able to power off the card during suspend. This is ++ * especially needed for a SD3.0 card re-enumeration working on UHS mode ++ * Note: reg_sd3_vmmc is also need to be enabled ++ */ ++ /* vmmc-supply = <®_sd3_vmmc>; */ ++ keep-power-in-suspend; ++ enable-sdio-wakeup; + status = "okay"; + }; + + &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 +1001,101 @@ + 0x0000c000 0x1404a38e 0x00000000>; + }; + }; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-hdmi"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds0"; ++ status = "okay"; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1>; ++ pinctrl-assert-gpios = <&max7310_b 3 GPIO_ACTIVE_HIGH>; /* TX */ ++ trx-en-gpio = <&max7310_b 6 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&max7310_b 5 GPIO_ACTIVE_HIGH>; ++ status = "disabled"; /* pin conflict with fec */ ++}; ++ ++&flexcan2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan2>; ++ trx-en-gpio = <&max7310_c 6 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&max7310_c 5 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&hdmi_audio { ++ status = "okay"; ++}; ++ ++&hdmi_cec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_cec>; ++ 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"; ++}; ++ ++&ldb { ++ status = "okay"; ++ ++ lvds-channel@0 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ primary; ++ 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>; ++ }; ++ }; ++ }; ++ ++ lvds-channel@1 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ status = "okay"; ++ ++ display-timings { ++ native-mode = <&timing1>; ++ timing1: 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>; ++ }; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sabresd.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -10,16 +10,51 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include ++ + / { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ }; ++ ++ battery: max8903@0 { ++ compatible = "fsl,max8903-charger"; ++ pinctrl-names = "default"; ++ dok_input = <&gpio2 24 1>; ++ uok_input = <&gpio1 27 1>; ++ chg_input = <&gpio3 23 1>; ++ flt_input = <&gpio5 2 1>; ++ fsl,dcm_always_high; ++ fsl,dc_valid; ++ fsl,usb_valid; ++ status = "okay"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ charger-led { ++ gpios = <&gpio1 2 0>; ++ linux,default-trigger = "max8903-charger-charging"; ++ retain-state-suspended; ++ }; ++ }; ++ + 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 +62,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 +72,57 @@ + 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; ++ }; ++ ++ reg_sensor: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "sensor-supply"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio2 31 0>; ++ startup-delay-us = <500>; ++ enable-active-high; ++ }; + }; + + gpio-keys { + compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ power { ++ label = "Power Button"; ++ gpios = <&gpio3 29 1>; ++ gpio-key,wakeup; ++ linux,code = ; ++ }; + + volume-up { + label = "Volume Up"; +- gpios = <&gpio1 4 0>; ++ gpios = <&gpio1 4 1>; + gpio-key,wakeup; +- linux,code = <115>; /* KEY_VOLUMEUP */ ++ linux,code = ; + }; + + volume-down { + label = "Volume Down"; +- gpios = <&gpio1 5 0>; ++ gpios = <&gpio1 5 1>; + gpio-key,wakeup; +- linux,code = <114>; /* KEY_VOLUMEDOWN */ ++ linux,code = ; + }; + }; + +@@ -66,7 +130,7 @@ + compatible = "fsl,imx6q-sabresd-wm8962", + "fsl,imx-audio-wm8962"; + model = "wm8962-audio"; +- ssi-controller = <&ssi2>; ++ cpu-dai = <&ssi2>; + audio-codec = <&codec>; + audio-routing = + "Headphone Jack", "HPOUTL", +@@ -79,6 +143,67 @@ + "DMICDAT", "DMIC"; + mux-int-port = <2>; + mux-ext-port = <3>; ++ hp-det-gpios = <&gpio7 8 1>; ++ mic-det-gpios = <&gpio1 9 1>; ++ }; ++ ++ 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"; ++ 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"; ++ 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 { +@@ -88,19 +213,52 @@ + default-brightness-level = <7>; + status = "okay"; + }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_1 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++ ++ 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"; + }; + ++&cpu0 { ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1c_reg>; ++}; ++ + &ecspi1 { + 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,16 +272,17 @@ + + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_1>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 25 0>; ++ fsl,magic-packet; + status = "okay"; + }; + + &i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c1_2>; ++ pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + codec: wm8962@1a { +@@ -138,6 +297,7 @@ + PLLVDD-supply = <®_audio>; + SPKVDD1-supply = <®_audio>; + SPKVDD2-supply = <®_audio>; ++ amic-mono; + gpio-cfg = < + 0x0000 /* 0:Default */ + 0x0000 /* 1:Default */ +@@ -147,12 +307,185 @@ + 0x0000 /* 5:Default */ + >; + }; ++ ++ mma8451@1c { ++ compatible = "fsl,mma8451"; ++ reg = <0x1c>; ++ position = <0>; ++ vdd-supply = <®_sensor>; ++ vddio-supply = <®_sensor>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <18 8>; ++ interrupt-route = <1>; ++ }; ++ ++ ov564x: ov564x@3c { ++ compatible = "ovti,ov564x"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_2>; ++ clocks = <&clks IMX6QDL_CLK_CKO>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <&vgen4_reg>; /* 1.8v */ ++ AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3, ++ on rev B board is VGEN5 */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */ ++ rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */ ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ hdmi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++ ++ max11801@48 { ++ compatible = "maxim,max11801"; ++ reg = <0x48>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <26 2>; ++ work-mode = <1>;/*DCM mode*/ ++ }; ++ ++ 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; ++ }; ++ }; ++ }; ++ ++ ov5640_mipi: ov5640_mipi@3c { /* i2c2 driver */ ++ compatible = "ovti,ov5640_mipi"; ++ reg = <0x3c>; ++ clocks = <&clks 201>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <&vgen4_reg>; /* 1.8v */ ++ AVDD-supply = <&vgen3_reg>; /* 2.8v, rev C board is VGEN3 ++ rev B board is VGEN5 */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio1 19 1>; /* active low: SD1_CLK */ ++ rst-gpios = <&gpio1 20 0>; /* active high: SD1_DAT2 */ ++ csi_id = <1>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <8 2>; ++ wakeup-gpios = <&gpio6 8 0>; ++ }; ++ + }; + + &i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c3_2>; ++ pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + egalax_ts@04 { +@@ -162,35 +495,327 @@ + interrupts = <7 2>; + wakeup-gpios = <&gpio6 7 0>; + }; ++ ++ mag3110@0e { ++ compatible = "fsl,mag3110"; ++ reg = <0x0e>; ++ position = <2>; ++ vdd-supply = <®_sensor>; ++ vddio-supply = <®_sensor>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <16 1>; ++ }; ++ ++ isl29023@44 { ++ compatible = "fsl,isl29023"; ++ reg = <0x44>; ++ rext = <499>; ++ vdd-supply = <®_sensor>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <9 2>; ++ }; + }; + + &iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- 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 + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x80000000 + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 + MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x80000000 ++ MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x80000000 + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 ++ MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x80000000 ++ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x80000000 ++ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 ++ MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x80000000 ++ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 ++ MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 ++ MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0x80000000 ++ MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x80000000 ++ MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x80000000 ++ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x80000000 ++ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 ++ MX6QDL_PAD_GPIO_1__WDOG2_B 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_enet_irq: enetirqgrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 ++ >; ++ }; ++ ++ 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: hdmicecgrp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_hdmi_hdcp: hdmihdcpgrp { ++ 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_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_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_uart5_1: uart5grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_COL4__UART5_RTS_B 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW4__UART5_CTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5dte_1: uart5dtegrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW1__UART5_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_COL1__UART5_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW4__UART5_RTS_B 0x1b0b1 ++ MX6QDL_PAD_KEY_COL4__UART5_CTS_B 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 ++ >; ++ }; ++ + }; + }; + ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-hdmi"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds1"; ++ status = "okay"; ++}; ++ ++&gpc { ++ /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,ldo-bypass = <1>; ++ fsl,wdog-reset = <2>; ++}; ++ ++&hdmi_audio { ++ status = "okay"; ++}; ++ ++&hdmi_cec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_cec>; ++ 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"; ++}; ++ + &ldb { + status = "okay"; + +- lvds-channel@1 { ++ lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; +@@ -210,11 +835,56 @@ + }; + }; + }; ++ ++ lvds-channel@1 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ primary; ++ status = "okay"; ++ ++ display-timings { ++ native-mode = <&timing1>; ++ timing1: 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>; ++ }; ++ }; ++ }; ++}; ++ ++&mipi_csi { ++ status = "okay"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ v_channel = <0>; ++ lanes = <2>; ++}; ++ ++&mipi_dsi { ++ dev_id = <0>; ++ disp_id = <1>; ++ lcd_panel = "TRULY-WVGA"; ++ disp-power-on-supply = <®_mipi_dsi_pwr_on>; ++ resets = <&mipi_dsi_reset>; ++ 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"; + }; + +@@ -225,7 +895,7 @@ + + &uart1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart1_1>; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; + }; + +@@ -237,25 +907,49 @@ + &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>; ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; + status = "okay"; + }; + + &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>; ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ bus-width = <8>; ++ non-removable; ++ no-1-8-v; ++ keep-power-in-suspend; ++ status = "okay"; ++}; ++ ++&wdog1 { ++ status = "disabled"; ++}; ++ ++&wdog2 { + status = "okay"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,116 @@ ++/* ++ * Copyright 2014 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 ++ */ ++ ++/ { ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ }; ++ ++ i2cmux { ++ compatible = "i2c-mux-gpio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ mux-gpios = <&gpio1 2 0>; ++ i2c-parent = <&i2c1>; ++ ++ i2c@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pca9555@26 { ++ compatible = "nxp,pca9555"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x26>; ++ }; ++ ++ hx8526@4a { ++ compatible = "himax,himax_ts"; ++ reg = <0x4a>; ++ gpio_intr = <&gpio1 4 0>; ++ }; ++ ++ eeprom@50 { ++ compatible = "at24,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ }; ++ ++ i2c@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dvi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++ }; ++ ++ }; ++}; ++ ++&i2c1 { ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ wp-gpios = <&gpio7 0 0>; ++ cd-gpios = <&gpio7 1 0>; ++ status = "okay"; ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3_1>; ++ status = "okay"; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ mode_str ="KD050C-WVGA"; ++ status = "okay"; ++}; ++ ++&mxcfb3 { ++ status = "okay"; ++}; ++ ++&mxcfb4 { ++ status = "okay"; ++}; ++ ++&ldb { ++ ipu_id = <1>; ++ disp_id = <0>; ++ ext_ref = <1>; ++ mode = "sep0"; ++ sec_ipu_id = <1>; ++ sec_disp_id = <1>; ++ status = "okay"; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1_1>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,114 @@ ++/* ++ * Copyright 2014 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 ++ */ ++ ++/ { ++ iomux_uart2: pinmux@20E0924 { ++ compatible = "pinctrl-single"; ++ reg = <0x20E0000 0x924>; /* Single register */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-single,register-width = <32>; ++ pinctrl-single,function-mask = <0x4>; ++ }; ++ ++ eth@pcie { ++ compatible = "intel,i211"; ++ local-mac-address = [FF FF FF FF FF FF]; ++ status = "okay"; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ power { ++ label = "Power Button"; ++ gpios = <&gpio1 29 1>; ++ linux,code = <116>; /* KEY_POWER */ ++ gpio-key,wakeup; ++ }; ++ }; ++ ++ i2cmux { ++ compatible = "i2c-mux-gpio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ mux-gpios = <&gpio1 2 0>; ++ i2c-parent = <&i2c1>; ++ ++ i2c@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ eeprom@50 { ++ compatible = "at24,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ rtc@56 { ++ compatible = "emmicro,em3027"; ++ reg = <0x56>; ++ }; ++ }; ++ ++ i2c@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dvi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++ }; ++ }; ++}; ++ ++&iomuxc { ++ imx6q-sbc-fx6m { ++ /* pins for uart2 */ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_7__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_GPIO_8__UART2_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x1b0b1 ++ MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x1b0b1 ++ >; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ non-removable; ++ status = "okay"; ++}; ++ ++/* rear serial console */ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,110 @@ ++/* ++ * Copyright 2014 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 ++ */ ++ ++/ { ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* regulator for mmc */ ++ reg_3p3v: 3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++ ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>, <&pinctrl_dvi0>; ++ ++ imx6q-sb-fx6x { ++ /* pins for i2c1 */ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ /* pins for mmc */ ++ 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__GPIO7_IO01 0x80000000 ++ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 ++ >; ++ }; ++ ++ pinctrl_usdhc3_100mhz: usdhc3grp-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 ++ >; ++ }; ++ ++ pinctrl_usdhc3_200mhz: usdhc3grp-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 ++ >; ++ }; ++ ++ /* pins for dvi/ts */ ++ pinctrl_dvi0: dvi0grp { ++ fsl,pins = < ++ /* DVI_DDC_SEL */ ++ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 ++ /* SB-FX6 Himax TS PENDOWN or SB-FX6m DVI HPD */ ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 ++ >; ++ }; ++ }; ++}; ++ ++/* i2c1 */ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "disabled"; ++}; ++ ++/* mmc */ ++&usdhc3 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ pinctrl-1 = <&pinctrl_usdhc3_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_200mhz>; ++ no-1-8-v; ++ keep-power-in-suspend; ++ vmmc-supply = <®_3p3v>; ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-udoo.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-udoo.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-udoo.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-udoo.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,664 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * Copyright (C) 2014 Jasbir ++ * Copyright 2015 Aidilab, Srl. ++ * ++ * Author: Fabio Estevam ++ * Author: Ettore Chimenti ++ * Author: Francesco Montefoschi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++/ { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb2 = &mxcfb2; ++// reg_can_xcvr = ®_can_xcvr; ++ mmc0 = &usdhc3; ++ mmc1 = &usdhc2; ++ mmc2 = &usdhc1; ++ mmc3 = &usdhc4; ++ ssi0 = &ssi1; ++ serial0 = &uart2; // console on ttymxc0 ++ serial1 = &uart1; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x40000000>; ++ }; ++ ++ 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"; ++ }; ++ ++ mxcfb2: fb@1 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str = ""; ++ default_bpp = <32>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_usb_h1_vbus: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ enable-active-high; ++ startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */ ++ gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ reg_lcd0_pwr: regulator@1 { ++ compatible = "regulator-fixed"; ++ regulator-name = "LCD0 POWER"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ regulator-boot-on; ++ regulator-always-on; ++ status = "disabled"; ++ }; ++ ++ reg_lcd0_backlight: regulator@2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "LCD0 BACKLIGHT"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ regulator-boot-on; ++ regulator-always-on; ++ status = "disabled"; ++ }; ++ ++// reg_can_xcvr: regulator@3 { ++// compatible = "regulator-fixed"; ++// reg = <3>; ++// regulator-name = "CAN XCVR"; ++// regulator-min-microvolt = <3300000>; ++// regulator-max-microvolt = <3300000>; ++// regulator-always-on; ++// enable-active-low; ++// }; ++ ++ reg_usb_otg_vbus: regulator@4 { ++ compatible = "regulator-fixed"; ++ reg = <4>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ enable-active-high; ++ }; ++ ++ reg_2p5v: regulator@5 { ++ compatible = "regulator-fixed"; ++ reg = <5>; ++ regulator-name = "2P5V"; ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-always-on; ++ }; ++ }; ++ ++ gpio-poweroff { ++ compatible = "gpio-poweroff"; ++ gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ codec: vt1613 { ++ compatible = "via,vt1613"; ++ }; ++ ++ sound { ++ compatible = "udoo,imx-vt1613-audio"; ++ ssi-controller = <&ssi1>; ++ audio-codec = <&codec>; ++ mux-int-port = <1>; ++ mux-ext-port = <6>; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ ++// sound-spdif { ++// compatible = "fsl,imx-audio-spdif", ++// "fsl,imx-sabreauto-spdif"; ++// model = "imx-spdif"; ++// spdif-controller = <&spdif>; ++// spdif-in; ++// status = "disabled"; ++// }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_1 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++ ++ udoo_ard: udoo_ard_manager { ++ compatible = "udoo,imx6q-udoo-ard"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_udoo_ard_alt>; ++ bossac-clk-gpio = <&gpio6 3 GPIO_ACTIVE_LOW>; ++ bossac-dat-gpio = <&gpio5 18 GPIO_ACTIVE_LOW>; ++ bossac-erase-gpio = <&gpio4 21 GPIO_ACTIVE_LOW>; ++ bossac-reset-gpio = <&gpio1 0 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ status = "okay"; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-hdmi"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds1"; ++ status = "okay"; ++}; ++ ++&gpc { // General power controller ++ /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,ldo-bypass = <1>; ++}; ++ ++&hdmi_audio { ++ 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"; ++}; ++ ++&ldb { // LVDS display bridge ++ status = "disabled"; ++ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>; ++ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>; ++ ++ lvds-channel@0 { ++ status = "disabled"; ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; // 7" display ++ //fsl,data-width = <24>; // 15.6" display ++ crtc = "ipu2-di0"; ++ primary; ++ ++ display-timings { ++ native-mode = <&timing1>; ++ ++ timing1: 800x480 { // 7" display ++ clock-frequency = <33660000>; ++ hactive = <800>; ++ vactive = <480>; ++ hback-porch = <56>; ++ hfront-porch = <50>; ++ vback-porch = <23>; ++ vfront-porch = <20>; ++ hsync-len = <150>; ++ vsync-len = <2>; ++ }; ++ ++ timing2: 1366x768 { // 15.6" display ++ clock-frequency = <76000000>; ++ hactive = <1366>; ++ vactive = <768>; ++ hback-porch = <220>; ++ hfront-porch = <40>; ++ vback-porch = <21>; ++ vfront-porch = <7>; ++ hsync-len = <60>; ++ vsync-len = <10>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c1 { // external pinout pin 20-21 ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++}; ++ ++&i2c2 { // internal (hdmi) ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ hdmi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++}; ++ ++&i2c3 { // CSI camera (CN11) and LVDS 7 inches touch panel (CN13) ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ ov5640_mipi: ov5640_mipi@3c { ++ compatible = "ovti,ov5640_mipi"; ++ reg = <0x3c>; ++ clocks = <&clks IMX6QDL_CLK_CKO>; ++ clock-names = "csi_mclk"; ++ pwn-gpios = <&gpio6 4 GPIO_ACTIVE_LOW>; ++ rst-gpios = <&gpio6 5 GPIO_ACTIVE_HIGH>; ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; ++ ++ touchscreen: st1232@55 { ++ compatible = "sitronix,st1232"; ++ reg = <0x55>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <13 IRQ_TYPE_LEVEL_LOW>; ++ pinctrl-0 = <&pinctrl_st1232>; ++ pinctrl-names = "default"; ++ gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; ++ }; ++}; ++ ++&fec { //ethernet ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ /* doesn't work with solidrun's kernel 3.14.48+ ++ phy-reset-gpios = <&gpio3 23 0>; ++ phy-reset-duration = <50>;*/ ++ status = "okay"; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog &external_hog>; ++ ++ imx6q-udoo { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ // Internal GPIOs ++ MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x80000000 // 5v enable ++ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 // Vtt enable ++ ++ MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x80000000 // Debug UART (J18) ++ ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 // USB hub reset ++ MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0 // USB hub clock ++ MX6QDL_PAD_EIM_WAIT__GPIO5_IO00 0xb0b1 // USB OTG select ++ ++ MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x80000000 // SD card power ++ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 // SD card detect ++ ++ MX6QDL_PAD_GPIO_16__GPIO7_IO11 0xb0b1 // SAM3X OTG vbus_en ++ MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x80000000 // SAM3X usb host ++ MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x30b1 // Arduino pinout pin 12 ++ ++ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 // LVDS panel on (CN13) ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 // LVDS backlight on (CN13) ++ ++ MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x1f071 // CSI camera enable (CN11) ++ MX6QDL_PAD_CSI0_DAT19__GPIO6_IO05 0x1f071 // CSI camera reset (CN11) ++ MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1 0x130b0 // CSI master clock (CN11) ++ >; ++ }; ++ ++ external_hog: hoggrp-2 { ++ fsl,pins = < ++ // External Pinout GPIOs ++ MX6QDL_PAD_CSI0_DAT11__GPIO5_IO29 0x80000000 // pin 00 ++ MX6QDL_PAD_CSI0_DAT10__GPIO5_IO28 0x80000000 // pin 01 ++ MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x80000000 // pin 02 ++ MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000 // pin 03 ++ MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x80000000 // pin 04 ++ MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0x80000000 // pin 05 ++ MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x80000000 // pin 06 ++ MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x80000000 // pin 07 ++ MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x80000000 // pin 08 ++ MX6QDL_PAD_SD1_DAT2__GPIO1_IO19 0x80000000 // pin 09 ++ MX6QDL_PAD_GPIO_1__GPIO1_IO01 0x80000000 // pin 10 ++ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x80000000 // pin 11 ++ MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x80000000 // pin 12 ++ MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x80000000 // pin 13 ++ MX6QDL_PAD_CSI0_DAT4__GPIO5_IO22 0x80000000 // pin 14 ++ MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 0x80000000 // pin 15 ++ MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x80000000 // pin 16 ++ MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x80000000 // pin 17 ++ MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 0x80000000 // pin 18 ++ MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 0x80000000 // pin 19 ++ // pin 20, 21 in pinctrl_i2c1 ++ MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x80000000 // pin 22 ++ MX6QDL_PAD_DISP0_DAT7__GPIO4_IO28 0x80000000 // pin 23 ++ MX6QDL_PAD_DISP0_DAT8__GPIO4_IO29 0x80000000 // pin 24 ++ MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x80000000 // pin 25 ++ MX6QDL_PAD_DISP0_DAT10__GPIO4_IO31 0x80000000 // pin 26 ++ MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x80000000 // pin 27 ++ MX6QDL_PAD_DISP0_DAT12__GPIO5_IO06 0x80000000 // pin 28 ++ MX6QDL_PAD_DISP0_DAT13__GPIO5_IO07 0x80000000 // pin 29 ++ MX6QDL_PAD_DISP0_DAT14__GPIO5_IO08 0x80000000 // pin 30 ++ MX6QDL_PAD_DISP0_DAT15__GPIO5_IO09 0x80000000 // pin 31 ++ MX6QDL_PAD_DISP0_DAT16__GPIO5_IO10 0x80000000 // pin 32 ++ MX6QDL_PAD_DISP0_DAT17__GPIO5_IO11 0x80000000 // pin 33 ++ MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x80000000 // pin 34 ++ MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13 0x80000000 // pin 35 ++ MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x80000000 // pin 36 ++ MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x80000000 // pin 37 ++ MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x80000000 // pin 38 ++ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x80000000 // pin 39 KEY_VOL_UP ++ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x80000000 // pin 40 HOME ++ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x80000000 // pin 41 SEARCH ++ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x80000000 // pin 42 BACK ++ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x80000000 // pin 43 MENU ++ MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x80000000 // pin 44 KEY_VOL_DOWN ++ MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16 0x80000000 // pin 45 ++ MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x80000000 // pin 46 ++ MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x80000000 // pin 47 ++ MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x80000000 // pin 48 ++ MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x80000000 // pin 49 ++ MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x80000000 // pin 50 ++ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x80000000 // pin 51 ++ MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x80000000 // pin 52 ++ MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x80000000 // pin 53 ++ >; ++ }; ++ ++ 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_EIM_D23__GPIO3_IO23 0x80000000 /* RGMII_nRST */ ++ MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* EN_ETH_PWR */ ++ >; ++ }; ++ ++ 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_5__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_st1232: st1232grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x80000000 // Touch panel reset ++ MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x80000000 // Touch panel interrupt ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 // or 0x100b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 // or 0x100b1 ++ >; ++ }; ++ ++ pinctrl_udoo_ard_alt: udooard2grp { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x80000000 ++ MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x80000000 ++ MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x80000000 ++ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x80000000 ++ >; ++ }; ++ ++// pinctrl_flexcan1: can1grp { ++// fsl,pins = < ++// MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x1b0b1 ++// MX6QDL_PAD_GPIO_8__FLEXCAN1_RX 0x1b0b1 ++// >; ++// }; ++ ++ ++// pinctrl_pwm4: pwm4grp { ++// fls,pins = < ++// MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x1b0b1 ++// >; ++// }; ++// ++// pinctrl_pwm3: pwm3grp { ++// fls,pins = < ++// MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 ++// >; ++// }; ++// ++// pinctrl_pwm1: pwm1grp { ++// fsl,pins = < ++// MX6QDL_PAD_GPIO_9__PWM1_OUT 0x1b0b1 ++// >; ++// }; ++// ++// pinctrl_pwm2: pwm2grp { ++// fsl,pins = < ++// MX6QDL_PAD_GPIO_1__PWM2_OUT 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_spdif_1: spdifgrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 ++ >; ++ }; ++ ++ ac97link_running: ac97link_runninggrp { ++ fsl,pins = < ++ MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x80000000 ++ MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x80000000 ++ MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x80000000 ++ MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x80000000 ++ >; ++ }; ++ ++ ac97link_reset: ac97link_resetgrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x80000000 ++ MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x80000000 ++ MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x80000000 ++ >; ++ }; ++ ++ ac97link_warm_reset: ac97link_warm_resetgrp { ++ fsl,pins = < ++ MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x80000000 ++ >; ++ }; ++ ++ }; ++}; ++ ++&ssi1 { ++ compatible = "fsl,imx6q-ssi", "fsl,imx51-ssi", "fsl,imx21-ssi"; ++ fsl,mode = "ac97-slave"; ++ pinctrl-names = "default", "ac97-running", "ac97-reset", "ac97-warm-reset"; ++ pinctrl-0 = <&ac97link_running>; ++ pinctrl-1 = <&ac97link_running>; ++ pinctrl-2 = <&ac97link_reset>; ++ pinctrl-3 = <&ac97link_warm_reset>; ++ /* sync, sdata (output), reset */ ++ ac97-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH ++ &gpio4 18 GPIO_ACTIVE_HIGH ++ &gpio2 30 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&uart2 { // iMX6 serial debug port - ttymxc1, available on micro USB CN6 (jumper J18 plugged) ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&uart4 { // iMX6-Arduino internal serial port - ttymxc3 ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart4>; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ non-removable; ++ keep-power-in-suspend; ++ no-1-8-v; ++ enable-sdio-wakeup; ++ status = "okay"; ++}; ++ ++&usbotg { ++ pinctrl-names = "default"; ++ vbus-supply = <®_usb_otg_vbus>; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ clocks = <&clks 201>; ++ clock-names = "phy"; ++ status = "okay"; ++}; ++ ++/* ++ * &pwm1 { ++ * pinctrl-names = "default"; ++ * pinctrl-0 = <&pinctrl_pwm1>; ++ * #pwm-cells = <3>; ++ * status = "okay"; ++ * }; ++ * ++ * &pwm2 { ++ * pinctrl-names = "default"; ++ * pinctrl-0 = <&pinctrl_pwm2>; ++ * #pwm-cells = <3>; ++ * status = "okay"; ++ * }; ++ * ++ * &pwm3 { ++ * pinctrl-names = "default"; ++ * pinctrl-0 = <&pinctrl_pwm3>; ++ * #pwm-cells = <3>; ++ * status = "okay"; ++ * }; ++ * ++ * &pwm4 { ++ * pinctrl-names = "default"; ++ * pinctrl-0 = <&pinctrl_pwm4>; ++ * #pwm-cells = <3>; ++ * status = "okay"; ++ * }; ++ */ ++ ++ ++&mipi_csi { ++ status = "okay"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ v_channel = <0>; ++ lanes = <2>; ++}; ++ ++// &spdif { ++// pinctrl-names = "default"; ++// pinctrl-0 = <&pinctrl_spdif_1>; ++// status = "disabled"; ++// }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-wandboard.dtsi linux-3.14.72/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -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,12 +95,110 @@ + 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 ++ >; ++ }; ++ ++ 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>; + status = "okay"; +@@ -104,7 +206,7 @@ + + &spdif { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_spdif_3>; ++ pinctrl-0 = <&pinctrl_spdif>; + status = "okay"; + }; + +@@ -115,13 +217,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 +234,7 @@ + + &usbotg { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usbotg_1>; ++ pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + dr_mode = "peripheral"; + status = "okay"; +@@ -140,21 +242,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.72.orig/arch/arm/boot/dts/imx6q.dtsi linux-3.14.72/arch/arm/boot/dts/imx6q.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -1,6 +1,6 @@ + + /* +- * Copyright 2013 Freescale Semiconductor, Inc. ++ * Copyright 2013-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 +@@ -8,15 +8,20 @@ + * + */ + ++#include + #include "imx6q-pinfunc.h" + #include "imx6qdl.dtsi" + + / { ++ aliases { ++ ipu1 = &ipu2; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <0>; +@@ -25,14 +30,29 @@ + /* kHz uV */ + 1200000 1275000 + 996000 1250000 +- 792000 1150000 +- 396000 950000 ++ 852000 1250000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++ 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>, +- <&clks 17>, <&clks 170>; ++ clocks = <&clks IMX6QDL_CLK_ARM>, ++ <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, ++ <&clks IMX6QDL_CLK_STEP>, ++ <&clks IMX6QDL_CLK_PLL1_SW>, ++ <&clks IMX6QDL_CLK_PLL1_SYS>, ++ <&clks IMX6QDL_PLL1_BYPASS>, ++ <&clks IMX6QDL_CLK_PLL1>, ++ <&clks IMX6QDL_PLL1_BYPASS_SRC> ; + clock-names = "arm", "pll2_pfd2_396m", "step", +- "pll1_sw", "pll1_sys"; ++ "pll1_sw", "pll1_sys", "pll1_bypass", "pll1", "pll1_bypass_src"; + arm-supply = <®_arm>; + pu-supply = <®_pu>; + soc-supply = <®_soc>; +@@ -61,10 +81,54 @@ + }; + + soc { +- ocram: sram@00900000 { ++ 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 IRQ_TYPE_LEVEL_HIGH>, ++ <0 10 IRQ_TYPE_LEVEL_HIGH>, ++ <0 11 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "irq_3d", "irq_2d", "irq_vg"; ++ clocks = <&clks IMX6QDL_CLK_GPU2D_AXI>, <&clks IMX6QDL_CLK_OPENVG_AXI>, ++ <&clks IMX6QDL_CLK_GPU3D_AXI>, <&clks IMX6QDL_CLK_GPU2D_CORE>, ++ <&clks IMX6QDL_CLK_GPU3D_CORE>, <&clks IMX6QDL_CLK_GPU3D_SHADER>; ++ 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"; ++ power-domains = <&gpc 1>; ++ }; ++ ++ ocrams: sram@00900000 { ++ compatible = "fsl,lpm-sram"; ++ reg = <0x00900000 0x4000>; ++ clocks = <&clks IMX6QDL_CLK_OCRAM>; ++ }; ++ ++ ocrams_ddr: sram@00904000 { ++ compatible = "fsl,ddr-lpm-sram"; ++ reg = <0x00904000 0x1000>; ++ clocks = <&clks IMX6QDL_CLK_OCRAM>; ++ }; ++ ++ ocram: sram@00905000 { + compatible = "mmio-sram"; +- reg = <0x00900000 0x40000>; +- clocks = <&clks 142>; ++ reg = <0x00905000 0x3B000>; ++ clocks = <&clks IMX6QDL_CLK_OCRAM>; + }; + + aips-bus@02000000 { /* AIPS1 */ +@@ -74,8 +138,9 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02018000 0x4000>; +- interrupts = <0 35 0x04>; +- clocks = <&clks 116>, <&clks 116>; ++ interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6Q_CLK_ECSPI5>, ++ <&clks IMX6Q_CLK_ECSPI5>; + clock-names = "ipg", "per"; + status = "disabled"; + }; +@@ -122,40 +187,81 @@ + }; + }; + ++ aips-bus@02100000 { /* AIPS2 */ ++ mipi_dsi: mipi@021e0000 { ++ compatible = "fsl,imx6q-mipi-dsi"; ++ reg = <0x021e0000 0x4000>; ++ interrupts = <0 102 0x04>; ++ gpr = <&gpr>; ++ clocks = <&clks IMX6QDL_CLK_HSI_TX>, <&clks IMX6QDL_CLK_VIDEO_27M>; ++ clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; ++ status = "disabled"; ++ }; ++ }; ++ + sata: sata@02200000 { + compatible = "fsl,imx6q-ahci"; + reg = <0x02200000 0x4000>; +- interrupts = <0 39 0x04>; +- clocks = <&clks 154>, <&clks 187>, <&clks 105>; ++ interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6QDL_CLK_SATA>, ++ <&clks IMX6QDL_CLK_SATA_REF_100M>, ++ <&clks IMX6QDL_CLK_AHB>; + 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 IMX6QDL_CLK_IPU2>, ++ <&clks IMX6QDL_CLK_IPU2_DI0>, <&clks IMX6QDL_CLK_IPU2_DI1>, ++ <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, <&clks IMX6QDL_CLK_IPU2_DI1_SEL>, ++ <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>; ++ 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"; ++&ecspi1 { ++ dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; ++ dma-names = "rx", "tx"; ++}; + +- lvds-channel@0 { +- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; +- }; ++&ecspi2 { ++ dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; ++ dma-names = "rx", "tx"; ++}; + +- lvds-channel@1 { +- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; +- }; ++&ecspi3 { ++ dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; ++ dma-names = "rx", "tx"; ++}; ++ ++&ecspi4 { ++ dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; ++ dma-names = "rx", "tx"; ++}; ++ ++&ldb { ++ compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb"; ++ ++ clocks = <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>, ++ <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, ++ <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, <&clks IMX6QDL_CLK_IPU2_DI1_SEL>, ++ <&clks IMX6QDL_CLK_LDB_DI0_DIV_3_5>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_3_5>, ++ <&clks IMX6QDL_CLK_LDB_DI0_DIV_7>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_7>, ++ <&clks IMX6QDL_CLK_LDB_DI0_DIV_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_SEL>; ++ clock-names = "ldb_di0", "ldb_di1", ++ "di0_sel", "di1_sel", ++ "di2_sel", "di3_sel", ++ "ldb_di0_div_3_5", "ldb_di1_div_3_5", ++ "ldb_di0_div_7", "ldb_di1_div_7", ++ "ldb_di0_div_sel", "ldb_di1_div_sel"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-hummingboard2.dts linux-3.14.72/arch/arm/boot/dts/imx6q-hummingboard2.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-hummingboard2.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-hummingboard2.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,60 @@ ++/* ++ * Device Tree file for SolidRun HummingBoard2 ++ * Copyright (C) 2015 Rabeeh Khoury ++ * Based on work by Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. ++ */ ++/dts-v1/; ++ ++#include "imx6q.dtsi" ++#include "imx6qdl-hummingboard2.dtsi" ++ ++/ { ++ model = "SolidRun HummingBoard2 Dual/Quad"; ++ compatible = "solidrun,hummingboard2/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.72.orig/arch/arm/boot/dts/imx6q-hummingboard.dts linux-3.14.72/arch/arm/boot/dts/imx6q-hummingboard.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-hummingboard.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-hummingboard.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) ++ * Based on dt work by Russell King ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License. ++ * ++ * This file 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. ++ * ++ * Or, alternatively ++ * ++ * b) 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 shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED , 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 THE AUTHORS OR COPYRIGHT ++ * HOLDERS 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. ++ */ ++/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 = <1025>; ++ fsl,transmit-boost-mdB = <3330>; ++ fsl,transmit-atten-16ths = <9>; ++ fsl,receive-eq-mdB = <3000>; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi linux-3.14.72/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi 2016-06-19 22:11:55.025157951 +0200 +@@ -22,7 +22,7 @@ + + &ecspi3 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_ecspi3_1>; ++ pinctrl-0 = <&pinctrl_ecspi3>; + status = "okay"; + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 24 0>; +@@ -36,7 +36,7 @@ + + &i2c1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c1_1>; ++ pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + eeprom@50 { +@@ -128,7 +128,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6q-phytec-pfla02 { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 +@@ -136,10 +136,73 @@ + MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */ + >; + }; +- }; + +- pfla02 { +- pinctrl_usdhc3_pfla02: usdhc3grp-pfla02 { ++ 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_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ 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 +@@ -150,7 +213,7 @@ + + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_3>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 23 0>; + status = "disabled"; +@@ -158,13 +221,13 @@ + + &uart4 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart4_1>; ++ pinctrl-0 = <&pinctrl_uart4>; + status = "disabled"; + }; + + &usdhc2 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc2_2>; ++ pinctrl-0 = <&pinctrl_usdhc2>; + cd-gpios = <&gpio1 4 0>; + wp-gpios = <&gpio1 2 0>; + status = "disabled"; +@@ -172,8 +235,8 @@ + + &usdhc3 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2 +- &pinctrl_usdhc3_pfla02>; ++ pinctrl-0 = <&pinctrl_usdhc3 ++ &pinctrl_usdhc3_cdwp>; + cd-gpios = <&gpio1 27 0>; + wp-gpios = <&gpio1 29 0>; + status = "disabled"; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-pinfunc.h linux-3.14.72/arch/arm/boot/dts/imx6q-pinfunc.h +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-pinfunc.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-pinfunc.h 2016-06-19 22:11:55.025157951 +0200 +@@ -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 +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -20,6 +20,32 @@ + compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; + }; + ++&ldb { ++ lvds-channel@0 { ++ crtc = "ipu2-di0"; ++ }; ++ ++ lvds-channel@1 { ++ crtc = "ipu2-di1"; ++ }; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&mxcfb3 { ++ status = "okay"; ++}; ++ ++&mxcfb4 { ++ status = "okay"; ++}; ++ + &sata { + status = "okay"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6q-sabreauto.dts" ++ ++&ecspi1 { ++ pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ /* pin conflict with ecspi1 */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* the uart3 depends on the i2c3, so disable it too. */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ /* max7310_c on i2c3 is gone */ ++ status = "okay"; ++ dr_mode = "peripheral"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6q-sabreauto.dts" ++ ++&flexcan1{ ++ status = "okay"; ++}; ++ ++&fec { ++ /* pin conflict with flexcan1 */ ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6q-sabreauto.dts" ++ ++&ecspi1 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&gpmi { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* pin conflict with gpmi and weim */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ /* max7310_c on i2c3 is gone */ ++ status = "okay"; ++ dr_mode = "peripheral"; ++}; ++ ++&weim { ++ pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabrelite.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabrelite.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabrelite.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabrelite.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -23,25 +23,30 @@ + + 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>; + regulator-always-on; + }; + +- reg_usb_otg_vbus: usb_otg_vbus { ++ reg_usb_otg_vbus: regulator@2 { + compatible = "regulator-fixed"; ++ reg = <2>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +@@ -54,7 +59,7 @@ + compatible = "fsl,imx6q-sabrelite-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-sabrelite-sgtl5000"; +- ssi-controller = <&ssi1>; ++ cpu-dai = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", +@@ -68,14 +73,14 @@ + &audmux { + status = "okay"; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_audmux_1>; ++ pinctrl-0 = <&pinctrl_audmux>; + }; + + &ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio3 19 0>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_ecspi1_1>; ++ pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + flash: m25p80@0 { +@@ -87,7 +92,7 @@ + + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_1>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 23 0>; + status = "okay"; +@@ -97,7 +102,7 @@ + status = "okay"; + clock-frequency = <100000>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c1_1>; ++ pinctrl-0 = <&pinctrl_i2c1>; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; +@@ -112,7 +117,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6q-sabrelite { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 +@@ -126,6 +131,86 @@ + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 + >; + }; ++ ++ 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_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_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ 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 ++ >; ++ }; ++ ++ 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 ++ >; ++ }; + }; + }; + +@@ -166,7 +251,7 @@ + &uart2 { + status = "okay"; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart2_1>; ++ pinctrl-0 = <&pinctrl_uart2>; + }; + + &usbh1 { +@@ -176,14 +261,14 @@ + &usbotg { + vbus-supply = <®_usb_otg_vbus>; + 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>; + cd-gpios = <&gpio7 0 0>; + wp-gpios = <&gpio7 1 0>; + vmmc-supply = <®_3p3v>; +@@ -192,7 +277,7 @@ + + &usdhc4 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc4_2>; ++ pinctrl-0 = <&pinctrl_usdhc4>; + cd-gpios = <&gpio2 6 0>; + wp-gpios = <&gpio2 7 0>; + vmmc-supply = <®_3p3v>; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -20,6 +20,38 @@ + compatible = "fsl,imx6q-sabresd", "fsl,imx6q"; + }; + ++&battery { ++ offset-charger = <1900>; ++ offset-discharger = <1694>; ++ offset-usb-charger = <1685>; ++}; ++ ++&ldb { ++ lvds-channel@0 { ++ crtc = "ipu2-di0"; ++ }; ++ ++ lvds-channel@1 { ++ crtc = "ipu2-di1"; ++ }; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&mxcfb3 { ++ status = "okay"; ++}; ++ ++&mxcfb4 { ++ status = "okay"; ++}; ++ + &sata { + status = "okay"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-enetirq.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-enetirq.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-enetirq.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-enetirq.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6q-sabresd.dts" ++ ++&fec { ++ pinctrl-0 = <&pinctrl_enet &pinctrl_enet_irq>; ++ interrupts-extended = <&gpio1 6 0x04>, <&intc 0 119 0x04>; ++}; ++ ++&i2c3 { ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2012-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 "imx6q-sabresd.dts" ++ ++&hdmi_video { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_hdcp>; ++ fsl,hdcp; ++}; ++ ++&i2c2 { ++ status = "disable"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-ldo.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-ldo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-ldo.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6q-sabresd.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++}; ++ ++&gpc { ++ /* use ldo-enable, u-boot will check it and configure */ ++ fsl,ldo-bypass = <0>; ++ /* watchdog select of reset source */ ++ fsl,wdog-reset = <1>; ++}; ++ ++&wdog1 { ++ status = "okay"; ++}; ++ ++&wdog2 { ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-uart.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-uart.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sabresd-uart.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sabresd-uart.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6q-sabresd.dts" ++ ++/ { ++ leds { ++ compatible = "gpio-leds"; ++ status = "disabled"; ++ }; ++}; ++ ++&uart5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5_1>; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++ /* for DTE mode, add below change */ ++ /* fsl,dte-mode; */ ++ /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ ++}; ++ ++&ecspi1 { ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sbc6x.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sbc6x.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sbc6x.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sbc6x.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -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.72.orig/arch/arm/boot/dts/imx6q-sbc-fx6.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sbc-fx6.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sbc-fx6.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sbc-fx6.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,23 @@ ++/* ++* Copyright 2014 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" ++#include "imx6q-cm-fx6.dtsi" ++#include "imx6qdl-sb-fx6x.dtsi" ++#include "imx6qdl-sb-fx6.dtsi" ++ ++/ { ++ model = "CompuLab CM-FX6 on SBC-FX6"; ++ compatible = "compulab,cm-fx6", "compulab,sbc-fx6", "fsl,imx6q"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sbc-fx6m.dts linux-3.14.72/arch/arm/boot/dts/imx6q-sbc-fx6m.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-sbc-fx6m.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-sbc-fx6m.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,33 @@ ++/* ++* Copyright 2014 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" ++#include "imx6q-cm-fx6.dtsi" ++#include "imx6qdl-sb-fx6x.dtsi" ++#include "imx6qdl-sb-fx6m.dtsi" ++ ++/ { ++ model = "CompuLab CM-FX6 on SBC-FX6m"; ++ compatible = "compulab,cm-fx6", "compulab,sbc-fx6m", "fsl,imx6q"; ++ ++ aliases { ++ mmc0 = &usdhc3; ++ }; ++}; ++ ++&hdmi_core { ++ ipu_id = <1>; ++ disp_id = <0>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6q-tbs2910.dts linux-3.14.72/arch/arm/boot/dts/imx6q-tbs2910.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-tbs2910.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-tbs2910.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -0,0 +1,643 @@ ++/* ++ * 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 ++#include ++ ++/ { ++ model = "TBS Matrix"; ++ compatible = "fsl,imx6q-sabresd", "fsl,imx6q"; ++ ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ mmc0 = &usdhc4; ++ }; ++ ++ chosen { ++ stdout-path = &uart1; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x80000000>; ++ }; ++ ++ 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>; ++ }; ++ ++ reg_3p3v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_5p0v: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "5P0V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ }; ++ ++ ir_recv: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio3 18 GPIO_ACTIVE_LOW>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ir>; ++ linux,rc-map-name = "rc-rc6-mce"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_leds>; ++ ++ red { ++ label = "red"; ++ gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ ++ fan { ++ compatible = "gpio-fan"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_fan>; ++ gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>; ++ gpio-fan,speed-map = <0 0 ++ 3000 1>; ++ }; ++ ++ sound { ++ compatible = "fsl,imx-audio-sgtl5000"; ++ model = "imx-sgtl5000"; ++ cpu-dai = <&ssi2>; ++ audio-codec = <&codec>; ++ audio-routing = "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <2>; ++ mux-ext-port = <3>; ++ }; ++ ++ 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 = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str ="LDB-XGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; ++ ++ 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"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++ ++ restart_poweroff { ++ compatible = "fsl,snvs-poweroff"; ++ }; ++}; ++ ++&sata { ++ status = "okay"; ++}; ++ ++&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 25 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ codec: sgtl5000@0a { ++ clocks = <&clks 201>; ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sgtl5000>; ++ VDDA-supply = <®_2p5v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++}; ++ ++&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 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ rtc: ds1307@68 { ++ compatible = "dallas,ds1307"; ++ reg = <0x68>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6qdl-sabresd { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 /* HUB_GPIO_RST */ ++ MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 /* eMMC_RST */ ++ >; ++ }; ++ ++ pinctrl_sgtl5000: sgtl5000grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 ++ >; ++ }; ++ ++ 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 ++ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b059 ++ >; ++ }; ++ ++ pinctrl_ir: sabresd-ir { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x17059 ++ >; ++ }; ++ ++ pinctrl_sabresd_spdif: sabresd-spdif { ++ fsl,pins = ; ++ }; ++ ++ 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_pcie: pciegrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x17059 ++ >; ++ }; ++ ++ 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_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_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 0x17059 ++ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 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_NANDF_D0__GPIO2_IO00 0x17059 ++ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 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 0x130b1 ++ >; ++ }; ++ }; ++ ++ gpio_fan { ++ pinctrl_gpio_fan: gpiofangrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x130b1 ++ >; ++ }; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pcie>; ++ power-on-gpio = <&gpio3 19 0>; ++ reset-gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ 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"; ++}; ++ ++&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"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sabresd_spdif>; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_5p0v>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_5p0v>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ bus-width = <4>; ++ cd-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>; ++ card-external-vcc-supply = <®_3p3v>; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ bus-width = <4>; ++ cd-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; ++ card-external-vcc-supply = <®_3p3v>; ++ 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.72.orig/arch/arm/boot/dts/imx6q-udoo.dts linux-3.14.72/arch/arm/boot/dts/imx6q-udoo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6q-udoo.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6q-udoo.dts 2016-06-19 22:11:55.025157951 +0200 +@@ -2,6 +2,7 @@ + * Copyright 2013 Freescale Semiconductor, Inc. + * + * Author: Fabio Estevam ++ * Author: Ettore Chimenti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -11,29 +12,14 @@ + + /dts-v1/; + #include "imx6q.dtsi" ++#include "imx6qdl-udoo.dtsi" + + / { + model = "Udoo i.MX6 Quad Board"; + compatible = "udoo,imx6q-udoo", "fsl,imx6q"; +- +- memory { +- reg = <0x10000000 0x40000000>; +- }; + }; + + &sata { + status = "okay"; + }; + +-&uart2 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart2_1>; +- status = "okay"; +-}; +- +-&usdhc3 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2>; +- non-removable; +- status = "okay"; +-}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sl.dtsi linux-3.14.72/arch/arm/boot/dts/imx6sl.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sl.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sl.dtsi 2016-06-19 22:11:55.029157811 +0200 +@@ -7,6 +7,8 @@ + * + */ + ++#include ++#include + #include "skeleton.dtsi" + #include "imx6sl-pinfunc.h" + #include +@@ -18,6 +20,10 @@ + gpio2 = &gpio3; + gpio3 = &gpio4; + gpio4 = &gpio5; ++ mmc0 = &usdhc1; ++ mmc1 = &usdhc2; ++ mmc2 = &usdhc3; ++ mmc3 = &usdhc4; + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; +@@ -27,25 +33,49 @@ + 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>, ++ <&clks IMX6SL_PLL1_BYPASS>, ++ <&clks IMX6SL_CLK_PLL1>, ++ <&clks IMX6SL_PLL1_BYPASS_SRC> ; ++ clock-names = "arm", "pll2_pfd2_396m", "step", ++ "pll1_sw", "pll1_sys", "pll1_bypass", "pll1", "pll1_bypass_src"; ++ 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>; +@@ -66,6 +96,10 @@ + }; + }; + ++ reg_vbus_wakeup: usb_vbus_wakeup { ++ compatible = "fsl,imx6-dummy-ldo2p5"; ++ }; ++ + soc { + #address-cells = <1>; + #size-cells = <1>; +@@ -73,19 +107,60 @@ + interrupt-parent = <&intc>; + ranges; + ++ busfreq { /* BUSFREQ */ ++ compatible = "fsl,imx6_busfreq"; ++ clocks = <&clks IMX6SL_CLK_PLL2_BUS>, <&clks IMX6SL_CLK_PLL2_PFD2>, ++ <&clks IMX6SL_CLK_PLL2_198M>, <&clks IMX6SL_CLK_ARM>, ++ <&clks IMX6SL_CLK_PLL3_USB_OTG>, <&clks IMX6SL_CLK_PERIPH>, ++ <&clks IMX6SL_CLK_PRE_PERIPH_SEL>, <&clks IMX6SL_CLK_PERIPH_CLK2_PODF>, ++ <&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_PODF>, ++ <&clks IMX6SL_CLK_STEP>, <&clks IMX6SL_PLL2_BYPASS_SRC>, <&clks IMX6SL_PLL2_BYPASS>, ++ <&clks IMX6SL_CLK_PLL2>, <&clks IMX6SL_CLK_PLL1>, <&clks IMX6SL_PLL1_BYPASS>, ++ <&clks IMX6SL_PLL1_BYPASS_SRC>; ++ 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", "pll2_bypass_src", ++ "pll2_bypass", "pll2", "pll1", "pll1_bypass", "pll1_bypass_src"; ++ fsl,max_ddr_freq = <400000000>; ++ }; ++ ++ ocrams: sram@00900000 { ++ compatible = "fsl,lpm-sram"; ++ reg = <0x00900000 0x4000>; ++ clocks = <&clks IMX6SL_CLK_OCRAM>; ++ }; ++ ++ ocrams_ddr: sram@00904000 { ++ compatible = "fsl,ddr-lpm-sram"; ++ reg = <0x00904000 0x1000>; ++ clocks = <&clks IMX6SL_CLK_OCRAM>; ++ }; ++ ++ ocram: sram@00905000 { ++ compatible = "mmio-sram"; ++ reg = <0x00905000 0x1B000>; ++ clocks = <&clks IMX6SL_CLK_OCRAM>; ++ }; ++ + 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 { +@@ -103,8 +178,24 @@ + ranges; + + spdif: spdif@02004000 { ++ compatible = "fsl,imx6sl-spdif", ++ "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"; ++ clocks = <&clks IMX6SL_CLK_SPDIF_GCLK>, <&clks IMX6SL_CLK_OSC>, ++ <&clks IMX6SL_CLK_SPDIF>, <&clks IMX6SL_CLK_DUMMY>, ++ <&clks IMX6SL_CLK_DUMMY>, <&clks IMX6SL_CLK_DUMMY>, ++ <&clks IMX6SL_CLK_IPG>, <&clks IMX6SL_CLK_DUMMY>, ++ <&clks IMX6SL_CLK_DUMMY>, <&clks IMX6SL_CLK_SPBA>; ++ clock-names = "core", "rxtx0", ++ "rxtx1", "rxtx2", ++ "rxtx3", "rxtx4", ++ "rxtx5", "rxtx6", ++ "rxtx7", "dma"; ++ status = "disabled"; + }; + + ecspi1: ecspi@02008000 { +@@ -112,10 +203,12 @@ + #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"; ++ dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -124,10 +217,12 @@ + #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"; ++ dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -136,10 +231,12 @@ + #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"; ++ dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -148,10 +245,12 @@ + #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"; ++ dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -159,7 +258,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 +271,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 +284,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"; +@@ -197,8 +296,10 @@ + ssi1: ssi@02028000 { + compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + reg = <0x02028000 0x4000>; +- interrupts = <0 46 0x04>; +- clocks = <&clks IMX6SL_CLK_SSI1>; ++ interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_SSI1_IPG>, ++ <&clks IMX6SL_CLK_SSI1>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 37 1 0>, + <&sdma 38 1 0>; + dma-names = "rx", "tx"; +@@ -209,8 +310,10 @@ + ssi2: ssi@0202c000 { + compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + reg = <0x0202c000 0x4000>; +- interrupts = <0 47 0x04>; +- clocks = <&clks IMX6SL_CLK_SSI2>; ++ interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_SSI2_IPG>, ++ <&clks IMX6SL_CLK_SSI2>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 41 1 0>, + <&sdma 42 1 0>; + dma-names = "rx", "tx"; +@@ -221,8 +324,10 @@ + ssi3: ssi@02030000 { + compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + reg = <0x02030000 0x4000>; +- interrupts = <0 48 0x04>; +- clocks = <&clks IMX6SL_CLK_SSI3>; ++ interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_SSI3_IPG>, ++ <&clks IMX6SL_CLK_SSI3>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 45 1 0>, + <&sdma 46 1 0>; + dma-names = "rx", "tx"; +@@ -234,7 +339,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 +352,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 +366,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 +376,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 +386,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 +396,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 +405,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 +414,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 +425,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 +436,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 +447,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 +458,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 +467,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 +491,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 +501,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 +549,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; +@@ -447,6 +562,7 @@ + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; ++ regulator-allow-bypass; + }; + + reg_pu: regulator-vddpu@140 { +@@ -454,7 +570,8 @@ + regulator-name = "vddpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; +- regulator-always-on; ++ regulator-enable-ramp-delay = <150>; ++ regulator-boot-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <9>; + anatop-vol-bit-width = <5>; +@@ -464,6 +581,7 @@ + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; ++ regulator-allow-bypass; + }; + + reg_soc: regulator-vddsoc@140 { +@@ -481,21 +599,38 @@ + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; ++ regulator-allow-bypass; + }; + }; + ++ 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,31 +642,41 @@ + 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>; ++ interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + }; + + epit2: epit@020d4000 { + reg = <0x020d4000 0x4000>; +- interrupts = <0 57 0x04>; ++ interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; + }; + + src: src@020d8000 { + compatible = "fsl,imx6sl-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,imx6sl-gpc", "fsl,imx6q-gpc"; + reg = <0x020dc000 0x4000>; +- interrupts = <0 89 0x04>; ++ interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>; ++ pu-supply = <®_pu>; ++ clocks = <&clks IMX6SL_CLK_GPU2D_PODF>, <&clks IMX6SL_CLK_GPU2D_OVG>, ++ <&clks IMX6SL_CLK_IPG>, <&clks IMX6SL_CLK_LCDIF_AXI>, ++ <&clks IMX6SL_CLK_LCDIF_PIX>, <&clks IMX6SL_CLK_EPDC_AXI>, ++ <&clks IMX6SL_CLK_EPDC_PIX>, <&clks IMX6SL_CLK_PXP_AXI>; ++ clock-names = "gpu2d_podf", "gpu2d_ovg", "ipg", "lcd_axi", ++ "lcd_pix", "epdc_axi", "epdc_pix", "pxp_axi"; ++ #power-domain-cells = <1>; + }; + + gpr: iomuxc-gpr@020e0000 { +@@ -543,261 +688,69 @@ + iomuxc: iomuxc@020e0000 { + compatible = "fsl,imx6sl-iomuxc"; + reg = <0x020e0000 0x4000>; +- +- ecspi1 { +- pinctrl_ecspi1_1: ecspi1grp-1 { +- fsl,pins = < +- MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 +- MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 +- MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 +- >; +- }; +- }; +- +- fec { +- pinctrl_fec_1: fecgrp-1 { +- fsl,pins = < +- MX6SL_PAD_FEC_MDC__FEC_MDC 0x1b0b0 +- MX6SL_PAD_FEC_MDIO__FEC_MDIO 0x1b0b0 +- MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV 0x1b0b0 +- MX6SL_PAD_FEC_RXD0__FEC_RX_DATA0 0x1b0b0 +- MX6SL_PAD_FEC_RXD1__FEC_RX_DATA1 0x1b0b0 +- MX6SL_PAD_FEC_TX_EN__FEC_TX_EN 0x1b0b0 +- MX6SL_PAD_FEC_TXD0__FEC_TX_DATA0 0x1b0b0 +- MX6SL_PAD_FEC_TXD1__FEC_TX_DATA1 0x1b0b0 +- MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT 0x4001b0a8 +- >; +- }; +- }; +- +- uart1 { +- pinctrl_uart1_1: uart1grp-1 { +- fsl,pins = < +- MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 +- MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 +- >; +- }; +- }; +- +- usbotg1 { +- pinctrl_usbotg1_1: usbotg1grp-1 { +- fsl,pins = < +- MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 +- >; +- }; +- +- pinctrl_usbotg1_2: usbotg1grp-2 { +- fsl,pins = < +- MX6SL_PAD_FEC_RXD0__USB_OTG1_ID 0x17059 +- >; +- }; +- +- pinctrl_usbotg1_3: usbotg1grp-3 { +- fsl,pins = < +- MX6SL_PAD_LCD_DAT1__USB_OTG1_ID 0x17059 +- >; +- }; +- +- pinctrl_usbotg1_4: usbotg1grp-4 { +- fsl,pins = < +- MX6SL_PAD_REF_CLK_32K__USB_OTG1_ID 0x17059 +- >; +- }; +- +- pinctrl_usbotg1_5: usbotg1grp-5 { +- fsl,pins = < +- MX6SL_PAD_SD3_DAT0__USB_OTG1_ID 0x17059 +- >; +- }; +- }; +- +- usbotg2 { +- pinctrl_usbotg2_1: usbotg2grp-1 { +- fsl,pins = < +- MX6SL_PAD_ECSPI1_SCLK__USB_OTG2_OC 0x17059 +- >; +- }; +- +- pinctrl_usbotg2_2: usbotg2grp-2 { +- fsl,pins = < +- MX6SL_PAD_ECSPI2_SCLK__USB_OTG2_OC 0x17059 +- >; +- }; +- +- pinctrl_usbotg2_3: usbotg2grp-3 { +- fsl,pins = < +- MX6SL_PAD_KEY_ROW5__USB_OTG2_OC 0x17059 +- >; +- }; +- +- pinctrl_usbotg2_4: usbotg2grp-4 { +- fsl,pins = < +- MX6SL_PAD_SD3_DAT2__USB_OTG2_OC 0x17059 +- >; +- }; +- }; +- +- usdhc1 { +- pinctrl_usdhc1_1: usdhc1grp-1 { +- fsl,pins = < +- MX6SL_PAD_SD1_CMD__SD1_CMD 0x17059 +- MX6SL_PAD_SD1_CLK__SD1_CLK 0x10059 +- MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x17059 +- MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x17059 +- MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x17059 +- MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x17059 +- MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x17059 +- MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x17059 +- MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x17059 +- MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059 +- >; +- }; +- +- 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 +- >; +- }; +- +- pinctrl_usdhc2_1_200mhz: usdhc2grp-1-200mhz { +- fsl,pins = < +- MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 +- MX6SL_PAD_SD2_CLK__SD2_CLK 0x100f9 +- MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 +- MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 +- MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 +- MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 +- >; +- }; +- +- }; +- +- usdhc3 { +- pinctrl_usdhc3_1: usdhc3grp-1 { +- fsl,pins = < +- MX6SL_PAD_SD3_CMD__SD3_CMD 0x17059 +- MX6SL_PAD_SD3_CLK__SD3_CLK 0x10059 +- MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x17059 +- MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x17059 +- MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x17059 +- MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059 +- >; +- }; +- +- pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { +- fsl,pins = < +- MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 +- MX6SL_PAD_SD3_CLK__SD3_CLK 0x100b9 +- MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 +- MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 +- MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 +- MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 +- >; +- }; +- +- pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { +- fsl,pins = < +- MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 +- MX6SL_PAD_SD3_CLK__SD3_CLK 0x100f9 +- MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 +- MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 +- MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 +- MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 +- >; +- }; +- }; + }; + + csi: csi@020e4000 { ++ compatible = "fsl,imx6s-csi"; + reg = <0x020e4000 0x4000>; +- interrupts = <0 7 0x04>; ++ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_DUMMY>, ++ <&clks IMX6SL_CLK_DUMMY>, ++ <&clks IMX6SL_CLK_DUMMY>; ++ clock-names = "disp-axi", "csi_mclk", "disp_dcic"; ++ 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"; + #dma-cells = <3>; ++ iram = <&ocram>; + /* imx6sl reuses imx6q sdma firmware */ + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; + }; + + pxp: pxp@020f0000 { ++ compatible = "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; + reg = <0x020f0000 0x4000>; +- interrupts = <0 98 0x04>; ++ interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_PXP_AXI>, <&clks IMX6SL_CLK_DUMMY>; ++ clock-names = "pxp-axi", "disp-axi"; ++ status = "disabled"; + }; + + epdc: epdc@020f4000 { ++ compatible = "fsl,imx6sl-epdc", "fsl,imx6dl-epdc"; + reg = <0x020f4000 0x4000>; +- interrupts = <0 97 0x04>; ++ interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_EPDC_AXI>, <&clks IMX6SL_CLK_EPDC_PIX>; ++ clock-names = "epdc_axi", "epdc_pix"; + }; + + lcdif: lcdif@020f8000 { ++ compatible = "fsl,imx6sl-lcdif", "fsl,imx28-lcdif"; + reg = <0x020f8000 0x4000>; +- interrupts = <0 39 0x04>; ++ interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_LCDIF_PIX>, ++ <&clks IMX6SL_CLK_LCDIF_AXI>, ++ <&clks IMX6SL_CLK_DUMMY>; ++ clock-names = "pix", "axi", "disp_axi"; ++ status = "disabled"; + }; + ++ + dcp: dcp@020fc000 { + reg = <0x020fc000 0x4000>; +- interrupts = <0 99 0x04>; ++ interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + +@@ -811,17 +764,18 @@ + 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>; ++ fsl,anatop = <&anatop>; + status = "disabled"; + }; + + 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 +785,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"; + }; + +@@ -842,12 +799,13 @@ + compatible = "fsl,imx6sl-usbmisc", "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; + clocks = <&clks IMX6SL_CLK_USBOH3>; ++ vbus-wakeup-supply = <®_vbus_wakeup>; + }; + + 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 +815,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 +827,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 +839,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 +851,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 +865,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 +875,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 +885,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"; + }; +@@ -937,19 +895,28 @@ + reg = <0x021b0000 0x4000>; + }; + +- rngb: rngb@021b4000 { ++ rng: rng@021b4000 { ++ compatible = "fsl,imx6sl-rng", "fsl,imx-rng", "imx-rng"; + reg = <0x021b4000 0x4000>; +- interrupts = <0 5 0x04>; ++ interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_DUMMY>; + }; + + weim: weim@021b8000 { + reg = <0x021b8000 0x4000>; +- interrupts = <0 14 0x04>; ++ interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>; + }; + +- ocotp: ocotp@021bc000 { +- compatible = "fsl,imx6sl-ocotp"; ++ ocotp: ocotp-ctrl@021bc000 { ++ compatible = "syscon"; + reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6SL_CLK_OCOTP>; ++ }; ++ ++ ocotp-fuse@021bc000 { ++ compatible = "fsl,imx6sl-ocotp", "fsl,imx6q-ocotp"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6SL_CLK_OCOTP>; + }; + + audmux: audmux@021d8000 { +@@ -957,6 +924,24 @@ + 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 = , ; ++ 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"; ++ power-domains = <&gpc 1>; ++ }; + }; + }; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-csi.dts linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-csi.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-csi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-csi.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,21 @@ ++/* ++ * 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 { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ status = "okay"; ++}; ++ ++&epdc { ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk.dts linux-3.14.72/arch/arm/boot/dts/imx6sl-evk.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk.dts 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sl-evk.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * Copyright (C) 2013-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 +@@ -8,21 +8,45 @@ + + /dts-v1/; + ++#include + #include "imx6sl.dtsi" + + / { + model = "Freescale i.MX6 SoloLite EVK Board"; + compatible = "fsl,imx6sl-evk", "fsl,imx6sl"; + ++ battery: max8903@0 { ++ compatible = "fsl,max8903-charger"; ++ pinctrl-names = "default"; ++ dok_input = <&gpio4 13 1>; ++ uok_input = <&gpio4 13 1>; ++ chg_input = <&gpio4 15 1>; ++ flt_input = <&gpio4 14 1>; ++ fsl,dcm_always_high; ++ fsl,dc_valid; ++ fsl,adc_disable; ++ status = "okay"; ++ }; ++ + memory { + reg = <0x80000000 0x40000000>; + }; + + regulators { + compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_lcd_3v3: lcd-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "lcd-3v3"; ++ gpio = <&gpio4 3 0>; ++ enable-active-high; ++ }; + +- 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 +54,119 @@ + 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; ++ }; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm1 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabresd-wm8962", ++ "fsl,imx-audio-wm8962"; ++ model = "wm8962-audio"; ++ cpu-dai = <&ssi2>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "Headphone Jack", "HPOUTL", ++ "Headphone Jack", "HPOUTR", ++ "Ext Spk", "SPKOUTL", ++ "Ext Spk", "SPKOUTR", ++ "AMIC", "MICBIAS", ++ "IN3R", "AMIC"; ++ amic-mono; ++ mux-int-port = <2>; ++ mux-ext-port = <3>; ++ hp-det-gpios = <&gpio4 19 1>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx6sl-evk-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-out; ++ }; ++ ++ sii902x_reset: sii902x-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio2 19 1>; ++ reset-delay-us = <100000>; ++ #reset-cells = <0>; + }; + }; + ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&clks { ++ assigned-clocks = <&clks IMX6SL_PLL4_BYPASS_SRC>, ++ <&clks IMX6SL_PLL4_BYPASS>, ++ <&clks IMX6SL_CLK_EXTERN_AUDIO_SEL>, ++ <&clks IMX6SL_CLK_EXTERN_AUDIO>, ++ <&clks IMX6SL_CLK_PLL4_POST_DIV>; ++ assigned-clock-parents = <&clks IMX6SL_CLK_OSC>, ++ <&clks IMX6SL_PLL4_BYPASS_SRC>, ++ <&clks IMX6SL_CLK_PLL4_AUDIO_DIV>; ++ assigned-clock-rates = <0>, <0>, <0>, <24000000>, ++ <24000000>; ++}; ++ ++&csi { ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&ov5640_ep>; ++ }; ++ }; ++}; ++ ++&cpu0 { ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1c_reg>; ++}; ++ + &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 +178,287 @@ + }; + }; + ++&epdc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_epdc_0>; ++ V3P3-supply = <&V3P3_reg>; ++ VCOM-supply = <&VCOM_reg>; ++ DISPLAY-supply = <&DISPLAY_reg>; ++ status = "okay"; ++}; ++ + &fec { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_fec_1>; ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&pinctrl_fec>; ++ pinctrl-1 = <&pinctrl_fec_sleep>; + phy-mode = "rmii"; + status = "okay"; + }; + ++&gpc { ++ /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,ldo-bypass = <1>; ++ /* watchdog select of reset source */ ++ fsl,wdog-reset = <1>; ++}; ++ ++&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>; ++ regulator-always-on; ++ }; ++ ++ vgen4_reg: vgen4 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen5_reg: vgen5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen6_reg: vgen6 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ elan@10 { ++ compatible = "elan,elan-touch"; ++ reg = <0x10>; ++ interrupt-parent = <&gpio2>; ++ interrupts = <10 2>; ++ gpio_elan_cs = <&gpio2 9 0>; ++ gpio_elan_rst = <&gpio4 4 0>; ++ gpio_intr = <&gpio2 10 0>; ++ status = "okay"; ++ }; ++ ++ mma8450@1c { ++ compatible = "fsl,mma8450"; ++ reg = <0x1c>; ++ }; ++ ++ max17135@48 { ++ compatible = "maxim,max17135"; ++ reg = <0x48>; ++ vneg_pwrup = <1>; ++ gvee_pwrup = <2>; ++ vpos_pwrup = <10>; ++ gvdd_pwrup = <12>; ++ gvdd_pwrdn = <1>; ++ vpos_pwrdn = <2>; ++ gvee_pwrdn = <8>; ++ vneg_pwrdn = <10>; ++ gpio_pmic_pwrgood = <&gpio2 13 0>; ++ gpio_pmic_vcom_ctrl = <&gpio2 3 0>; ++ gpio_pmic_wakeup = <&gpio2 14 0>; ++ gpio_pmic_v3p3 = <&gpio2 7 0>; ++ gpio_pmic_intr = <&gpio2 12 0>; ++ ++ regulators { ++ DISPLAY_reg: DISPLAY { ++ regulator-name = "DISPLAY"; ++ }; ++ ++ GVDD_reg: GVDD { ++ /* 20v */ ++ regulator-name = "GVDD"; ++ }; ++ ++ GVEE_reg: GVEE { ++ /* -22v */ ++ regulator-name = "GVEE"; ++ }; ++ ++ HVINN_reg: HVINN { ++ /* -22v */ ++ regulator-name = "HVINN"; ++ }; ++ ++ HVINP_reg: HVINP { ++ /* 20v */ ++ regulator-name = "HVINP"; ++ }; ++ ++ VCOM_reg: VCOM { ++ regulator-name = "VCOM"; ++ /* 2's-compliment, -4325000 */ ++ regulator-min-microvolt = <0xffbe0178>; ++ /* 2's-compliment, -500000 */ ++ regulator-max-microvolt = <0xfff85ee0>; ++ }; ++ ++ VNEG_reg: VNEG { ++ /* -15v */ ++ regulator-name = "VNEG"; ++ }; ++ ++ VPOS_reg: VPOS { ++ /* 15v */ ++ regulator-name = "VPOS"; ++ }; ++ ++ V3P3_reg: V3P3 { ++ regulator-name = "V3P3"; ++ }; ++ }; ++ }; ++ ++}; ++ ++&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>; ++ amic-mono; ++ }; ++ ++ sii902x@39 { ++ compatible = "SiI,sii902x"; ++ interrupt-parent = <&gpio2>; ++ interrupts = <10 2>; ++ mode_str ="1280x720M@60"; ++ bits-per-pixel = <16>; ++ resets = <&sii902x_reset>; ++ reg = <0x39>; ++ }; ++ ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "disabled"; ++ ++ ov5640: ov5640@3c { ++ compatible = "ovti,ov5640"; ++ 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>; ++ port { ++ ov5640_ep: endpoint { ++ remote-endpoint = <&csi_ep>; ++ }; ++ }; ++ }; ++}; ++ + &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 +468,438 @@ + MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 + MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000 + MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 ++ MX6SL_PAD_ECSPI2_MISO__GPIO4_IO14 0x17000 ++ MX6SL_PAD_ECSPI2_MOSI__GPIO4_IO13 0x17000 ++ MX6SL_PAD_ECSPI2_SS0__GPIO4_IO15 0x17000 ++ MX6SL_PAD_FEC_RX_ER__GPIO4_IO19 0x1b0b0 ++ MX6SL_PAD_EPDC_PWRCTRL3__GPIO2_IO10 0x17000 ++ MX6SL_PAD_EPDC_PWRCTRL2__GPIO2_IO09 0x80000000 ++ MX6SL_PAD_KEY_COL6__GPIO4_IO04 0x110b0 ++ MX6SL_PAD_LCD_RESET__GPIO2_IO19 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6SL_PAD_AUD_RXD__AUD3_RXD 0x4130b0 ++ MX6SL_PAD_AUD_TXC__AUD3_TXC 0x4130b0 ++ MX6SL_PAD_AUD_TXD__AUD3_TXD 0x4110b0 ++ MX6SL_PAD_AUD_TXFS__AUD3_TXFS 0x4130b0 ++ MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0 ++ >; ++ }; ++ ++ ++ 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 ++ >; ++ }; ++ ++ pinctrl_epdc_0: epdcgrp-0 { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_D0__EPDC_DATA00 0x80000000 ++ MX6SL_PAD_EPDC_D1__EPDC_DATA01 0x80000000 ++ MX6SL_PAD_EPDC_D2__EPDC_DATA02 0x80000000 ++ MX6SL_PAD_EPDC_D3__EPDC_DATA03 0x80000000 ++ MX6SL_PAD_EPDC_D4__EPDC_DATA04 0x80000000 ++ MX6SL_PAD_EPDC_D5__EPDC_DATA05 0x80000000 ++ MX6SL_PAD_EPDC_D6__EPDC_DATA06 0x80000000 ++ MX6SL_PAD_EPDC_D7__EPDC_DATA07 0x80000000 ++ MX6SL_PAD_EPDC_D8__EPDC_DATA08 0x80000000 ++ MX6SL_PAD_EPDC_D9__EPDC_DATA09 0x80000000 ++ MX6SL_PAD_EPDC_D10__EPDC_DATA10 0x80000000 ++ MX6SL_PAD_EPDC_D11__EPDC_DATA11 0x80000000 ++ MX6SL_PAD_EPDC_D12__EPDC_DATA12 0x80000000 ++ MX6SL_PAD_EPDC_D13__EPDC_DATA13 0x80000000 ++ MX6SL_PAD_EPDC_D14__EPDC_DATA14 0x80000000 ++ MX6SL_PAD_EPDC_D15__EPDC_DATA15 0x80000000 ++ MX6SL_PAD_EPDC_GDCLK__EPDC_GDCLK 0x80000000 ++ MX6SL_PAD_EPDC_GDSP__EPDC_GDSP 0x80000000 ++ MX6SL_PAD_EPDC_GDOE__EPDC_GDOE 0x80000000 ++ MX6SL_PAD_EPDC_GDRL__EPDC_GDRL 0x80000000 ++ MX6SL_PAD_EPDC_SDCLK__EPDC_SDCLK_P 0x80000000 ++ MX6SL_PAD_EPDC_SDOE__EPDC_SDOE 0x80000000 ++ MX6SL_PAD_EPDC_SDLE__EPDC_SDLE 0x80000000 ++ MX6SL_PAD_EPDC_SDSHR__EPDC_SDSHR 0x80000000 ++ MX6SL_PAD_EPDC_BDR0__EPDC_BDR0 0x80000000 ++ MX6SL_PAD_EPDC_SDCE0__EPDC_SDCE0 0x80000000 ++ MX6SL_PAD_EPDC_SDCE1__EPDC_SDCE1 0x80000000 ++ MX6SL_PAD_EPDC_SDCE2__EPDC_SDCE2 0x80000000 ++ >; ++ }; ++ ++ 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_fec_sleep: fecgrp-sleep { ++ fsl,pins = < ++ MX6SL_PAD_FEC_MDC__GPIO4_IO23 0x3080 ++ MX6SL_PAD_FEC_MDIO__GPIO4_IO20 0x3080 ++ MX6SL_PAD_FEC_CRS_DV__GPIO4_IO25 0x3080 ++ MX6SL_PAD_FEC_RXD0__GPIO4_IO17 0x3080 ++ MX6SL_PAD_FEC_RXD1__GPIO4_IO18 0x3080 ++ MX6SL_PAD_FEC_TX_EN__GPIO4_IO22 0x3080 ++ MX6SL_PAD_FEC_TXD0__GPIO4_IO24 0x3080 ++ MX6SL_PAD_FEC_TXD1__GPIO4_IO16 0x3080 ++ MX6SL_PAD_FEC_REF_CLK__GPIO4_IO26 0x3080 ++ >; ++ }; ++ ++ pinctrl_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_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_SDCE2__I2C3_SCL 0x4001b8b1 ++ MX6SL_PAD_EPDC_SDCE3__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ 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_lcdif_dat: lcdifdatgrp { ++ fsl,pins = < ++ MX6SL_PAD_LCD_DAT0__LCD_DATA00 0x1b0b0 ++ MX6SL_PAD_LCD_DAT1__LCD_DATA01 0x1b0b0 ++ MX6SL_PAD_LCD_DAT2__LCD_DATA02 0x1b0b0 ++ MX6SL_PAD_LCD_DAT3__LCD_DATA03 0x1b0b0 ++ MX6SL_PAD_LCD_DAT4__LCD_DATA04 0x1b0b0 ++ MX6SL_PAD_LCD_DAT5__LCD_DATA05 0x1b0b0 ++ MX6SL_PAD_LCD_DAT6__LCD_DATA06 0x1b0b0 ++ MX6SL_PAD_LCD_DAT7__LCD_DATA07 0x1b0b0 ++ MX6SL_PAD_LCD_DAT8__LCD_DATA08 0x1b0b0 ++ MX6SL_PAD_LCD_DAT9__LCD_DATA09 0x1b0b0 ++ MX6SL_PAD_LCD_DAT10__LCD_DATA10 0x1b0b0 ++ MX6SL_PAD_LCD_DAT11__LCD_DATA11 0x1b0b0 ++ MX6SL_PAD_LCD_DAT12__LCD_DATA12 0x1b0b0 ++ MX6SL_PAD_LCD_DAT13__LCD_DATA13 0x1b0b0 ++ MX6SL_PAD_LCD_DAT14__LCD_DATA14 0x1b0b0 ++ MX6SL_PAD_LCD_DAT15__LCD_DATA15 0x1b0b0 ++ MX6SL_PAD_LCD_DAT16__LCD_DATA16 0x1b0b0 ++ MX6SL_PAD_LCD_DAT17__LCD_DATA17 0x1b0b0 ++ MX6SL_PAD_LCD_DAT18__LCD_DATA18 0x1b0b0 ++ MX6SL_PAD_LCD_DAT19__LCD_DATA19 0x1b0b0 ++ MX6SL_PAD_LCD_DAT20__LCD_DATA20 0x1b0b0 ++ MX6SL_PAD_LCD_DAT21__LCD_DATA21 0x1b0b0 ++ MX6SL_PAD_LCD_DAT22__LCD_DATA22 0x1b0b0 ++ MX6SL_PAD_LCD_DAT23__LCD_DATA23 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_lcdif_ctrl: lcdifctrlgrp { ++ fsl,pins = < ++ MX6SL_PAD_LCD_CLK__LCD_CLK 0x1b0b0 ++ MX6SL_PAD_LCD_ENABLE__LCD_ENABLE 0x1b0b0 ++ MX6SL_PAD_LCD_HSYNC__LCD_HSYNC 0x1b0b0 ++ MX6SL_PAD_LCD_VSYNC__LCD_VSYNC 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_pwm1: pwm1grp { ++ fsl,pins = < ++ MX6SL_PAD_PWM1__PWM1_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_pwm1_sleep: pwm1grp-sleep { ++ fsl,pins = < ++ MX6SL_PAD_PWM1__GPIO3_IO23 0x3080 ++ >; ++ }; ++ ++ pinctrl_spdif: spdifgrp { ++ fsl,pins = < ++ MX6SL_PAD_SD2_DAT4__SPDIF_OUT 0x80000000 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 ++ MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart4_1: uart4grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_SD1_DAT4__UART4_RX_DATA 0x1b0b1 ++ MX6SL_PAD_SD1_DAT5__UART4_TX_DATA 0x1b0b1 ++ MX6SL_PAD_SD1_DAT7__UART4_CTS_B 0x1b0b1 ++ MX6SL_PAD_SD1_DAT6__UART4_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart4dte_1: uart4dtegrp-1 { ++ fsl,pins = < ++ MX6SL_PAD_SD1_DAT5__UART4_RX_DATA 0x1b0b1 ++ MX6SL_PAD_SD1_DAT4__UART4_TX_DATA 0x1b0b1 ++ MX6SL_PAD_SD1_DAT6__UART4_CTS_B 0x1b0b1 ++ MX6SL_PAD_SD1_DAT7__UART4_RTS_B 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 ++ >; ++ }; ++ ++ pinctrl_csi_0: csigrp-0 { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_GDRL__CSI_MCLK 0x110b0 ++ MX6SL_PAD_EPDC_GDCLK__CSI_PIXCLK 0x110b0 ++ MX6SL_PAD_EPDC_GDSP__CSI_VSYNC 0x110b0 ++ MX6SL_PAD_EPDC_GDOE__CSI_HSYNC 0x110b0 ++ MX6SL_PAD_EPDC_SDLE__CSI_DATA09 0x110b0 ++ MX6SL_PAD_EPDC_SDCLK__CSI_DATA08 0x110b0 ++ MX6SL_PAD_EPDC_D7__CSI_DATA07 0x110b0 ++ MX6SL_PAD_EPDC_D6__CSI_DATA06 0x110b0 ++ MX6SL_PAD_EPDC_D5__CSI_DATA05 0x110b0 ++ MX6SL_PAD_EPDC_D4__CSI_DATA04 0x110b0 ++ MX6SL_PAD_EPDC_D3__CSI_DATA03 0x110b0 ++ MX6SL_PAD_EPDC_D2__CSI_DATA02 0x110b0 ++ MX6SL_PAD_EPDC_D1__CSI_DATA01 0x110b0 ++ MX6SL_PAD_EPDC_D0__CSI_DATA00 0x110b0 ++ MX6SL_PAD_EPDC_SDSHR__GPIO1_IO26 0x80000000 ++ MX6SL_PAD_EPDC_SDOE__GPIO1_IO25 0x80000000 + >; + }; + }; + }; + ++&pxp { ++ status = "okay"; ++}; ++ ++&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"; ++}; ++ ++&lcdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_lcdif_dat ++ &pinctrl_lcdif_ctrl>; ++ lcd-supply = <®_lcd_3v3>; ++ display = <&display>; ++ status = "okay"; ++ ++ display: display { ++ bits-per-pixel = <16>; ++ bus-width = <24>; ++ ++ display-timings { ++ native-mode = <&timing0>; ++ timing0: timing0 { ++ clock-frequency = <33500000>; ++ hactive = <800>; ++ vactive = <480>; ++ hback-porch = <89>; ++ hfront-porch = <164>; ++ vback-porch = <23>; ++ vfront-porch = <10>; ++ hsync-len = <10>; ++ vsync-len = <10>; ++ hsync-active = <0>; ++ vsync-active = <0>; ++ de-active = <1>; ++ pixelclk-active = <0>; ++ }; ++ }; ++ }; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&pinctrl_pwm1>; ++ pinctrl-1 = <&pinctrl_pwm1_sleep>; ++ status = "okay"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif>; ++ assigned-clocks = <&clks IMX6SL_CLK_SPDIF0_SEL>, ++ <&clks IMX6SL_CLK_SPDIF0_PODF>; ++ assigned-clock-parents = <&clks IMX6SL_CLK_PLL3_PFD3>; ++ assigned-clock-rates = <0>, <227368421>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-slave"; ++ assigned-clocks = <&clks IMX6SL_CLK_SSI2_SEL>, ++ <&clks IMX6SL_CLK_SSI2>; ++ assigned-clock-rates = <0>, <24000000>; ++ 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,30 +913,36 @@ + + &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>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; + status = "okay"; + }; + + &usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; +- pinctrl-0 = <&pinctrl_usdhc2_1>; +- pinctrl-1 = <&pinctrl_usdhc2_1_100mhz>; +- pinctrl-2 = <&pinctrl_usdhc2_1_200mhz>; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ pinctrl-1 = <&pinctrl_usdhc2_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + cd-gpios = <&gpio5 0 0>; + wp-gpios = <&gpio4 29 0>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; + 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 = <&gpio3 22 0>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; + status = "okay"; + }; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-ldo.dts linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-ldo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-ldo.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,20 @@ ++ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sl-evk.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++}; ++ ++&gpc { ++ /* use ldo-enable, u-boot will check it and configure */ ++ fsl,ldo-bypass = <0>; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-pf200.dts linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-pf200.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-pf200.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-pf200.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,13 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sl-evk-ldo.dts" ++ ++&pmic { ++ compatible = "fsl,pfuze200"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-uart.dts linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-uart.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sl-evk-uart.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sl-evk-uart.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sl-evk.dts" ++ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart4_1>; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++ /* for DTE mode, add below change */ ++ /* fsl,dte-mode; */ ++ /* pinctrl-0 = <&pinctrl_uart4dte_1>; */ ++}; ++ ++&usdhc1 { ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,1251 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++/dts-v1/; ++ ++#include "imx6sx.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 SoloX 17x17 ARM2 Board"; ++ compatible = "fsl,imx6sx-17x17-arm2", "fsl,imx6sx"; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ }; ++ ++ clocks { ++ codec_osc: codec_osc { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <12000000>; ++ }; ++ }; ++ ++ max7322_reset: max7322-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <1>; ++ #reset-cells = <0>; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ 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_sdb_vmmc: sdb_vmmc{ ++ compatible = "regulator-fixed"; ++ regulator-name = "SD2_SPWR"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio2 11 GPIO_ACTIVE_LOW>; ++ }; ++ ++ reg_usb_otg1_vbus: usb_otg1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 9 0>; ++ enable-active-high; ++ }; ++ ++ reg_usb_otg2_vbus: usb_otg2_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg2_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 12 0>; ++ enable-active-high; ++ }; ++ ++ reg_vref_3v3: regulator@0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vref-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ }; ++ ++ memory { ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6sx-arm2-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6sx-arm2-sgtl5000"; ++ cpu-dai = <&ssi1>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "LINE_IN", "Line In Jack", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <1>; ++ mux-ext-port = <4>; ++ }; ++}; ++ ++&adc1 { ++ vref-supply = <®_vref_3v3>; ++ status = "okay"; ++}; ++ ++&adc2 { ++ vref-supply = <®_vref_3v3>; ++ status = "okay"; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux_2>; ++ status = "okay"; ++}; ++ ++&cpu0 { ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1c_reg>; ++}; ++ ++&ecspi4 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio7 4 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi4_1 &pinctrl_ecspi4_cs_1>; ++ status = "disabled"; /* pin conflict with USDHC3 */ ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p32"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&fec1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet1_1>; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy1>; ++ pinctrl-assert-gpios = <&max7322_1 0 GPIO_ACTIVE_HIGH>; ++ fsl,magic-packet; ++ status = "okay"; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ethphy0: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++ ++ ethphy1: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ }; ++ }; ++}; ++ ++&fec2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet2_1>; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy0>; ++ pinctrl-assert-gpios = <&max7322_2 0 GPIO_ACTIVE_HIGH>; ++ fsl,magic-packet; ++ status = "okay"; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1_1>; ++ trx-en-gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>; ++ trx-err-gpio = <&gpio4 24 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan2_1>; ++ trx-en-gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>; ++ trx-err-gpio = <&gpio4 30 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&gpc { ++ fsl,cpu_pupscr_sw2iso = <0x2>; ++ fsl,cpu_pupscr_sw = <0x1>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++ fsl,wdog-reset = <1>; /* watchdog select of reset source */ ++ fsl,ldo-bypass = <1>; /* use ldo-bypass, u-boot will check it and configure */ ++}; ++ ++&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; ++ }; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_1>; ++ status = "okay"; ++ ++ max7322_1: gpio@68 { ++ compatible = "maxim,max7322"; ++ reg = <0x68>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ resets = <&max7322_reset>; ++ }; ++ ++ max7322_2: gpio@69 { ++ compatible = "maxim,max7322"; ++ reg = <0x69>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ resets = <&max7322_reset>; ++ }; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&codec_osc>; ++ VDDA-supply = <&vgen4_reg>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++}; ++ ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_1>; ++ status = "okay"; ++}; ++ ++&i2c4 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c4_1>; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog_1>; ++ ++ hog { ++ pinctrl_hog_1: hoggrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x1f059 ++ MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x1f059 ++ MX6SX_PAD_QSPI1A_SS0_B__GPIO4_IO_22 0x80000000 ++ /* CAN1_2_EN */ ++ MX6SX_PAD_QSPI1B_DATA1__GPIO4_IO_25 0x17059 ++ /* CAN1_2_STBY_B */ ++ MX6SX_PAD_QSPI1B_DATA3__GPIO4_IO_27 0x17059 ++ /* CAN1_ERR_B */ ++ MX6SX_PAD_QSPI1B_DATA0__GPIO4_IO_24 0x17059 ++ /* CAN2_ERR_B */ ++ MX6SX_PAD_QSPI1B_SS0_B__GPIO4_IO_30 0x17059 ++ /* SD2_PWROFF */ ++ MX6SX_PAD_KEY_COL1__GPIO2_IO_11 0x17059 ++ /* WDOG_B reset */ ++ MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x10b0 ++ >; ++ }; ++ }; ++}; ++ ++&lcdif1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_lcdif_dat_0 ++ &pinctrl_lcdif_ctrl_0>; ++ 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>; ++ }; ++ }; ++ }; ++}; ++ ++&mlb { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_mlb_1>; ++ status = "disabled";/* pin conflict with usdhc2*/ ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3_0>; ++ status = "okay"; ++}; ++ ++&pxp { ++ status = "okay"; ++}; ++ ++&qspi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_qspi2_1>; ++ status = "okay"; ++ ddrsmp=<2>; ++ ++ flash0: n25q256a@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ reg = <0>; ++ }; ++ ++ flash1: n25q256a@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ reg = <1>; ++ }; ++}; ++ ++&sai2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sai2_1>; ++ status = "disabled"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif_1>; ++ status = "disabled"; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1_1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2_1>; ++ status = "okay"; ++}; ++ ++&usbh { ++ pinctrl-names = "idle", "active"; ++ pinctrl-0 = <&pinctrl_usbh_1>; ++ pinctrl-1 = <&pinctrl_usbh_2>; ++ osc-clkgate-delay = <0x3>; ++ pad-supply = <&vgen1_reg>; ++ status = "okay"; ++}; ++ ++&usbotg1 { ++ vbus-supply = <®_usb_otg1_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg1_1>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usbotg2 { ++ /* ++ * Pin conflict with others, need to switch R580 & R579 ++ * to B and disable pwm3 to enable it. ++ */ ++ vbus-supply = <®_usb_otg2_vbus>; ++ disable-over-current; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg2_1>; ++ status = "disabled"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2_1>; ++ non-removable; ++ /* need hw rework to enable signal voltage switch */ ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ 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>; ++ bus-width = <8>; ++ cd-gpios = <&gpio2 10 0>; ++ wp-gpios = <&gpio2 15 0>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ vmmc-supply = <®_sdb_vmmc>; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4_1>; ++ bus-width = <8>; ++ non-removable; ++ /* need hw rework to enable signal voltage switch */ ++ no-1-8-v; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ audmux { ++ pinctrl_audmux_1: audmuxgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__AUDMUX_AUD6_TXC 0x130B0 ++ MX6SX_PAD_CSI_DATA01__AUDMUX_AUD6_TXFS 0x130B0 ++ MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD 0x120B0 ++ MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x130B0 ++ MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130B0 ++ >; ++ }; ++ ++ pinctrl_audmux_2: audmuxgrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_COL__AUDMUX_AUD4_TXC 0x130b0 ++ MX6SX_PAD_ENET1_CRS__AUDMUX_AUD4_TXD 0x130b0 ++ MX6SX_PAD_ENET1_RX_CLK__AUDMUX_AUD4_TXFS 0x130b0 ++ MX6SX_PAD_ENET1_TX_CLK__AUDMUX_AUD4_RXD 0x130b0 ++ >; ++ }; ++ }; ++ ++ ecspi4 { ++ pinctrl_ecspi4_cs_1: ecspi4_cs_grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA2__GPIO7_IO_4 0x80000000 ++ >; ++ }; ++ ++ pinctrl_ecspi4_1: ecspi4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA3__ECSPI4_MISO 0x100b1 ++ MX6SX_PAD_SD3_CMD__ECSPI4_MOSI 0x100b1 ++ MX6SX_PAD_SD3_CLK__ECSPI4_SCLK 0x100b1 ++ >; ++ }; ++ }; ++ ++ canfd1 { ++ pinctrl_canfd1_1: canfd1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CANFD_TX1 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CANFD_RX1 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ canfd2 { ++ pinctrl_canfd2_1: canfd2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CANFD_RX2 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CANFD_TX2 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ csi { ++ pinctrl_csi_0: csigrp-0 { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA07__CSI1_MCLK 0x110b0 ++ MX6SX_PAD_LCD1_DATA06__CSI1_PIXCLK 0x110b0 ++ MX6SX_PAD_LCD1_DATA04__CSI1_VSYNC 0x110b0 ++ MX6SX_PAD_LCD1_DATA05__CSI1_HSYNC 0x110b0 ++ MX6SX_PAD_LCD1_DATA17__CSI1_DATA_0 0x110b0 ++ MX6SX_PAD_LCD1_DATA16__CSI1_DATA_1 0x110b0 ++ MX6SX_PAD_LCD1_DATA15__CSI1_DATA_2 0x110b0 ++ MX6SX_PAD_LCD1_DATA14__CSI1_DATA_3 0x110b0 ++ MX6SX_PAD_LCD1_DATA13__CSI1_DATA_4 0x110b0 ++ MX6SX_PAD_LCD1_DATA12__CSI1_DATA_5 0x110b0 ++ MX6SX_PAD_LCD1_DATA11__CSI1_DATA_6 0x110b0 ++ MX6SX_PAD_LCD1_DATA10__CSI1_DATA_7 0x110b0 ++ MX6SX_PAD_LCD1_DATA09__CSI1_DATA_8 0x110b0 ++ MX6SX_PAD_LCD1_DATA08__CSI1_DATA_9 0x110b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x80000000 ++ MX6SX_PAD_LCD1_VSYNC__GPIO3_IO_28 0x80000000 ++ >; ++ }; ++ ++ pinctrl_csi_1: csigrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_MCLK__CSI1_MCLK 0x110b0 ++ MX6SX_PAD_CSI_PIXCLK__CSI1_PIXCLK 0x110b0 ++ MX6SX_PAD_CSI_VSYNC__CSI1_VSYNC 0x110b0 ++ MX6SX_PAD_CSI_HSYNC__CSI1_HSYNC 0x110b0 ++ MX6SX_PAD_CSI_DATA00__CSI1_DATA_2 0x110b0 ++ MX6SX_PAD_CSI_DATA01__CSI1_DATA_3 0x110b0 ++ MX6SX_PAD_CSI_DATA02__CSI1_DATA_4 0x110b0 ++ MX6SX_PAD_CSI_DATA03__CSI1_DATA_5 0x110b0 ++ MX6SX_PAD_CSI_DATA04__CSI1_DATA_6 0x110b0 ++ MX6SX_PAD_CSI_DATA05__CSI1_DATA_7 0x110b0 ++ MX6SX_PAD_CSI_DATA06__CSI1_DATA_8 0x110b0 ++ MX6SX_PAD_CSI_DATA07__CSI1_DATA_9 0x110b0 ++ ++ MX6SX_PAD_LCD1_ENABLE__GPIO3_IO_25 0x80000000 ++ MX6SX_PAD_LCD1_HSYNC__GPIO3_IO_26 0x80000000 ++ >; ++ }; ++ }; ++ ++ enet1 { ++ pinctrl_enet1_1: enet1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 ++ MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 ++ MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 ++ >; ++ }; ++ ++ pinctrl_enet1_clkout_1: enet1_clkoutgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x91 ++ >; ++ }; ++ }; ++ ++ enet2 { ++ pinctrl_enet2_1: enet2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x3081 ++ >; ++ }; ++ }; ++ ++ esai { ++ pinctrl_esai_1: esaigrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_MCLK__ESAI_TX_HF_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA00__ESAI_TX_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA01__ESAI_TX_FS 0x1b030 ++ MX6SX_PAD_CSI_HSYNC__ESAI_TX0 0x1b030 ++ MX6SX_PAD_CSI_DATA04__ESAI_TX1 0x1b030 ++ MX6SX_PAD_CSI_DATA06__ESAI_TX2_RX3 0x1b030 ++ MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2 0x1b030 ++ MX6SX_PAD_CSI_DATA02__ESAI_RX_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA03__ESAI_RX_FS 0x1b030 ++ MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0 0x1b030 ++ MX6SX_PAD_CSI_DATA05__ESAI_TX4_RX1 0x1b030 ++ >; ++ }; ++ }; ++ ++ flexcan1 { ++ pinctrl_flexcan1_1: flexcan1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ flexcan2 { ++ pinctrl_flexcan2_1: flexcan2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ gpmi-nand { ++ pinctrl_gpmi_nand_1: gpmi-nand-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 ++ MX6SX_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 ++ MX6SX_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 ++ MX6SX_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 ++ MX6SX_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 ++ MX6SX_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 ++ MX6SX_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 ++ MX6SX_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 ++ MX6SX_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 ++ MX6SX_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 ++ MX6SX_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 ++ MX6SX_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 ++ MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 ++ MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 ++ MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 ++ MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 ++ >; ++ }; ++ }; ++ ++ i2c1 { ++ pinctrl_i2c1_1: i2c1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c1_2: i2c1grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA01__I2C1_SDA 0x4001b8b1 ++ MX6SX_PAD_CSI_DATA00__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c2 { ++ pinctrl_i2c2_1: i2c2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c3 { ++ pinctrl_i2c3_1: i2c3grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_TX_CLK__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3_2: i2c3grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c4 { ++ pinctrl_i2c4_1: i2c4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x4001b8b1 ++ MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x4001b8b1 ++ >; ++ }; ++ pinctrl_i2c4_2: i2c4grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA1__I2C4_SDA 0x4001b8b1 ++ MX6SX_PAD_SD3_DATA0__I2C4_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ lcdif1 { ++ pinctrl_lcdif_dat_0: lcdifdatgrp-0 { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_lcdif_ctrl_0: lcdifctrlgrp-0 { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x4001b0b0 ++ MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x4001b0b0 ++ MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x4001b0b0 ++ >; ++ }; ++ }; ++ ++ mlb { ++ pinctrl_mlb_1: mlbgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD2_DATA3__MLB_DATA 0x31 ++ MX6SX_PAD_SD2_CLK__MLB_SIG 0x31 ++ MX6SX_PAD_SD2_CMD__MLB_CLK 0x31 ++ >; ++ }; ++ }; ++ ++ pwm3 { ++ pinctrl_pwm3_0: pwm3grp-0 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO12__PWM3_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_pwm3_1: pwm3grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0 ++ >; ++ }; ++ }; ++ ++ pwm4 { ++ pinctrl_pwm4_0: pwm4grp-0 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x110b0 ++ >; ++ }; ++ }; ++ ++ qspi2 { ++ pinctrl_qspi2_1: qspi2grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0 0x70a1 ++ MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1 0x70a1 ++ MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2 0x70a1 ++ MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3 0x70a1 ++ MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK 0x70a1 ++ MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B 0x70a1 ++ MX6SX_PAD_NAND_DATA01__QSPI2_B_DATA_0 0x70a1 ++ MX6SX_PAD_NAND_DATA00__QSPI2_B_DATA_1 0x70a1 ++ MX6SX_PAD_NAND_WE_B__QSPI2_B_DATA_2 0x70a1 ++ MX6SX_PAD_NAND_RE_B__QSPI2_B_DATA_3 0x70a1 ++ MX6SX_PAD_NAND_DATA02__QSPI2_B_SCLK 0x70a1 ++ MX6SX_PAD_NAND_DATA03__QSPI2_B_SS0_B 0x70a1 ++ >; ++ }; ++ }; ++ ++ sai1 { ++ pinctrl_sai1_1: sai1grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x1b030 ++ MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x1b030 ++ MX6SX_PAD_CSI_DATA02__SAI1_RX_BCLK 0x1b030 ++ MX6SX_PAD_CSI_DATA03__SAI1_RX_SYNC 0x1b030 ++ MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x1b030 ++ MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x1b030 ++ >; ++ }; ++ ++ pinctrl_sai1_2: sai1grp_2 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x130B0 ++ MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x130B0 ++ MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x120B0 ++ MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x130B0 ++ MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130B0 ++ >; ++ }; ++ }; ++ ++ sai2 { ++ pinctrl_sai2_1: sai2grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_COL0__SAI2_TX_BCLK 0x1b030 ++ MX6SX_PAD_KEY_COL1__SAI2_TX_SYNC 0x1b030 ++ MX6SX_PAD_KEY_ROW0__SAI2_TX_DATA_0 0x1b030 ++ MX6SX_PAD_KEY_ROW1__SAI2_RX_DATA_0 0x1b030 ++ >; ++ }; ++ }; ++ ++ ++ spdif { ++ pinctrl_spdif_1: spdifgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_RX_CLK__SPDIF_OUT 0x1b0b0 ++ MX6SX_PAD_ENET2_COL__SPDIF_IN 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_spdif_2: spdifgrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_DATA4__SPDIF_OUT 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1_1: uart1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO05__UART1_RX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1_2: uart1grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_COL__UART1_RX 0x1b0b1 ++ MX6SX_PAD_ENET2_CRS__UART1_TX 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ uart2 { ++ pinctrl_uart2_1: uart2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO07__UART2_RX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO06__UART2_TX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2_2: uart2grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA0__UART2_RX 0x1b0b1 ++ MX6SX_PAD_SD1_DATA1__UART2_TX 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ uart5 { ++ pinctrl_uart5_1: uart5grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5dte_1: uart5dtegrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ usbh { ++ pinctrl_usbh_1: usbhgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_USB_H_STROBE__USB_H_STROBE 0x40013030 ++ MX6SX_PAD_USB_H_DATA__USB_H_DATA 0x40013030 ++ >; ++ }; ++ ++ pinctrl_usbh_2: usbhgrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_USB_H_STROBE__USB_H_STROBE 0x40017030 ++ >; ++ }; ++ }; ++ ++ usbotg1 { ++ pinctrl_usbotg1_1: usbotg1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_2: usbotg1grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_COL__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_3: usbotg1grp-3 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_DATA1__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ }; ++ ++ usbotg2 { ++ pinctrl_usbotg2_1: usbotg2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO13__ANATOP_OTG2_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg2_2: usbotg2grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_CRS__ANATOP_OTG2_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg2_3: usbotg2grp-3 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_SCLK__ANATOP_OTG2_ID 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc1 { ++ pinctrl_usdhc1_1: usdhc1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_CMD__USDHC1_CMD 0x17059 ++ MX6SX_PAD_SD1_CLK__USDHC1_CLK 0x10059 ++ MX6SX_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 ++ MX6SX_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 ++ MX6SX_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 ++ MX6SX_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc2 { ++ pinctrl_usdhc2_1: usdhc2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 ++ MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 ++ MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x17059 ++ MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x17059 ++ MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x17059 ++ MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc3 { ++ pinctrl_usdhc3_1: usdhc3grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10059 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17059 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17059 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17059 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17059 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17059 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17059 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17059 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 ++ >; ++ }; ++ ++ }; ++ ++ usdhc4 { ++ pinctrl_usdhc4_1: usdhc4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x17059 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x17059 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x17059 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc4_1_100mhz: usdhc4grp-1-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170b9 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100b9 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170b9 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170b9 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170b9 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170b9 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170b9 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170b9 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170b9 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc4_1_200mhz: usdhc4grp-1-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170f9 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100f9 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170f9 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170f9 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170f9 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170f9 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170f9 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170f9 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170f9 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170f9 ++ >; ++ }; ++ ++ pinctrl_usdhc4_2: usdhc4grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ >; ++ }; ++ ++ }; ++ ++ weim { ++ pinctrl_weim_cs0_1: weim_cs0grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_ALE__WEIM_CS0_B 0xb0b1 ++ >; ++ }; ++ ++ pinctrl_weim_nor_1: weim_norgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_CE1_B__WEIM_OE 0xb0b1 ++ MX6SX_PAD_NAND_RE_B__WEIM_RW 0xb0b1 ++ MX6SX_PAD_NAND_WE_B__WEIM_WAIT 0xb060 ++ /* data */ ++ MX6SX_PAD_QSPI1A_SCLK__WEIM_DATA_0 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS0_B__WEIM_DATA_1 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__WEIM_DATA_2 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA3__WEIM_DATA_3 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA2__WEIM_DATA_4 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA1__WEIM_DATA_5 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA0__WEIM_DATA_6 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__WEIM_DATA_7 0x1b0b0 ++ MX6SX_PAD_QSPI1B_SCLK__WEIM_DATA_8 0x1b0b0 ++ MX6SX_PAD_QSPI1B_SS0_B__WEIM_DATA_9 0x1b0b0 ++ MX6SX_PAD_QSPI1B_SS1_B__WEIM_DATA_10 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA3__WEIM_DATA_11 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA2__WEIM_DATA_12 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA1__WEIM_DATA_13 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA0__WEIM_DATA_14 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DQS__WEIM_DATA_15 0x1b0b0 ++ /* address */ ++ MX6SX_PAD_NAND_DATA00__WEIM_AD_0 0xb0b1 ++ MX6SX_PAD_NAND_DATA01__WEIM_AD_1 0xb0b1 ++ MX6SX_PAD_NAND_DATA02__WEIM_AD_2 0xb0b1 ++ MX6SX_PAD_NAND_DATA03__WEIM_AD_3 0xb0b1 ++ MX6SX_PAD_NAND_DATA04__WEIM_AD_4 0xb0b1 ++ MX6SX_PAD_NAND_DATA05__WEIM_AD_5 0xb0b1 ++ MX6SX_PAD_NAND_DATA06__WEIM_AD_6 0xb0b1 ++ MX6SX_PAD_NAND_DATA07__WEIM_AD_7 0xb0b1 ++ MX6SX_PAD_LCD1_DATA08__WEIM_AD_8 0xb0b1 ++ MX6SX_PAD_LCD1_DATA09__WEIM_AD_9 0xb0b1 ++ MX6SX_PAD_LCD1_DATA10__WEIM_AD_10 0xb0b1 ++ MX6SX_PAD_LCD1_DATA11__WEIM_AD_11 0xb0b1 ++ MX6SX_PAD_LCD1_DATA12__WEIM_AD_12 0xb0b1 ++ MX6SX_PAD_LCD1_DATA13__WEIM_AD_13 0xb0b1 ++ MX6SX_PAD_LCD1_DATA14__WEIM_AD_14 0xb0b1 ++ MX6SX_PAD_LCD1_DATA15__WEIM_AD_15 0xb0b1 ++ MX6SX_PAD_LCD1_DATA16__WEIM_ADDR_16 0xb0b1 ++ MX6SX_PAD_LCD1_DATA17__WEIM_ADDR_17 0xb0b1 ++ MX6SX_PAD_LCD1_DATA18__WEIM_ADDR_18 0xb0b1 ++ MX6SX_PAD_LCD1_DATA19__WEIM_ADDR_19 0xb0b1 ++ MX6SX_PAD_LCD1_DATA20__WEIM_ADDR_20 0xb0b1 ++ MX6SX_PAD_LCD1_DATA21__WEIM_ADDR_21 0xb0b1 ++ MX6SX_PAD_LCD1_DATA22__WEIM_ADDR_22 0xb0b1 ++ MX6SX_PAD_LCD1_DATA03__WEIM_ADDR_24 0xb0b1 ++ MX6SX_PAD_LCD1_DATA04__WEIM_ADDR_25 0xb0b1 ++ MX6SX_PAD_LCD1_DATA05__WEIM_ADDR_26 0xb0b1 ++ >; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-ecspi.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-ecspi.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-ecspi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-ecspi.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,459 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++/dts-v1/; ++ ++#include ++#include "imx6sx.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 SoloX SDB Board"; ++ compatible = "fsl,imx6sx-sdb", "fsl,imx6sx"; ++ ++ chosen { ++ stdout-path = &uart1; ++ }; ++ ++ memory { ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ backlight1 { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ fb-names = "mxs-lcdif0"; ++ }; ++ ++ backlight2 { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ fb-names = "mxs-lcdif1"; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ volume-up { ++ label = "Volume Up"; ++ gpios = <&gpio1 18 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ volume-down { ++ label = "Volume Down"; ++ gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ hannstar_cabc { ++ compatible = "hannstar,cabc"; ++ ++ lvds0 { ++ gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_lcd_3v3: lcd-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "lcd-3v3"; ++ gpio = <&gpio3 27 0>; ++ enable-active-high; ++ status = "disabled"; ++ }; ++ ++ vcc_sd3: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_vcc_sd3>; ++ regulator-name = "VCC_SD3"; ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ }; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ status = "okay"; /* pin conflict with qspi*/ ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart5 { /* for bluetooth */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++ /* for DTE mode, add below change */ ++ /* fsl,dte-mode;*/ ++ /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ non-removable; ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ pinctrl-1 = <&pinctrl_usdhc3_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_200mhz>; ++ bus-width = <8>; ++ cd-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ vmmc-supply = <&vcc_sd3>; ++ status = "disabled"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ cd-gpios = <&gpio6 21 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&ecspi4 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio7 4 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi4_1 &pinctrl_ecspi4_cs_1>; ++ status = "okay"; /* pin conflict with USDHC3 */ ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p32"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6x-sdb { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA0__GPIO6_IO_2 0x17059 ++ MX6SX_PAD_SD1_DATA3__GPIO6_IO_5 0xb000 ++ >; ++ }; ++ ++ pinctrl_canfd1: canfd1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CANFD_TX1 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CANFD_RX1 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_canfd2: canfd2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CANFD_RX2 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CANFD_TX2 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_egalax_int: egalax_intgrp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_DATA3__GPIO4_IO_19 0x80000000 ++ >; ++ }; ++ ++ pinctrl_enet1: enet1grp { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 ++ MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 ++ MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b1 ++ MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 ++ >; ++ }; ++ ++ pinctrl_flexcan1: flexcan1grp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_flexcan2: flexcan2grp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_gpio_keys: gpio_keysgrp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA04__GPIO1_IO_18 0x17059 ++ MX6SX_PAD_CSI_DATA05__GPIO1_IO_19 0x17059 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c4: i2c4grp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x4001b8b1 ++ MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_lcdif_dat: lcdifdatgrp { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_lcdif_ctrl: lcdifctrlgrp { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x4001b0b0 ++ MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x4001b0b0 ++ MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_pwm3: pwm3grp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand_1: gpmi-nand-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 ++ MX6SX_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 ++ MX6SX_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 ++ MX6SX_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 ++ MX6SX_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 ++ MX6SX_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 ++ MX6SX_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 ++ MX6SX_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 ++ MX6SX_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 ++ MX6SX_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 ++ MX6SX_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 ++ MX6SX_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 ++ MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 ++ MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 ++ MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 ++ MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 ++ >; ++ }; ++ ++ pinctrl_vcc_sd3: vccsd3grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_COL1__GPIO2_IO_11 0x17059 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO05__UART1_RX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5dte_1: uart5dtegrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ fsl,pins = < ++ MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 ++ MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 ++ MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x17059 ++ MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x17059 ++ MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x17059 ++ MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10059 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17059 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17059 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17059 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17059 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17059 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17059 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17059 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17059 ++ MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x17059 /* CD */ ++ MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x17059 /* WP */ ++ >; ++ }; ++ ++ pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x17059 /* CD */ ++ MX6SX_PAD_SD4_DATA6__GPIO6_IO_20 0x17059 /* WP */ ++ >; ++ }; ++ ++ pinctrl_ecspi4_cs_1: ecspi4_cs_grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA2__GPIO7_IO_4 0x80000000 ++ >; ++ }; ++ ++ pinctrl_ecspi4_1: ecspi4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA3__ECSPI4_MISO 0x100b1 ++ MX6SX_PAD_SD3_CMD__ECSPI4_MOSI 0x100b1 ++ MX6SX_PAD_SD3_CLK__ECSPI4_SCLK 0x100b1 ++ >; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-gpmi-weim.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-gpmi-weim.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-gpmi-weim.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-gpmi-weim.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,429 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++/dts-v1/; ++ ++#include ++#include "imx6sx.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 SoloX SDB Board"; ++ compatible = "fsl,imx6sx-sdb", "fsl,imx6sx"; ++ ++ chosen { ++ stdout-path = &uart1; ++ }; ++ ++ memory { ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ backlight1 { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ fb-names = "mxs-lcdif0"; ++ }; ++ ++ backlight2 { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ fb-names = "mxs-lcdif1"; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ volume-up { ++ label = "Volume Up"; ++ gpios = <&gpio1 18 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ volume-down { ++ label = "Volume Down"; ++ gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ hannstar_cabc { ++ compatible = "hannstar,cabc"; ++ ++ lvds0 { ++ gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_lcd_3v3: lcd-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "lcd-3v3"; ++ gpio = <&gpio3 27 0>; ++ enable-active-high; ++ status = "disabled"; ++ }; ++ ++ vcc_sd3: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_vcc_sd3>; ++ regulator-name = "VCC_SD3"; ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ }; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ status = "okay"; /* pin conflict with qspi*/ ++ nand-on-flash-bbt; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart5 { /* for bluetooth */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++ /* for DTE mode, add below change */ ++ /* fsl,dte-mode;*/ ++ /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ non-removable; ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ pinctrl-1 = <&pinctrl_usdhc3_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_200mhz>; ++ bus-width = <8>; ++ cd-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ vmmc-supply = <&vcc_sd3>; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ cd-gpios = <&gpio6 21 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6x-sdb { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA0__GPIO6_IO_2 0x17059 ++ MX6SX_PAD_SD1_DATA3__GPIO6_IO_5 0xb000 ++ >; ++ }; ++ ++ pinctrl_canfd1: canfd1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CANFD_TX1 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CANFD_RX1 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_canfd2: canfd2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CANFD_RX2 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CANFD_TX2 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_egalax_int: egalax_intgrp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_DATA3__GPIO4_IO_19 0x80000000 ++ >; ++ }; ++ ++ pinctrl_enet1: enet1grp { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 ++ MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 ++ MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b1 ++ MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 ++ >; ++ }; ++ ++ pinctrl_flexcan1: flexcan1grp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_flexcan2: flexcan2grp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_gpio_keys: gpio_keysgrp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA04__GPIO1_IO_18 0x17059 ++ MX6SX_PAD_CSI_DATA05__GPIO1_IO_19 0x17059 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c4: i2c4grp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x4001b8b1 ++ MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_lcdif_dat: lcdifdatgrp { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_lcdif_ctrl: lcdifctrlgrp { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x4001b0b0 ++ MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x4001b0b0 ++ MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_pwm3: pwm3grp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand_1: gpmi-nand-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 ++ MX6SX_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 ++ MX6SX_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 ++ MX6SX_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 ++ MX6SX_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 ++ MX6SX_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 ++ MX6SX_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 ++ MX6SX_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 ++ MX6SX_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 ++ MX6SX_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 ++ MX6SX_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 ++ MX6SX_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 ++ MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 ++ MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 ++ MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 ++ MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 ++ >; ++ }; ++ ++ pinctrl_vcc_sd3: vccsd3grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_COL1__GPIO2_IO_11 0x17059 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO05__UART1_RX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5dte_1: uart5dtegrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ fsl,pins = < ++ MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 ++ MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 ++ MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x17059 ++ MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x17059 ++ MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x17059 ++ MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10059 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17059 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17059 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17059 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17059 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17059 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17059 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17059 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17059 ++ MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x17059 /* CD */ ++ MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x17059 /* WP */ ++ >; ++ }; ++ ++ pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x17059 /* CD */ ++ MX6SX_PAD_SD4_DATA6__GPIO6_IO_20 0x17059 /* WP */ ++ >; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-ldo.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-ldo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-ldo.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2015 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 "imx6sx-17x17-arm2.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++}; ++ ++&gpc { ++ fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-mlb.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-mlb.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-mlb.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-mlb.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-17x17-arm2.dts" ++ ++&mlb { ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ /* pin conflict with mlb */ ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-sai.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-sai.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-sai.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-sai.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-17x17-arm2.dts" ++ ++/ { ++ sound { ++ cpu-dai = <&sai2>; ++ }; ++}; ++ ++&audmux { ++ /* Pin conflict with SAI */ ++ status = "disabled"; ++}; ++ ++&pinctrl_hog_1 { ++ /* Pin conflict with SAI */ ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_SS0_B__GPIO4_IO_22 0x80000000 ++ /* CAN1_2_EN */ ++ MX6SX_PAD_QSPI1B_DATA1__GPIO4_IO_25 0x17059 ++ /* CAN1_2_STBY_B */ ++ MX6SX_PAD_QSPI1B_DATA3__GPIO4_IO_27 0x17059 ++ /* CAN1_ERR_B */ ++ MX6SX_PAD_QSPI1B_DATA0__GPIO4_IO_24 0x17059 ++ /* CAN2_ERR_B */ ++ MX6SX_PAD_QSPI1B_SS0_B__GPIO4_IO_30 0x17059 ++ >; ++}; ++ ++®_sdb_vmmc{ ++ /* Pin conflict with SAI */ ++ gpio = <0 0 0>; ++}; ++ ++&sai2 { ++ status = "okay"; ++}; ++ ++&sdma { ++ gpr = <&gpr>; ++ /* SDMA event remap for SAI2 */ ++ fsl,sdma-event-remap = <0 17 1>, <0 18 1>; ++}; ++ ++&usdhc2 { ++ /* Pin conflict with SAI */ ++ status = "disabled"; ++}; ++ ++&usdhc3 { ++ /* Pin conflict with SAI */ ++ status = "disabled"; ++}; ++ ++&usdhc4 { ++ /* Pin conflict with SAI */ ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-spdif.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-spdif.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-spdif.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-spdif.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-17x17-arm2.dts" ++ ++/ { ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx-sabreauto-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-in; ++ spdif-out; ++ }; ++}; ++ ++&audmux { ++ /* pin conflict with spdif */ ++ status = "disabled"; ++}; ++ ++&spdif { ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-ssi.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-ssi.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-17x17-arm2-ssi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-17x17-arm2-ssi.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-17x17-arm2.dts" ++ ++&pinctrl_hog_1 { ++ /* Pin conflict with SSI */ ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_SS0_B__GPIO4_IO_22 0x80000000 ++ /* CAN1_2_EN */ ++ MX6SX_PAD_QSPI1B_DATA1__GPIO4_IO_25 0x17059 ++ /* CAN1_2_STBY_B */ ++ MX6SX_PAD_QSPI1B_DATA3__GPIO4_IO_27 0x17059 ++ /* CAN1_ERR_B */ ++ MX6SX_PAD_QSPI1B_DATA0__GPIO4_IO_24 0x17059 ++ /* CAN2_ERR_B */ ++ MX6SX_PAD_QSPI1B_SS0_B__GPIO4_IO_30 0x17059 ++ >; ++}; ++ ++®_sdb_vmmc{ ++ /* Pin conflict with SSI */ ++ gpio = <0 0 0>; ++}; ++ ++&usdhc2 { ++ /* Pin conflict with SSI */ ++ status = "disabled"; ++}; ++ ++&usdhc3 { ++ /* Pin conflict with SSI */ ++ status = "disabled"; ++}; ++ ++&usdhc4 { ++ /* Pin conflict with SSI */ ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-csi.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-csi.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-csi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-csi.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-19x19-arm2.dts" ++ ++&esai { ++ /* pin conflict with sai */ ++ status = "disabled"; ++}; ++ ++&sai1 { ++ status = "disabled"; ++}; ++ ++&i2c2 { ++ ov5640: ov5640@3c { ++ status = "okay"; ++ }; ++}; ++ +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,1260 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++/dts-v1/; ++ ++#include "imx6sx.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 SoloX 19x19 ARM2 Board"; ++ compatible = "fsl,imx6sx-19x19-arm2", "fsl,imx6sx"; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ }; ++ ++ hannstar_cabc { ++ compatible = "hannstar,cabc"; ++ ++ lvds0 { ++ gpios = <&gpio2 16 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ clocks { ++ codec_osc: codec_osc { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <12000000>; ++ }; ++ }; ++ ++ max7322_reset: max7322-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio6 18 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <1>; ++ #reset-cells = <0>; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ 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_usb_otg1_vbus: usb_otg1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 9 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ memory { ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ sound-cs42888 { ++ compatible = "fsl,imx6-sabreauto-cs42888", ++ "fsl,imx-audio-cs42888"; ++ model = "imx-cs42888"; ++ esai-controller = <&esai>; ++ asrc-controller = <&asrc>; ++ audio-codec = <&cs42888>; ++ }; ++}; ++ ++&esai { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_esai_1>; ++ status = "okay"; ++}; ++ ++&csi1 { ++ status = "okay"; ++ ++ port { ++ csi1_ep: endpoint { ++ remote-endpoint = <&ov5640_ep>; ++ }; ++ }; ++}; ++ ++&csi2 { ++ status = "okay"; ++ port { ++ csi2_ep: endpoint { ++ remote-endpoint = <&vadc_ep>; ++ }; ++ }; ++}; ++ ++&cpu0 { ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1c_reg>; ++}; ++ ++&fec1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet1_1>; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy1>; ++ pinctrl-assert-gpios = <&max7322_1 0 GPIO_ACTIVE_HIGH>; ++ fsl,magic-packet; ++ status = "okay"; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ethphy0: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++ ++ ethphy1: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ }; ++ }; ++}; ++ ++&fec2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet2_1>; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy0>; ++ pinctrl-assert-gpios = <&max7322_2 0 GPIO_ACTIVE_HIGH>; ++ fsl,magic-packet; ++ status = "okay"; ++}; ++ ++&gpc { ++ fsl,cpu_pupscr_sw2iso = <0x2>; ++ fsl,cpu_pupscr_sw = <0x1>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++ fsl,wdog-reset = <1>; /* watchdog select of reset source */ ++ fsl,ldo-bypass = <1>; /* use ldo-bypass, u-boot will check it and configure */ ++}; ++ ++&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; ++ }; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_1>; ++ status = "okay"; ++ ++ max7322_1: gpio@68 { ++ compatible = "maxim,max7322"; ++ reg = <0x68>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ resets = <&max7322_reset>; ++ }; ++ ++ max7322_2: gpio@69 { ++ compatible = "maxim,max7322"; ++ reg = <0x69>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ resets = <&max7322_reset>; ++ }; ++ ++ ov5640: ov5640@3c { ++ compatible = "ovti,ov5640"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_csi_1>; ++ clocks = <&clks IMX6SX_CLK_CSI>; ++ clock-names = "csi_mclk"; ++ AVDD-supply = <&vgen3_reg>; /* 2.8v */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio3 26 1>; ++ rst-gpios = <&gpio3 25 0>; ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ status = "disabled"; ++ port { ++ ov5640_ep: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_1>; ++ status = "okay"; ++}; ++ ++&i2c4 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c4_2>; ++ status = "okay"; ++ ++ sgtl5000: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&codec_osc>; ++ VDDA-supply = <&vgen4_reg>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++ ++ cs42888: cs42888@048 { ++ compatible = "cirrus,cs42888"; ++ reg = <0x048>; ++ clocks = <&clks IMX6SX_CLK_ESAI_EXTAL>; ++ clock-names = "mclk"; ++ VA-supply = <®_3p3v>; ++ VD-supply = <®_3p3v>; ++ VLS-supply = <®_3p3v>; ++ VLC-supply = <®_3p3v>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog_1>; ++ ++ hog { ++ pinctrl_hog_1: hoggrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_DATA4__GPIO6_IO_18 0x1b0b0 ++ MX6SX_PAD_KEY_ROW1__GPIO2_IO_16 0x1b0b0 ++ MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x10b0 ++ >; ++ }; ++ }; ++}; ++ ++&lcdif1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_lcdif_dat_0 ++ &pinctrl_lcdif_ctrl_0>; ++ display = <&display0>; ++ status = "disabled"; ++ ++ display0: 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>; ++ }; ++ }; ++ }; ++}; ++ ++&lcdif2 { ++ display = <&display1>; ++ disp-dev = "ldb"; ++ status = "okay"; ++ ++ display1: display { ++ bits-per-pixel = <16>; ++ bus-width = <18>; ++ }; ++}; ++ ++&ldb { ++ status = "okay"; ++ ++ lvds-channel@0 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ crtc = "lcdif2"; ++ status = "okay"; ++ ++ display-timings { ++ native-mode = <&timing1>; ++ timing1: 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>; ++ }; ++ }; ++ }; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-lcdif1"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds"; ++ status = "okay"; ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3_0>; ++ status = "okay"; ++}; ++ ++&pxp { ++ status = "okay"; ++}; ++ ++&sai1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sai1_1>; ++ status = "disabled"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1_1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2_1>; ++ status = "okay"; ++}; ++ ++&qspi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_qspi2_1>; ++ status = "okay"; ++ ddrsmp=<2>; ++ ++ flash0: n25q256a@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ reg = <0>; ++ }; ++ ++ flash1: n25q256a@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ reg = <1>; ++ }; ++}; ++ ++&usbh { ++ pinctrl-names = "idle", "active"; ++ pinctrl-0 = <&pinctrl_usbh_1>; ++ pinctrl-1 = <&pinctrl_usbh_2>; ++ osc-clkgate-delay = <0x3>; ++ pad-supply = <&vgen1_reg>; ++ status = "okay"; ++}; ++ ++&usbotg1 { ++ vbus-supply = <®_usb_otg1_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg1_1>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usdhc1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc1_1>; ++ bus-width = <4>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ no-1-8-v; ++ status = "okay"; ++}; ++ ++&weim { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_weim_nor_1 &pinctrl_weim_cs0_1>; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0x50000000 0x08000000>; ++ status = "disabled"; /* pin conflict with qspi, nand and lcd1 */ ++ ++ nor@0,0 { ++ compatible = "cfi-flash"; ++ reg = <0 0 0x02000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ bank-width = <2>; ++ fsl,weim-cs-timing = <0x00610081 0x00000001 0x1c022000 ++ 0x0000c000 0x1404a38e 0x00000000>; ++ }; ++}; ++ ++&vadc { ++ vadc_in = <0>; ++ csi_id = <1>; ++ status = "okay"; ++ port { ++ vadc_ep: endpoint { ++ remote-endpoint = <&csi2_ep>; ++ }; ++ }; ++}; ++ ++&iomuxc { ++ audmux { ++ pinctrl_audmux_1: audmuxgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__AUDMUX_AUD6_TXC 0x130B0 ++ MX6SX_PAD_CSI_DATA01__AUDMUX_AUD6_TXFS 0x130B0 ++ MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD 0x120B0 ++ MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x130B0 ++ MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130B0 ++ >; ++ }; ++ ++ pinctrl_audmux_2: audmuxgrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_COL__AUDMUX_AUD4_TXC 0x130b0 ++ MX6SX_PAD_ENET1_CRS__AUDMUX_AUD4_TXD 0x130b0 ++ MX6SX_PAD_ENET1_RX_CLK__AUDMUX_AUD4_TXFS 0x130b0 ++ MX6SX_PAD_ENET1_TX_CLK__AUDMUX_AUD4_RXD 0x130b0 ++ >; ++ }; ++ }; ++ ++ ecspi4 { ++ pinctrl_ecspi4_cs_1: ecspi4_cs_grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA2__GPIO7_IO_4 0x80000000 ++ >; ++ }; ++ ++ pinctrl_ecspi4_1: ecspi4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA3__ECSPI4_MISO 0x100b1 ++ MX6SX_PAD_SD3_CMD__ECSPI4_MOSI 0x100b1 ++ MX6SX_PAD_SD3_CLK__ECSPI4_SCLK 0x100b1 ++ >; ++ }; ++ }; ++ ++ canfd1 { ++ pinctrl_canfd1_1: canfd1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CANFD_TX1 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CANFD_RX1 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ canfd2 { ++ pinctrl_canfd2_1: canfd2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CANFD_RX2 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CANFD_TX2 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ csi { ++ pinctrl_csi_0: csigrp-0 { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA07__CSI1_MCLK 0x110b0 ++ MX6SX_PAD_LCD1_DATA06__CSI1_PIXCLK 0x110b0 ++ MX6SX_PAD_LCD1_DATA04__CSI1_VSYNC 0x110b0 ++ MX6SX_PAD_LCD1_DATA05__CSI1_HSYNC 0x110b0 ++ MX6SX_PAD_LCD1_DATA17__CSI1_DATA_0 0x110b0 ++ MX6SX_PAD_LCD1_DATA16__CSI1_DATA_1 0x110b0 ++ MX6SX_PAD_LCD1_DATA15__CSI1_DATA_2 0x110b0 ++ MX6SX_PAD_LCD1_DATA14__CSI1_DATA_3 0x110b0 ++ MX6SX_PAD_LCD1_DATA13__CSI1_DATA_4 0x110b0 ++ MX6SX_PAD_LCD1_DATA12__CSI1_DATA_5 0x110b0 ++ MX6SX_PAD_LCD1_DATA11__CSI1_DATA_6 0x110b0 ++ MX6SX_PAD_LCD1_DATA10__CSI1_DATA_7 0x110b0 ++ MX6SX_PAD_LCD1_DATA09__CSI1_DATA_8 0x110b0 ++ MX6SX_PAD_LCD1_DATA08__CSI1_DATA_9 0x110b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x80000000 ++ MX6SX_PAD_LCD1_VSYNC__GPIO3_IO_28 0x80000000 ++ >; ++ }; ++ ++ pinctrl_csi_1: csigrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_MCLK__CSI1_MCLK 0x110b0 ++ MX6SX_PAD_CSI_PIXCLK__CSI1_PIXCLK 0x110b0 ++ MX6SX_PAD_CSI_VSYNC__CSI1_VSYNC 0x110b0 ++ MX6SX_PAD_CSI_HSYNC__CSI1_HSYNC 0x110b0 ++ MX6SX_PAD_CSI_DATA00__CSI1_DATA_2 0x110b0 ++ MX6SX_PAD_CSI_DATA01__CSI1_DATA_3 0x110b0 ++ MX6SX_PAD_CSI_DATA02__CSI1_DATA_4 0x110b0 ++ MX6SX_PAD_CSI_DATA03__CSI1_DATA_5 0x110b0 ++ MX6SX_PAD_CSI_DATA04__CSI1_DATA_6 0x110b0 ++ MX6SX_PAD_CSI_DATA05__CSI1_DATA_7 0x110b0 ++ MX6SX_PAD_CSI_DATA06__CSI1_DATA_8 0x110b0 ++ MX6SX_PAD_CSI_DATA07__CSI1_DATA_9 0x110b0 ++ ++ MX6SX_PAD_LCD1_ENABLE__GPIO3_IO_25 0x80000000 ++ MX6SX_PAD_LCD1_HSYNC__GPIO3_IO_26 0x80000000 ++ >; ++ }; ++ }; ++ ++ enet1 { ++ pinctrl_enet1_1: enet1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 ++ MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 ++ MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 ++ >; ++ }; ++ ++ pinctrl_enet1_clkout_1: enet1_clkoutgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x91 ++ >; ++ }; ++ }; ++ ++ enet2 { ++ pinctrl_enet2_1: enet2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x3081 ++ >; ++ }; ++ }; ++ ++ esai { ++ pinctrl_esai_1: esaigrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_MCLK__ESAI_TX_HF_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA00__ESAI_TX_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA01__ESAI_TX_FS 0x1b030 ++ MX6SX_PAD_CSI_HSYNC__ESAI_TX0 0x1b030 ++ MX6SX_PAD_CSI_DATA04__ESAI_TX1 0x1b030 ++ MX6SX_PAD_CSI_DATA06__ESAI_TX2_RX3 0x1b030 ++ MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2 0x1b030 ++ MX6SX_PAD_CSI_DATA02__ESAI_RX_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA03__ESAI_RX_FS 0x1b030 ++ MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0 0x1b030 ++ MX6SX_PAD_CSI_DATA05__ESAI_TX4_RX1 0x1b030 ++ >; ++ }; ++ }; ++ ++ flexcan1 { ++ pinctrl_flexcan1_1: flexcan1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ flexcan2 { ++ pinctrl_flexcan2_1: flexcan2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ gpmi-nand { ++ pinctrl_gpmi_nand_1: gpmi-nand-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 ++ MX6SX_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 ++ MX6SX_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 ++ MX6SX_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 ++ MX6SX_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 ++ MX6SX_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 ++ MX6SX_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 ++ MX6SX_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 ++ MX6SX_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 ++ MX6SX_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 ++ MX6SX_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 ++ MX6SX_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 ++ MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 ++ MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 ++ MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 ++ MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 ++ >; ++ }; ++ }; ++ ++ i2c1 { ++ pinctrl_i2c1_1: i2c1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c1_2: i2c1grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA01__I2C1_SDA 0x4001b8b1 ++ MX6SX_PAD_CSI_DATA00__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c2 { ++ pinctrl_i2c2_1: i2c2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c3 { ++ pinctrl_i2c3_1: i2c3grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_TX_CLK__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3_2: i2c3grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c4 { ++ pinctrl_i2c4_1: i2c4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x4001b8b1 ++ MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x4001b8b1 ++ >; ++ }; ++ pinctrl_i2c4_2: i2c4grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_DATA1__I2C4_SDA 0x4001b8b1 ++ MX6SX_PAD_SD3_DATA0__I2C4_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ lcdif1 { ++ pinctrl_lcdif_dat_0: lcdifdatgrp-0 { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_lcdif_ctrl_0: lcdifctrlgrp-0 { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x4001b0b0 ++ MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x4001b0b0 ++ MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x4001b0b0 ++ >; ++ }; ++ }; ++ ++ mlb { ++ pinctrl_mlb_1: mlbgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD2_DATA3__MLB_DATA 0x31 ++ MX6SX_PAD_SD2_CLK__MLB_SIG 0x31 ++ MX6SX_PAD_SD2_CMD__MLB_CLK 0x31 ++ >; ++ }; ++ }; ++ ++ mqs { ++ pinctrl_mqs_1: mqsgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD2_CLK__MQS_RIGHT 0x80000000 ++ MX6SX_PAD_SD2_CMD__MQS_LEFT 0x80000000 ++ >; ++ }; ++ }; ++ ++ pwm3 { ++ pinctrl_pwm3_0: pwm3grp-0 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO12__PWM3_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_pwm3_1: pwm3grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0 ++ >; ++ }; ++ }; ++ ++ pwm4 { ++ pinctrl_pwm4_0: pwm4grp-0 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x110b0 ++ >; ++ }; ++ }; ++ ++ qspi2 { ++ pinctrl_qspi2_1: qspi2grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0 0x70a1 ++ MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1 0x70a1 ++ MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2 0x70a1 ++ MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3 0x70a1 ++ MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK 0x70a1 ++ MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B 0x70a1 ++ MX6SX_PAD_NAND_DATA01__QSPI2_B_DATA_0 0x70a1 ++ MX6SX_PAD_NAND_DATA00__QSPI2_B_DATA_1 0x70a1 ++ MX6SX_PAD_NAND_WE_B__QSPI2_B_DATA_2 0x70a1 ++ MX6SX_PAD_NAND_RE_B__QSPI2_B_DATA_3 0x70a1 ++ MX6SX_PAD_NAND_DATA02__QSPI2_B_SCLK 0x70a1 ++ MX6SX_PAD_NAND_DATA03__QSPI2_B_SS0_B 0x70a1 ++ >; ++ }; ++ }; ++ ++ sai1 { ++ pinctrl_sai1_1: sai1grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x1b030 ++ MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x1b030 ++ MX6SX_PAD_CSI_DATA02__SAI1_RX_BCLK 0x1b030 ++ MX6SX_PAD_CSI_DATA03__SAI1_RX_SYNC 0x1b030 ++ MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x1b030 ++ MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x1b030 ++ >; ++ }; ++ ++ pinctrl_sai1_2: sai1grp_2 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x130B0 ++ MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x130B0 ++ MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x120B0 ++ MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x130B0 ++ MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130B0 ++ >; ++ }; ++ }; ++ ++ sai2 { ++ pinctrl_sai2_1: sai2grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_COL0__SAI2_TX_BCLK 0x1b030 ++ MX6SX_PAD_KEY_COL1__SAI2_TX_SYNC 0x1b030 ++ MX6SX_PAD_KEY_ROW0__SAI2_TX_DATA_0 0x1b030 ++ MX6SX_PAD_KEY_ROW1__SAI2_RX_DATA_0 0x1b030 ++ >; ++ }; ++ }; ++ ++ ++ spdif { ++ pinctrl_spdif_1: spdifgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_RX_CLK__SPDIF_OUT 0x1b0b0 ++ MX6SX_PAD_ENET2_COL__SPDIF_IN 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_spdif_2: spdifgrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_DATA4__SPDIF_OUT 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1_1: uart1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO05__UART1_RX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1_2: uart1grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_COL__UART1_RX 0x1b0b1 ++ MX6SX_PAD_ENET2_CRS__UART1_TX 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ uart2 { ++ pinctrl_uart2_1: uart2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO07__UART2_RX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO06__UART2_TX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2_2: uart2grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA0__UART2_RX 0x1b0b1 ++ MX6SX_PAD_SD1_DATA1__UART2_TX 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ uart5 { ++ pinctrl_uart5_1: uart5grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5dte_1: uart5dtegrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ usbh { ++ pinctrl_usbh_1: usbhgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_USB_H_STROBE__USB_H_STROBE 0x40013030 ++ MX6SX_PAD_USB_H_DATA__USB_H_DATA 0x40013030 ++ >; ++ }; ++ ++ pinctrl_usbh_2: usbhgrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_USB_H_STROBE__USB_H_STROBE 0x40017030 ++ >; ++ }; ++ }; ++ ++ usbotg1 { ++ pinctrl_usbotg1_1: usbotg1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_2: usbotg1grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_COL__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_3: usbotg1grp-3 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_DATA1__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ }; ++ ++ usbotg2 { ++ pinctrl_usbotg2_1: usbotg2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO13__ANATOP_OTG2_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg2_2: usbotg2grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_CRS__ANATOP_OTG2_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg2_3: usbotg2grp-3 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_SCLK__ANATOP_OTG2_ID 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc1 { ++ pinctrl_usdhc1_1: usdhc1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_CMD__USDHC1_CMD 0x17059 ++ MX6SX_PAD_SD1_CLK__USDHC1_CLK 0x10059 ++ MX6SX_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 ++ MX6SX_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 ++ MX6SX_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 ++ MX6SX_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc2 { ++ pinctrl_usdhc2_1: usdhc2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 ++ MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 ++ MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x17059 ++ MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x17059 ++ MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x17059 ++ MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc3 { ++ pinctrl_usdhc3_1: usdhc3grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10059 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17059 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17059 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17059 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17059 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17059 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17059 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17059 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 ++ >; ++ }; ++ ++ }; ++ ++ usdhc4 { ++ pinctrl_usdhc4_1: usdhc4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x17059 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x17059 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x17059 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc4_1_100mhz: usdhc4grp-1-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170b9 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100b9 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170b9 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170b9 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170b9 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170b9 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170b9 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170b9 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170b9 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc4_1_200mhz: usdhc4grp-1-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170f9 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100f9 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170f9 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170f9 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170f9 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170f9 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170f9 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170f9 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170f9 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170f9 ++ >; ++ }; ++ ++ pinctrl_usdhc4_2: usdhc4grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ >; ++ }; ++ ++ }; ++ ++ weim { ++ pinctrl_weim_cs0_1: weim_cs0grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_ALE__WEIM_CS0_B 0xb0b1 ++ >; ++ }; ++ ++ pinctrl_weim_nor_1: weim_norgrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_CE1_B__WEIM_OE 0xb0b1 ++ MX6SX_PAD_NAND_RE_B__WEIM_RW 0xb0b1 ++ MX6SX_PAD_NAND_WE_B__WEIM_WAIT 0xb060 ++ /* data */ ++ MX6SX_PAD_QSPI1A_SCLK__WEIM_DATA_0 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS0_B__WEIM_DATA_1 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__WEIM_DATA_2 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA3__WEIM_DATA_3 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA2__WEIM_DATA_4 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA1__WEIM_DATA_5 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DATA0__WEIM_DATA_6 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__WEIM_DATA_7 0x1b0b0 ++ MX6SX_PAD_QSPI1B_SCLK__WEIM_DATA_8 0x1b0b0 ++ MX6SX_PAD_QSPI1B_SS0_B__WEIM_DATA_9 0x1b0b0 ++ MX6SX_PAD_QSPI1B_SS1_B__WEIM_DATA_10 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA3__WEIM_DATA_11 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA2__WEIM_DATA_12 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA1__WEIM_DATA_13 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DATA0__WEIM_DATA_14 0x1b0b0 ++ MX6SX_PAD_QSPI1B_DQS__WEIM_DATA_15 0x1b0b0 ++ /* address */ ++ MX6SX_PAD_NAND_DATA00__WEIM_AD_0 0xb0b1 ++ MX6SX_PAD_NAND_DATA01__WEIM_AD_1 0xb0b1 ++ MX6SX_PAD_NAND_DATA02__WEIM_AD_2 0xb0b1 ++ MX6SX_PAD_NAND_DATA03__WEIM_AD_3 0xb0b1 ++ MX6SX_PAD_NAND_DATA04__WEIM_AD_4 0xb0b1 ++ MX6SX_PAD_NAND_DATA05__WEIM_AD_5 0xb0b1 ++ MX6SX_PAD_NAND_DATA06__WEIM_AD_6 0xb0b1 ++ MX6SX_PAD_NAND_DATA07__WEIM_AD_7 0xb0b1 ++ MX6SX_PAD_LCD1_DATA08__WEIM_AD_8 0xb0b1 ++ MX6SX_PAD_LCD1_DATA09__WEIM_AD_9 0xb0b1 ++ MX6SX_PAD_LCD1_DATA10__WEIM_AD_10 0xb0b1 ++ MX6SX_PAD_LCD1_DATA11__WEIM_AD_11 0xb0b1 ++ MX6SX_PAD_LCD1_DATA12__WEIM_AD_12 0xb0b1 ++ MX6SX_PAD_LCD1_DATA13__WEIM_AD_13 0xb0b1 ++ MX6SX_PAD_LCD1_DATA14__WEIM_AD_14 0xb0b1 ++ MX6SX_PAD_LCD1_DATA15__WEIM_AD_15 0xb0b1 ++ MX6SX_PAD_LCD1_DATA16__WEIM_ADDR_16 0xb0b1 ++ MX6SX_PAD_LCD1_DATA17__WEIM_ADDR_17 0xb0b1 ++ MX6SX_PAD_LCD1_DATA18__WEIM_ADDR_18 0xb0b1 ++ MX6SX_PAD_LCD1_DATA19__WEIM_ADDR_19 0xb0b1 ++ MX6SX_PAD_LCD1_DATA20__WEIM_ADDR_20 0xb0b1 ++ MX6SX_PAD_LCD1_DATA21__WEIM_ADDR_21 0xb0b1 ++ MX6SX_PAD_LCD1_DATA22__WEIM_ADDR_22 0xb0b1 ++ MX6SX_PAD_LCD1_DATA03__WEIM_ADDR_24 0xb0b1 ++ MX6SX_PAD_LCD1_DATA04__WEIM_ADDR_25 0xb0b1 ++ MX6SX_PAD_LCD1_DATA05__WEIM_ADDR_26 0xb0b1 ++ >; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-gpmi-weim.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-gpmi-weim.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-gpmi-weim.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-gpmi-weim.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-19x19-arm2.dts" ++ ++&qspi2 { ++ status = "disabled"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ status = "okay"; /* pin conflict with qspi*/ ++ nand-on-flash-bbt; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-lcdif1.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-lcdif1.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-lcdif1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-lcdif1.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-19x19-arm2.dts" ++ ++&i2c2 { ++ ov5640: ov5640@3c { ++ status = "disabled"; ++ }; ++}; ++ ++&lcdif1 { ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-ldo.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-ldo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-ldo.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2015 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 "imx6sx-19x19-arm2.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++}; ++ ++&gpc { ++ fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-mqs.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-mqs.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-mqs.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-mqs.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-19x19-arm2.dts" ++ ++/ { ++ sound-mqs { ++ compatible = "fsl,imx6sx-sdb-mqs", ++ "fsl,imx-audio-mqs"; ++ model = "mqs-audio"; ++ cpu-dai = <&sai1>; ++ audio-codec = <&mqs>; ++ }; ++}; ++ ++&esai { ++ /* pin conflict with sai */ ++ status = "disabled"; ++}; ++ ++&mqs { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_mqs_1>; ++ clocks = <&clks IMX6SX_CLK_SAI1>; ++ clock-names = "mclk"; ++ status = "okay"; ++}; ++ ++&sai1 { ++ status = "okay"; ++}; ++ ++&sdma { ++ gpr = <&gpr>; ++ /* SDMA event remap for SAI1 */ ++ fsl,sdma-event-remap = <0 15 1>, <0 16 1>; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-sai.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-sai.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-19x19-arm2-sai.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-19x19-arm2-sai.dts 2016-06-19 22:11:55.029157811 +0200 +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-19x19-arm2.dts" ++ ++/ { ++ sound-sgtl5000 { ++ compatible = "fsl,imx6sx-arm2-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6sx-arm2-sgtl5000"; ++ cpu-dai = <&sai1>; ++ audio-codec = <&sgtl5000>; ++ audio-routing = ++ "LINE_IN", "Line In Jack", ++ "Headphone Jack", "HP_OUT"; ++ }; ++}; ++ ++&esai { ++ /* pin conflict with sai */ ++ status = "disabled"; ++}; ++ ++&sai1 { ++ status = "okay"; ++}; ++ ++&sdma { ++ gpr = <&gpr>; ++ /* SDMA event remap for SAI1 */ ++ fsl,sdma-event-remap = <0 15 1>, <0 16 1>; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx.dtsi linux-3.14.72/arch/arm/boot/dts/imx6sx.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx.dtsi 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,1492 @@ ++/* ++ * Copyright 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include "imx6sx-pinfunc.h" ++#include "skeleton.dtsi" ++ ++/ { ++ aliases { ++ can0 = &flexcan1; ++ can1 = &flexcan2; ++ ethernet0 = &fec1; ++ ethernet1 = &fec2; ++ gpio0 = &gpio1; ++ gpio1 = &gpio2; ++ gpio2 = &gpio3; ++ gpio3 = &gpio4; ++ gpio4 = &gpio5; ++ gpio5 = &gpio6; ++ gpio6 = &gpio7; ++ i2c0 = &i2c1; ++ i2c1 = &i2c2; ++ i2c2 = &i2c3; ++ i2c3 = &i2c4; ++ mmc0 = &usdhc1; ++ mmc1 = &usdhc2; ++ mmc2 = &usdhc3; ++ mmc3 = &usdhc4; ++ serial0 = &uart1; ++ serial1 = &uart2; ++ serial2 = &uart3; ++ serial3 = &uart4; ++ serial4 = &uart5; ++ serial5 = &uart6; ++ spi0 = &ecspi1; ++ spi1 = &ecspi2; ++ spi2 = &ecspi3; ++ spi3 = &ecspi4; ++ spi4 = &ecspi5; ++ usbphy0 = &usbphy1; ++ usbphy1 = &usbphy2; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "arm,cortex-a9"; ++ device_type = "cpu"; ++ reg = <0>; ++ next-level-cache = <&L2>; ++ operating-points = < ++ /* kHz uV */ ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1075000 ++ 198000 975000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC uV */ ++ 996000 1175000 ++ 792000 1175000 ++ 396000 1175000 ++ 198000 1175000 ++ >; ++ clock-latency = <61036>; /* two CLK32 periods */ ++ clocks = <&clks IMX6SX_CLK_ARM>, ++ <&clks IMX6SX_CLK_PLL2_PFD2>, ++ <&clks IMX6SX_CLK_STEP>, ++ <&clks IMX6SX_CLK_PLL1_SW>, ++ <&clks IMX6SX_CLK_PLL1_SYS>, ++ <&clks IMX6SX_PLL1_BYPASS>, ++ <&clks IMX6SX_CLK_PLL1>, ++ <&clks IMX6SX_PLL1_BYPASS_SRC> ; ++ clock-names = "arm", "pll2_pfd2_396m", "step", ++ "pll1_sw", "pll1_sys", "pll1_bypass", "pll1", "pll1_bypass_src"; ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++ }; ++ }; ++ ++ intc: interrupt-controller@00a01000 { ++ compatible = "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ reg = <0x00a01000 0x1000>, ++ <0x00a00100 0x100>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ckil: clock@0 { ++ compatible = "fixed-clock"; ++ reg = <0>; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ clock-output-names = "ckil"; ++ }; ++ ++ osc: clock@1 { ++ compatible = "fixed-clock"; ++ reg = <1>; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ clock-output-names = "osc"; ++ }; ++ ++ ipp_di0: clock@2 { ++ compatible = "fixed-clock"; ++ reg = <2>; ++ #clock-cells = <0>; ++ clock-frequency = <0>; ++ clock-output-names = "ipp_di0"; ++ }; ++ ++ ipp_di1: clock@3 { ++ compatible = "fixed-clock"; ++ reg = <3>; ++ #clock-cells = <0>; ++ clock-frequency = <0>; ++ clock-output-names = "ipp_di1"; ++ }; ++ }; ++ ++ soc { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "simple-bus"; ++ interrupt-parent = <&intc>; ++ ranges; ++ ++ busfreq { ++ compatible = "fsl,imx6_busfreq"; ++ clocks = <&clks IMX6SX_CLK_PLL2_BUS>, <&clks IMX6SX_CLK_PLL2_PFD2>, ++ <&clks IMX6SX_CLK_PLL2_198M>, <&clks IMX6SX_CLK_ARM>, ++ <&clks IMX6SX_CLK_PLL3_USB_OTG>, <&clks IMX6SX_CLK_PERIPH>, ++ <&clks IMX6SX_CLK_PERIPH_PRE>, <&clks IMX6SX_CLK_PERIPH_CLK2>, ++ <&clks IMX6SX_CLK_PERIPH_CLK2_SEL>, <&clks IMX6SX_CLK_OSC>, ++ <&clks IMX6SX_CLK_PLL1_SYS>, <&clks IMX6SX_CLK_PERIPH2>, ++ <&clks IMX6SX_CLK_AHB>, <&clks IMX6SX_CLK_OCRAM>, ++ <&clks IMX6SX_CLK_PLL1_SW>, <&clks IMX6SX_CLK_PERIPH2_PRE>, ++ <&clks IMX6SX_CLK_PERIPH2_CLK2_SEL>, <&clks IMX6SX_CLK_PERIPH2_CLK2>, ++ <&clks IMX6SX_CLK_STEP>, <&clks IMX6SX_CLK_MMDC_P0_FAST>, ++ <&clks IMX6SX_CLK_M4>; ++ 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", "mmdc", "m4"; ++ fsl,max_ddr_freq = <400000000>; ++ }; ++ ++ pmu { ++ compatible = "arm,cortex-a9-pmu"; ++ interrupts = ; ++ }; ++ ++ ocrams: sram@008f8000 { ++ compatible = "fsl,lpm-sram"; ++ reg = <0x008f8000 0x4000>; ++ clocks = <&clks IMX6SX_CLK_OCRAM_S>; ++ }; ++ ++ ocrams_ddr: sram@00900000 { ++ compatible = "fsl,ddr-lpm-sram"; ++ reg = <0x00900000 0x1000>; ++ clocks = <&clks IMX6SX_CLK_OCRAM>; ++ }; ++ ++ ocram: sram@00901000 { ++ compatible = "mmio-sram"; ++ reg = <0x00901000 0x1F000>; ++ clocks = <&clks IMX6SX_CLK_OCRAM>; ++ }; ++ ++ ocram_mf: sram-mf@00900000 { ++ compatible = "fsl,mega-fast-sram"; ++ reg = <0x00900000 0x20000>; ++ clocks = <&clks IMX6SX_CLK_OCRAM>; ++ }; ++ ++ L2: l2-cache@00a02000 { ++ compatible = "arm,pl310-cache"; ++ reg = <0x00a02000 0x1000>; ++ interrupts = ; ++ cache-unified; ++ cache-level = <2>; ++ arm,tag-latency = <4 2 3>; ++ arm,data-latency = <4 2 3>; ++ }; ++ ++ gpu: gpu@01800000 { ++ compatible = "fsl,imx6sx-gpu", "fsl,imx6q-gpu"; ++ reg = <0x01800000 0x4000>, <0x80000000 0x0>; ++ reg-names = "iobase_3d", "phys_baseaddr"; ++ interrupts = ; ++ interrupt-names = "irq_3d"; ++ clocks = <&clks IMX6SX_CLK_GPU_AXI_PODF>, <&clks IMX6SX_CLK_GPU>, ++ <&clks 0>; ++ clock-names = "gpu3d_axi_clk", "gpu3d_clk", ++ "gpu3d_shader_clk"; ++ resets = <&src 0>; ++ reset-names = "gpu3d"; ++ power-domains = <&gpc 1>; ++ }; ++ ++ caam_sm: caam-sm@00100000 { ++ compatible = "fsl,imx6q-caam-sm"; ++ reg = <0x00100000 0x3fff>; ++ }; ++ ++ dma_apbh: dma-apbh@01804000 { ++ compatible = "fsl,imx6sx-dma-apbh", "fsl,imx28-dma-apbh"; ++ reg = <0x01804000 0x2000>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3"; ++ #dma-cells = <1>; ++ dma-channels = <4>; ++ clocks = <&clks IMX6SX_CLK_APBH_DMA>; ++ }; ++ ++ irq_sec_vio: caam_secvio { ++ compatible = "fsl,imx6q-caam-secvio"; ++ interrupts = <0 20 0x04>; ++ secvio_src = <0x8000001d>; ++ }; ++ ++ gpmi: gpmi-nand@01806000{ ++ compatible = "fsl,imx6sx-gpmi-nand"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x01806000 0x2000>, <0x01808000 0x4000>; ++ reg-names = "gpmi-nand", "bch"; ++ interrupts = ; ++ interrupt-names = "bch"; ++ clocks = <&clks IMX6SX_CLK_GPMI_IO>, ++ <&clks IMX6SX_CLK_GPMI_APB>, ++ <&clks IMX6SX_CLK_GPMI_BCH>, ++ <&clks IMX6SX_CLK_GPMI_BCH_APB>, ++ <&clks IMX6SX_CLK_PER1_BCH>; ++ clock-names = "gpmi_io", "gpmi_apb", "gpmi_bch", ++ "gpmi_bch_apb", "per1_bch"; ++ dmas = <&dma_apbh 0>; ++ dma-names = "rx-tx"; ++ status = "disabled"; ++ }; ++ ++ aips1: aips-bus@02000000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02000000 0x100000>; ++ ranges; ++ ++ spba-bus@02000000 { ++ compatible = "fsl,spba-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02000000 0x40000>; ++ ranges; ++ ++ spdif: spdif@02004000 { ++ compatible = "fsl,imx6sx-spdif", "fsl,imx35-spdif"; ++ reg = <0x02004000 0x4000>; ++ interrupts = ; ++ dmas = <&sdma 14 18 0>, ++ <&sdma 15 18 0>; ++ dma-names = "rx", "tx"; ++ clocks = <&clks IMX6SX_CLK_SPDIF_GCLK>, ++ <&clks IMX6SX_CLK_OSC>, ++ <&clks IMX6SX_CLK_SPDIF>, ++ <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks IMX6SX_CLK_IPG>, ++ <&clks 0>, <&clks 0>, ++ <&clks IMX6SX_CLK_SPBA>; ++ clock-names = "core", "rxtx0", ++ "rxtx1", "rxtx2", ++ "rxtx3", "rxtx4", ++ "rxtx5", "rxtx6", ++ "rxtx7", "dma"; ++ status = "disabled"; ++ }; ++ ++ ecspi1: ecspi@02008000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x02008000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_ECSPI1>, ++ <&clks IMX6SX_CLK_ECSPI1>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ ecspi2: ecspi@0200c000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x0200c000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_ECSPI2>, ++ <&clks IMX6SX_CLK_ECSPI2>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ ecspi3: ecspi@02010000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x02010000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_ECSPI3>, ++ <&clks IMX6SX_CLK_ECSPI3>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ ecspi4: ecspi@02014000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x02014000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_ECSPI4>, ++ <&clks IMX6SX_CLK_ECSPI4>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@02020000 { ++ compatible = "fsl,imx6sx-uart", ++ "fsl,imx6q-uart", "fsl,imx21-uart"; ++ reg = <0x02020000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_UART_IPG>, ++ <&clks IMX6SX_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 25 4 0>, <&sdma 26 4 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ esai: esai@02024000 { ++ compatible = "fsl,imx35-esai"; ++ reg = <0x02024000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_ESAI_IPG>, ++ <&clks IMX6SX_CLK_ESAI_MEM>, ++ <&clks IMX6SX_CLK_ESAI_EXTAL>, ++ <&clks IMX6SX_CLK_ESAI_IPG>, ++ <&clks IMX6SX_CLK_SPBA>; ++ clock-names = "core", "mem", "extal", ++ "fsys", "dma"; ++ dmas = <&sdma 23 21 0>, ++ <&sdma 24 21 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ ssi1: ssi@02028000 { ++ compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; ++ reg = <0x02028000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_SSI1_IPG>, ++ <&clks IMX6SX_CLK_SSI1>; ++ clock-names = "ipg", "baud"; ++ dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ ssi2: ssi@0202c000 { ++ compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; ++ reg = <0x0202c000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_SSI2_IPG>, ++ <&clks IMX6SX_CLK_SSI2>; ++ clock-names = "ipg", "baud"; ++ dmas = <&sdma 41 1 0>, <&sdma 42 1 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ ssi3: ssi@02030000 { ++ compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; ++ reg = <0x02030000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_SSI3_IPG>, ++ <&clks IMX6SX_CLK_SSI3>; ++ clock-names = "ipg", "baud"; ++ dmas = <&sdma 45 1 0>, <&sdma 46 1 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ asrc: asrc@02034000 { ++ compatible = "fsl,imx53-asrc"; ++ reg = <0x02034000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_ASRC_IPG>, ++ <&clks IMX6SX_CLK_ASRC_MEM>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks IMX6SX_CLK_SPDIF>, <&clks 0>, <&clks 0>, ++ <&clks IMX6SX_CLK_SPBA>; ++ clock-names = "mem", "ipg", "asrck_0", ++ "asrck_1", "asrck_2", "asrck_3", "asrck_4", ++ "asrck_5", "asrck_6", "asrck_7", "asrck_8", ++ "asrck_9", "asrck_a", "asrck_b", "asrck_c", ++ "asrck_d", "asrck_e", "asrck_f", "dma"; ++ dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, ++ <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; ++ dma-names = "rxa", "rxb", "rxc", ++ "txa", "txb", "txc"; ++ fsl,asrc-rate = <48000>; ++ fsl,asrc-width = <16>; ++ status = "okay"; ++ }; ++ ++ asrc_p2p: asrc_p2p { ++ compatible = "fsl,imx6q-asrc-p2p"; ++ fsl,p2p-rate = <48000>; ++ fsl,p2p-width = <16>; ++ fsl,asrc-dma-rx-events = <17 18 19>; ++ fsl,asrc-dma-tx-events = <20 21 22>; ++ status = "okay"; ++ }; ++ }; ++ ++ pwm1: pwm@02080000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x02080000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM1>, ++ <&clks IMX6SX_CLK_PWM1>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ ++ pwm2: pwm@02084000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x02084000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM2>, ++ <&clks IMX6SX_CLK_PWM2>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ ++ pwm3: pwm@02088000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x02088000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM3>, ++ <&clks IMX6SX_CLK_PWM3>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ ++ pwm4: pwm@0208c000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x0208c000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM4>, ++ <&clks IMX6SX_CLK_PWM4>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ ++ flexcan1: can@02090000 { ++ compatible = "fsl,imx6sx-flexcan", "fsl,imx6q-flexcan"; ++ reg = <0x02090000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_CAN1_IPG>, ++ <&clks IMX6SX_CLK_CAN1_SERIAL>; ++ clock-names = "ipg", "per"; ++ stop-mode = <&gpr 0x10 1 0x10 17>; ++ status = "disabled"; ++ }; ++ ++ flexcan2: can@02094000 { ++ compatible = "fsl,imx6sx-flexcan", "fsl,imx6q-flexcan"; ++ reg = <0x02094000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_CAN2_IPG>, ++ <&clks IMX6SX_CLK_CAN2_SERIAL>; ++ clock-names = "ipg", "per"; ++ stop-mode = <&gpr 0x10 2 0x10 18>; ++ status = "disabled"; ++ }; ++ ++ gpt: gpt@02098000 { ++ compatible = "fsl,imx6sx-gpt", "fsl,imx31-gpt"; ++ reg = <0x02098000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_GPT_BUS>, ++ <&clks IMX6SX_CLK_GPT_SERIAL>; ++ clock-names = "ipg", "per"; ++ }; ++ ++ gpio1: gpio@0209c000 { ++ compatible = "fsl,imx6sx-gpio", "fsl,imx35-gpio"; ++ reg = <0x0209c000 0x4000>; ++ interrupts = , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio@020a0000 { ++ compatible = "fsl,imx6sx-gpio", "fsl,imx35-gpio"; ++ reg = <0x020a0000 0x4000>; ++ interrupts = , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio@020a4000 { ++ compatible = "fsl,imx6sx-gpio", "fsl,imx35-gpio"; ++ reg = <0x020a4000 0x4000>; ++ interrupts = , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio4: gpio@020a8000 { ++ compatible = "fsl,imx6sx-gpio", "fsl,imx35-gpio"; ++ reg = <0x020a8000 0x4000>; ++ interrupts = , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio5: gpio@020ac000 { ++ compatible = "fsl,imx6sx-gpio", "fsl,imx35-gpio"; ++ reg = <0x020ac000 0x4000>; ++ interrupts = , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio6: gpio@020b0000 { ++ compatible = "fsl,imx6sx-gpio", "fsl,imx35-gpio"; ++ reg = <0x020b0000 0x4000>; ++ interrupts = , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio7: gpio@020b4000 { ++ compatible = "fsl,imx6sx-gpio", "fsl,imx35-gpio"; ++ reg = <0x020b4000 0x4000>; ++ interrupts = , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ kpp: kpp@020b8000 { ++ compatible = "fsl,imx6sx-kpp", "fsl,imx21-kpp"; ++ reg = <0x020b8000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_DUMMY>; ++ status = "disabled"; ++ }; ++ ++ wdog1: wdog@020bc000 { ++ compatible = "fsl,imx6sx-wdt", "fsl,imx21-wdt"; ++ reg = <0x020bc000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_DUMMY>; ++ }; ++ ++ wdog2: wdog@020c0000 { ++ compatible = "fsl,imx6sx-wdt", "fsl,imx21-wdt"; ++ reg = <0x020c0000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_DUMMY>; ++ status = "disabled"; ++ }; ++ ++ clks: ccm@020c4000 { ++ compatible = "fsl,imx6sx-ccm"; ++ reg = <0x020c4000 0x4000>; ++ interrupts = , ++ ; ++ #clock-cells = <1>; ++ clocks = <&ckil>, <&osc>, <&ipp_di0>, <&ipp_di1>; ++ clock-names = "ckil", "osc", "ipp_di0", "ipp_di1"; ++ }; ++ ++ anatop: anatop@020c8000 { ++ compatible = "fsl,imx6sx-anatop", "fsl,imx6q-anatop", ++ "syscon", "simple-bus"; ++ reg = <0x020c8000 0x1000>; ++ interrupts = , ++ , ++ ; ++ ++ regulator-1p1@110 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vdd1p1"; ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1375000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x110>; ++ anatop-vol-bit-shift = <8>; ++ anatop-vol-bit-width = <5>; ++ anatop-min-bit-val = <4>; ++ anatop-min-voltage = <800000>; ++ anatop-max-voltage = <1375000>; ++ }; ++ ++ regulator-3p0@120 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vdd3p0"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <3150000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x120>; ++ anatop-vol-bit-shift = <8>; ++ anatop-vol-bit-width = <5>; ++ anatop-min-bit-val = <0>; ++ anatop-min-voltage = <2625000>; ++ anatop-max-voltage = <3400000>; ++ }; ++ ++ regulator-2p5@130 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vdd2p5"; ++ regulator-min-microvolt = <2100000>; ++ regulator-max-microvolt = <2875000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x130>; ++ anatop-vol-bit-shift = <8>; ++ anatop-vol-bit-width = <5>; ++ anatop-min-bit-val = <0>; ++ anatop-min-voltage = <2100000>; ++ anatop-max-voltage = <2875000>; ++ }; ++ ++ reg_arm: regulator-vddcore@140 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "cpu"; ++ regulator-min-microvolt = <725000>; ++ regulator-max-microvolt = <1450000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x140>; ++ anatop-vol-bit-shift = <0>; ++ anatop-vol-bit-width = <5>; ++ anatop-delay-reg-offset = <0x170>; ++ anatop-delay-bit-shift = <24>; ++ anatop-delay-bit-width = <2>; ++ anatop-min-bit-val = <1>; ++ anatop-min-voltage = <725000>; ++ anatop-max-voltage = <1450000>; ++ }; ++ ++ reg_pcie_phy: regulator-vddpcie-phy@140 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vddpcie-phy"; ++ regulator-min-microvolt = <725000>; ++ regulator-max-microvolt = <1450000>; ++ anatop-reg-offset = <0x140>; ++ anatop-vol-bit-shift = <9>; ++ anatop-vol-bit-width = <5>; ++ anatop-delay-reg-offset = <0x170>; ++ anatop-delay-bit-shift = <26>; ++ anatop-delay-bit-width = <2>; ++ anatop-min-bit-val = <1>; ++ anatop-min-voltage = <725000>; ++ anatop-max-voltage = <1450000>; ++ }; ++ ++ reg_soc: regulator-vddsoc@140 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vddsoc"; ++ regulator-min-microvolt = <725000>; ++ regulator-max-microvolt = <1450000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x140>; ++ anatop-vol-bit-shift = <18>; ++ anatop-vol-bit-width = <5>; ++ anatop-delay-reg-offset = <0x170>; ++ anatop-delay-bit-shift = <28>; ++ anatop-delay-bit-width = <2>; ++ anatop-min-bit-val = <1>; ++ anatop-min-voltage = <725000>; ++ anatop-max-voltage = <1450000>; ++ }; ++ }; ++ ++ tempmon: tempmon { ++ compatible = "fsl,imx6sx-tempmon"; ++ interrupts = ; ++ fsl,tempmon = <&anatop>; ++ fsl,tempmon-data = <&ocotp>; ++ clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>; ++ }; ++ ++ usbphy1: usbphy@020c9000 { ++ compatible = "fsl,imx6sx-usbphy", "fsl,imx23-usbphy"; ++ reg = <0x020c9000 0x1000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USBPHY1>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ usbphy2: usbphy@020ca000 { ++ compatible = "fsl,imx6sx-usbphy", "fsl,imx23-usbphy"; ++ reg = <0x020ca000 0x1000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USBPHY2>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ usbphy_nop1: usbphy_nop1 { ++ compatible = "usb-nop-xceiv"; ++ clocks = <&clks IMX6SX_CLK_USBPHY1>; ++ clock-names = "main_clk"; ++ }; ++ ++ mqs: mqs { ++ compatible = "fsl,imx6sx-mqs"; ++ gpr = <&gpr>; ++ status = "disabled"; ++ }; ++ ++ caam_snvs: caam-snvs@020cc000 { ++ compatible = "fsl,imx6q-caam-snvs"; ++ reg = <0x020cc000 0x4000>; ++ }; ++ ++ snvs: snvs@020cc000 { ++ compatible = "fsl,sec-v4.0-mon", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x020cc000 0x4000>; ++ ++ snvs-rtc-lp@34 { ++ compatible = "fsl,sec-v4.0-mon-rtc-lp"; ++ reg = <0x34 0x58>; ++ interrupts = , ; ++ }; ++ }; ++ ++ snvs-pwrkey@0x020cc000 { ++ compatible = "fsl,imx6sx-snvs-pwrkey"; ++ reg = <0x020cc000 0x4000>; ++ interrupts = ; ++ fsl,keycode = <116>; /* KEY_POWER */ ++ fsl,wakeup; ++ }; ++ ++ epit1: epit@020d0000 { ++ reg = <0x020d0000 0x4000>; ++ interrupts = ; ++ }; ++ ++ epit2: epit@020d4000 { ++ reg = <0x020d4000 0x4000>; ++ interrupts = ; ++ }; ++ ++ src: src@020d8000 { ++ compatible = "fsl,imx6sx-src", "fsl,imx51-src"; ++ reg = <0x020d8000 0x4000>; ++ interrupts = , ++ ; ++ #reset-cells = <1>; ++ }; ++ ++ gpc: gpc@020dc000 { ++ compatible = "fsl,imx6sx-gpc", "fsl,imx6q-gpc"; ++ reg = <0x020dc000 0x4000>; ++ interrupts = ; ++ fsl,mf-mix-wakeup-irq = <0x7c00000 0x3d00 0x0 0x400240>; ++ clocks = <&clks IMX6SX_CLK_GPU>, <&clks IMX6SX_CLK_IPG>, ++ <&clks IMX6SX_CLK_PXP_AXI>, <&clks IMX6SX_CLK_DISPLAY_AXI>, ++ <&clks IMX6SX_CLK_LCDIF1_PIX>, <&clks IMX6SX_CLK_LCDIF_APB>, ++ <&clks IMX6SX_CLK_LCDIF2_PIX>, <&clks IMX6SX_CLK_CSI>, ++ <&clks IMX6SX_CLK_VADC>; ++ clock-names = "gpu3d_core", "ipg", "pxp_axi", "disp_axi", "lcdif1_pix", ++ "lcdif_axi", "lcdif2_pix", "csi_mclk"; ++ pcie-phy-supply = <®_pcie_phy>; ++ #power-domain-cells = <1>; ++ }; ++ ++ iomuxc: iomuxc@020e0000 { ++ compatible = "fsl,imx6sx-iomuxc"; ++ reg = <0x020e0000 0x4000>; ++ }; ++ ++ gpr: iomuxc-gpr@020e4000 { ++ compatible = "fsl,imx6sx-iomuxc-gpr", "syscon"; ++ reg = <0x020e4000 0x4000>; ++ }; ++ ++ ldb: ldb@020e0014 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-ldb", "fsl,imx53-ldb"; ++ gpr = <&gpr>; ++ status = "disabled"; ++ ++ clocks = <&clks IMX6SX_CLK_LDB_DI0>, ++ <&clks IMX6SX_CLK_LCDIF1_SEL>, ++ <&clks IMX6SX_CLK_LCDIF2_SEL>, ++ <&clks IMX6SX_CLK_LDB_DI0_DIV_3_5>, ++ <&clks IMX6SX_CLK_LDB_DI0_DIV_7>, ++ <&clks IMX6SX_CLK_LDB_DI0_DIV_SEL>; ++ clock-names = "ldb_di0", ++ "di0_sel", ++ "di1_sel", ++ "ldb_di0_div_3_5", ++ "ldb_di0_div_7", ++ "ldb_di0_div_sel"; ++ ++ lvds-channel@0 { ++ reg = <0>; ++ status = "disabled"; ++ }; ++ }; ++ ++ sdma: sdma@020ec000 { ++ compatible = "fsl,imx6sx-sdma", "fsl,imx35-sdma"; ++ reg = <0x020ec000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_SDMA>, ++ <&clks IMX6SX_CLK_SDMA>; ++ clock-names = "ipg", "ahb"; ++ #dma-cells = <3>; ++ fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; ++ }; ++ }; ++ ++ aips2: aips-bus@02100000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02100000 0x100000>; ++ ranges; ++ ++ crypto: caam@2100000 { ++ compatible = "fsl,sec-v4.0"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2100000 0x40000>; ++ ranges = <0 0x2100000 0x40000>; ++ interrupt-parent = <&intc>; /* interrupts = <0 92 0x4>; */ ++ clocks = <&clks IMX6SX_CLK_CAAM_MEM>, <&clks IMX6SX_CLK_CAAM_ACLK>, ++ <&clks IMX6SX_CLK_CAAM_IPG> ,<&clks IMX6SX_CLK_EIM_SLOW>; ++ 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 0x4>; ++ }; ++ ++ sec_jr1: jr1@2000 { ++ compatible = "fsl,sec-v4.0-job-ring"; ++ reg = <0x2000 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <0 106 0x4>; ++ }; ++ }; ++ ++ usbotg1: usb@02184000 { ++ compatible = "fsl,imx6sx-usb", "fsl,imx27-usb"; ++ reg = <0x02184000 0x200>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USBOH3>; ++ fsl,usbphy = <&usbphy1>; ++ fsl,usbmisc = <&usbmisc 0>; ++ fsl,anatop = <&anatop>; ++ status = "disabled"; ++ }; ++ ++ usbotg2: usb@02184200 { ++ compatible = "fsl,imx6sx-usb", "fsl,imx27-usb"; ++ reg = <0x02184200 0x200>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USBOH3>; ++ fsl,usbphy = <&usbphy2>; ++ fsl,usbmisc = <&usbmisc 1>; ++ status = "disabled"; ++ }; ++ ++ usbh: usb@02184400 { ++ compatible = "fsl,imx6sx-usb", "fsl,imx27-usb"; ++ reg = <0x02184400 0x200>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USBOH3>; ++ fsl,usbmisc = <&usbmisc 2>; ++ phy_type = "hsic"; ++ fsl,usbphy = <&usbphy_nop1>; ++ fsl,anatop = <&anatop>; ++ status = "disabled"; ++ }; ++ ++ usbmisc: usbmisc@02184800 { ++ #index-cells = <1>; ++ compatible = "fsl,imx6sx-usbmisc", "fsl,imx6q-usbmisc"; ++ reg = <0x02184800 0x200>; ++ clocks = <&clks IMX6SX_CLK_USBOH3>; ++ }; ++ ++ fec1: ethernet@02188000 { ++ compatible = "fsl,imx6sx-fec", "fsl,imx6q-fec"; ++ reg = <0x02188000 0x4000>; ++ interrupts = , ++ ; ++ clocks = <&clks IMX6SX_CLK_ENET>, ++ <&clks IMX6SX_CLK_ENET_AHB>, ++ <&clks IMX6SX_CLK_ENET_PTP>, ++ <&clks IMX6SX_CLK_ENET_REF>, ++ <&clks IMX6SX_CLK_ENET_PTP>; ++ clock-names = "ipg", "ahb", "ptp", ++ "enet_clk_ref", "enet_out"; ++ fsl,num-tx-queues=<3>; ++ fsl,num-rx-queues=<3>; ++ status = "disabled"; ++ }; ++ ++ mlb: mlb@0218c000 { ++ compatible = "fsl,imx6sx-mlb50"; ++ reg = <0x0218c000 0x4000>; ++ interrupts = , ++ , ++ ; ++ clocks = <&clks IMX6SX_CLK_MLB>; ++ clock-names = "mlb"; ++ iram = <&ocram>; ++ status = "disabled"; ++ }; ++ ++ usdhc1: usdhc@02190000 { ++ compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; ++ reg = <0x02190000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USDHC1>, ++ <&clks IMX6SX_CLK_USDHC1>, ++ <&clks IMX6SX_CLK_USDHC1>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ usdhc2: usdhc@02194000 { ++ compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; ++ reg = <0x02194000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USDHC2>, ++ <&clks IMX6SX_CLK_USDHC2>, ++ <&clks IMX6SX_CLK_USDHC2>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ usdhc3: usdhc@02198000 { ++ compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; ++ reg = <0x02198000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USDHC3>, ++ <&clks IMX6SX_CLK_USDHC3>, ++ <&clks IMX6SX_CLK_USDHC3>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ usdhc4: usdhc@0219c000 { ++ compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; ++ reg = <0x0219c000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_USDHC4>, ++ <&clks IMX6SX_CLK_USDHC4>, ++ <&clks IMX6SX_CLK_USDHC4>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@021a0000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-i2c", "fsl,imx21-i2c"; ++ reg = <0x021a0000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_I2C1>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@021a4000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-i2c", "fsl,imx21-i2c"; ++ reg = <0x021a4000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_I2C2>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@021a8000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-i2c", "fsl,imx21-i2c"; ++ reg = <0x021a8000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_I2C3>; ++ status = "disabled"; ++ }; ++ ++ mmdc: mmdc@021b0000 { ++ compatible = "fsl,imx6sx-mmdc", "fsl,imx6q-mmdc"; ++ reg = <0x021b0000 0x4000>; ++ }; ++ ++ fec2: ethernet@021b4000 { ++ compatible = "fsl,imx6sx-fec", "fsl,imx6q-fec"; ++ reg = <0x021b4000 0x4000>; ++ interrupts = , ++ ; ++ clocks = <&clks IMX6SX_CLK_ENET>, ++ <&clks IMX6SX_CLK_ENET_AHB>, ++ <&clks IMX6SX_CLK_ENET_PTP>, ++ <&clks IMX6SX_CLK_ENET2_REF_125M>, ++ <&clks IMX6SX_CLK_ENET_PTP>; ++ clock-names = "ipg", "ahb", "ptp", ++ "enet_clk_ref", "enet_out"; ++ fsl,num-tx-queues=<3>; ++ fsl,num-rx-queues=<3>; ++ status = "disabled"; ++ }; ++ ++ weim: weim@021b8000 { ++ compatible = "fsl,imx6sx-weim", "fsl,imx6q-weim"; ++ reg = <0x021b8000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_EIM_SLOW>; ++ }; ++ ++ ocotp: ocotp-ctrl@021bc000 { ++ compatible = "syscon"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6SX_CLK_OCOTP>; ++ }; ++ ++ ocotp-fuse@021bc000 { ++ compatible = "fsl,imx6sx-ocotp", "fsl,imx6q-ocotp"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6SX_CLK_OCOTP>; ++ }; ++ ++ romcp@021ac000 { ++ compatible = "fsl,imx6sx-romcp", "syscon"; ++ reg = <0x021ac000 0x4000>; ++ }; ++ ++ sai1: sai@021d4000 { ++ compatible = "fsl,imx6sx-sai"; ++ reg = <0x021d4000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_SAI1_IPG>, ++ <&clks IMX6SX_CLK_SAI1>, ++ <&clks 0>, <&clks 0>; ++ clock-names = "bus", "mclk1", "mclk2", "mclk3"; ++ dma-names = "rx", "tx"; ++ dmas = <&sdma 31 25 0>, <&sdma 32 25 0>; ++ dma-source = <&gpr 0 15 0 16>; ++ status = "disabled"; ++ }; ++ ++ audmux: audmux@021d8000 { ++ compatible = "fsl,imx6sx-audmux", "fsl,imx31-audmux"; ++ reg = <0x021d8000 0x4000>; ++ status = "disabled"; ++ }; ++ ++ sai2: sai@021dc000 { ++ compatible = "fsl,imx6sx-sai"; ++ reg = <0x021dc000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_SAI2_IPG>, ++ <&clks IMX6SX_CLK_SAI2>, ++ <&clks 0>, <&clks 0>; ++ clock-names = "bus", "mclk1", "mclk2", "mclk3"; ++ dma-names = "rx", "tx"; ++ dmas = <&sdma 33 25 0>, <&sdma 34 25 0>; ++ dma-source = <&gpr 0 17 0 18>; ++ status = "disabled"; ++ }; ++ ++ qspi1: qspi@021e0000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-qspi"; ++ reg = <0x021e0000 0x4000>, <0x60000000 0x10000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_QSPI1>, ++ <&clks IMX6SX_CLK_QSPI1>; ++ clock-names = "qspi_en", "qspi"; ++ status = "disabled"; ++ }; ++ ++ qspi2: qspi@021e4000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-qspi"; ++ reg = <0x021e4000 0x4000>, <0x70000000 0x10000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_QSPI2>, ++ <&clks IMX6SX_CLK_QSPI2>; ++ clock-names = "qspi_en", "qspi"; ++ status = "disabled"; ++ }; ++ ++ qspi_m4: qspi-m4 { ++ compatible = "fsl,imx6sx-qspi-m4-restore"; ++ reg = <0x021e4000 0x4000>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@021e8000 { ++ compatible = "fsl,imx6sx-uart", ++ "fsl,imx6q-uart", "fsl,imx21-uart"; ++ reg = <0x021e8000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_UART_IPG>, ++ <&clks IMX6SX_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@021ec000 { ++ compatible = "fsl,imx6sx-uart", ++ "fsl,imx6q-uart", "fsl,imx21-uart"; ++ reg = <0x021ec000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_UART_IPG>, ++ <&clks IMX6SX_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 29 4 0>, <&sdma 30 4 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@021f0000 { ++ compatible = "fsl,imx6sx-uart", ++ "fsl,imx6q-uart", "fsl,imx21-uart"; ++ reg = <0x021f0000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_UART_IPG>, ++ <&clks IMX6SX_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@021f4000 { ++ compatible = "fsl,imx6sx-uart", ++ "fsl,imx6q-uart", "fsl,imx21-uart"; ++ reg = <0x021f4000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_UART_IPG>, ++ <&clks IMX6SX_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@021f8000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-i2c", "fsl,imx21-i2c"; ++ reg = <0x021f8000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_I2C4>; ++ status = "disabled"; ++ }; ++ ++ qosc: qosc@021fc000 { ++ compatible = "fsl,imx6sx-qosc"; ++ reg = <0x021fc000 0x4000>; ++ }; ++ }; ++ ++ aips3: aips-bus@02200000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02200000 0x100000>; ++ ranges; ++ ++ spba-bus@02200000 { ++ compatible = "fsl,spba-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02240000 0x40000>; ++ ranges; ++ ++ dcic1: dcic@0220c000 { ++ compatible = "fsl,imx6sx-dcic"; ++ reg = <0x0220c000 0x4000>; ++ interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SX_CLK_DCIC1>, ++ <&clks IMX6SX_CLK_DISPLAY_AXI>; ++ clock-names = "dcic", "disp-axi"; ++ gpr = <&gpr>; ++ status = "disabled"; ++ }; ++ ++ dcic2: dcic@02210000 { ++ compatible = "fsl,imx6sx-dcic"; ++ reg = <0x02210000 0x4000>; ++ interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SX_CLK_DCIC2>, ++ <&clks IMX6SX_CLK_DISPLAY_AXI>; ++ clock-names = "dcic", "disp-axi"; ++ gpr = <&gpr>; ++ status = "disabled"; ++ }; ++ ++ csi1: csi@02214000 { ++ compatible = "fsl,imx6s-csi"; ++ reg = <0x02214000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_DISPLAY_AXI>, ++ <&clks IMX6SX_CLK_CSI>, ++ <&clks IMX6SX_CLK_DCIC1>; ++ clock-names = "disp-axi", "csi_mclk", "disp_dcic"; ++ power-domains = <&gpc 2>; ++ status = "disabled"; ++ }; ++ ++ pxp: pxp@02218000 { ++ compatible = "fsl,imx6sx-pxp-dma", "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; ++ reg = <0x02218000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PXP_AXI>, ++ <&clks IMX6SX_CLK_DISPLAY_AXI>; ++ clock-names = "pxp-axi", "disp-axi"; ++ power-domains = <&gpc 2>; ++ status = "disabled"; ++ }; ++ ++ csi2: csi@0221c000 { ++ compatible = "fsl,imx6s-csi"; ++ reg = <0x0221c000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_DISPLAY_AXI>, ++ <&clks IMX6SX_CLK_CSI>, ++ <&clks IMX6SX_CLK_DCIC2>; ++ clock-names = "disp-axi", "csi_mclk", "disp_dcic"; ++ power-domains = <&gpc 2>; ++ status = "disabled"; ++ }; ++ ++ lcdif1: lcdif@02220000 { ++ compatible = "fsl,imx6sx-lcdif", "fsl,imx28-lcdif"; ++ reg = <0x02220000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_LCDIF1_PIX>, ++ <&clks IMX6SX_CLK_LCDIF_APB>, ++ <&clks IMX6SX_CLK_DISPLAY_AXI>; ++ clock-names = "pix", "axi", "disp_axi"; ++ power-domains = <&gpc 2>; ++ status = "disabled"; ++ }; ++ ++ lcdif2: lcdif@02224000 { ++ compatible = "fsl,imx6sx-lcdif", "fsl,imx28-lcdif"; ++ reg = <0x02224000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_LCDIF2_PIX>, ++ <&clks IMX6SX_CLK_LCDIF_APB>, ++ <&clks IMX6SX_CLK_DISPLAY_AXI>; ++ clock-names = "pix", "axi", "disp_axi"; ++ power-domains = <&gpc 2>; ++ status = "disabled"; ++ }; ++ ++ vadc: vadc@02228000 { ++ compatible = "fsl,imx6sx-vadc"; ++ reg = <0x02228000 0x4000>, <0x0222c000 0x4000>; ++ reg-names = "vadc-vafe", "vadc-vdec"; ++ clocks = <&clks IMX6SX_CLK_VADC>, ++ <&clks IMX6SX_CLK_CSI>; ++ clock-names = "vadc", "csi"; ++ power-domains = <&gpc 2>; ++ gpr = <&gpr>; ++ status = "disabled"; ++ }; ++ }; ++ ++ adc1: adc@02280000 { ++ compatible = "fsl,imx6sx-adc", "fsl,vf610-adc"; ++ reg = <0x02280000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_IPG>; ++ num-channels = <4>; ++ clock-names = "adc"; ++ status = "disabled"; ++ }; ++ ++ adc2: adc@02284000 { ++ compatible = "fsl,imx6sx-adc", "fsl,vf610-adc"; ++ reg = <0x02284000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_IPG>; ++ num-channels = <4>; ++ clock-names = "adc"; ++ status = "disabled"; ++ }; ++ ++ wdog3: wdog@02288000 { ++ compatible = "fsl,imx6sx-wdt", "fsl,imx21-wdt"; ++ reg = <0x02288000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_DUMMY>; ++ status = "disabled"; ++ }; ++ ++ ecspi5: ecspi@0228c000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sx-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x0228c000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_ECSPI5>, ++ <&clks IMX6SX_CLK_ECSPI5>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ sema4: sema4@02290000 { /* sema4 */ ++ compatible = "fsl,imx6sx-sema4"; ++ reg = <0x02290000 0x4000>; ++ interrupts = <0 116 0x04>; ++ status = "okay"; ++ }; ++ ++ mu: mu@02294000 { /* mu */ ++ compatible = "fsl,imx6sx-mu"; ++ reg = <0x02294000 0x4000>; ++ interrupts = <0 90 0x04>; ++ status = "okay"; ++ }; ++ ++ mcctest: mcctest{ ++ compatible = "fsl,imx6sx-mcc-test"; ++ status = "disabled"; ++ }; ++ ++ mcctty: mcctty{ ++ compatible = "fsl,imx6sx-mcc-tty"; ++ status = "disabled"; ++ }; ++ ++ uart6: serial@022a0000 { ++ compatible = "fsl,imx6sx-uart", ++ "fsl,imx6q-uart", "fsl,imx21-uart"; ++ reg = <0x022a0000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_UART_IPG>, ++ <&clks IMX6SX_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ dmas = <&sdma 0 4 0>, <&sdma 47 4 0>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ pwm5: pwm@022a4000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x022a4000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM5>, ++ <&clks IMX6SX_CLK_PWM5>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ ++ pwm6: pwm@022a8000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x022a8000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM6>, ++ <&clks IMX6SX_CLK_PWM6>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ ++ pwm7: pwm@022ac000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x022ac000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM7>, ++ <&clks IMX6SX_CLK_PWM7>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ ++ pwm8: pwm@0022b0000 { ++ compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; ++ reg = <0x0022b0000 0x4000>; ++ interrupts = ; ++ clocks = <&clks IMX6SX_CLK_PWM8>, ++ <&clks IMX6SX_CLK_PWM8>; ++ clock-names = "ipg", "per"; ++ #pwm-cells = <2>; ++ }; ++ }; ++ ++ pcie: pcie@0x08000000 { ++ compatible = "fsl,imx6sx-pcie", "snps,dw-pcie"; ++ reg = <0x08ffc000 0x4000>, <0x08f00000 0x80000>; ++ reg-names = "dbi", "config"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x81000000 0 0 0x08f80000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; /* non-prefetchable memory */ ++ num-lanes = <1>; ++ interrupts = ; ++ interrupt-names = "msi"; ++ #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 IMX6SX_CLK_PCIE_AXI>, ++ <&clks IMX6SX_CLK_LVDS1_OUT>, ++ <&clks IMX6SX_CLK_PCIE_REF_125M>, ++ <&clks IMX6SX_CLK_DISPLAY_AXI>; ++ clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_inbound_axi"; ++ pcie-phy-supply = <®_pcie_phy>; ++ power-domains = <&gpc 2>; ++ status = "disabled"; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-pinfunc.h linux-3.14.72/arch/arm/boot/dts/imx6sx-pinfunc.h +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-pinfunc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-pinfunc.h 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,1570 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef __DTS_IMX6SX_PINFUNC_H ++#define __DTS_IMX6SX_PINFUNC_H ++ ++/* ++ * The pin function ID is a tuple of ++ * ++ */ ++#define MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x0014 0x035C 0x07A8 0x0 0x1 ++#define MX6SX_PAD_GPIO1_IO00__USDHC1_VSELECT 0x0014 0x035C 0x0000 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO00__SPDIF_LOCK 0x0014 0x035C 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO00__CCM_WAIT 0x0014 0x035C 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO00__WDOG1_WDOG_ANY 0x0014 0x035C 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO00__GPIO1_IO_0 0x0014 0x035C 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO00__SNVS_HP_WRAPPER_VIO_5 0x0014 0x035C 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO00__PHY_DTB_1 0x0014 0x035C 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x0018 0x0360 0x07AC 0x0 0x1 ++#define MX6SX_PAD_GPIO1_IO01__USDHC1_RESET_B 0x0018 0x0360 0x0000 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO01__SPDIF_SR_CLK 0x0018 0x0360 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO01__CCM_STOP 0x0018 0x0360 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO01__WDOG3_WDOG_B 0x0018 0x0360 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO01__GPIO1_IO_1 0x0018 0x0360 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO01__SNVS_HP_WRAPPER_VIO_5_CTL 0x0018 0x0360 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO01__PHY_DTB_0 0x0018 0x0360 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x001C 0x0364 0x07B0 0x0 0x1 ++#define MX6SX_PAD_GPIO1_IO02__USDHC1_CD_B 0x001C 0x0364 0x0864 0x1 0x1 ++#define MX6SX_PAD_GPIO1_IO02__CSI2_MCLK 0x001C 0x0364 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO02__CCM_DI0_EXT_CLK 0x001C 0x0364 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO02__WDOG1_WDOG_B 0x001C 0x0364 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO02__GPIO1_IO_2 0x001C 0x0364 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO02__CCM_REF_EN_B 0x001C 0x0364 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO02__PHY_TDI 0x001C 0x0364 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x0020 0x0368 0x07B4 0x0 0x1 ++#define MX6SX_PAD_GPIO1_IO03__USDHC1_WP 0x0020 0x0368 0x0868 0x1 0x1 ++#define MX6SX_PAD_GPIO1_IO03__ENET1_REF_CLK_25M 0x0020 0x0368 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO03__CCM_DI1_EXT_CLK 0x0020 0x0368 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO03__WDOG2_WDOG_B 0x0020 0x0368 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO03__GPIO1_IO_3 0x0020 0x0368 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO03__CCM_PLL3_BYP 0x0020 0x0368 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO03__PHY_TCK 0x0020 0x0368 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO04__UART1_RX 0x0024 0x036C 0x0830 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO04__UART1_TX 0x0024 0x036C 0x0000 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO04__USDHC2_RESET_B 0x0024 0x036C 0x0000 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO04__ENET1_MDC 0x0024 0x036C 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO04__OSC32K_32K_OUT 0x0024 0x036C 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO04__ENET2_REF_CLK2 0x0024 0x036C 0x076C 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO04__GPIO1_IO_4 0x0024 0x036C 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO04__CCM_PLL2_BYP 0x0024 0x036C 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO04__PHY_TMS 0x0024 0x036C 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO05__UART1_RX 0x0028 0x0370 0x0830 0x0 0x1 ++#define MX6SX_PAD_GPIO1_IO05__UART1_TX 0x0028 0x0370 0x0000 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO05__USDHC2_VSELECT 0x0028 0x0370 0x0000 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO05__ENET1_MDIO 0x0028 0x0370 0x0764 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO05__ASRC_ASRC_EXT_CLK 0x0028 0x0370 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO05__ENET1_REF_CLK1 0x0028 0x0370 0x0760 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO05__GPIO1_IO_5 0x0028 0x0370 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO05__SRC_TESTER_ACK 0x0028 0x0370 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO05__PHY_TDO 0x0028 0x0370 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO06__UART2_RX 0x002C 0x0374 0x0838 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO06__UART2_TX 0x002C 0x0374 0x0000 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO06__USDHC2_CD_B 0x002C 0x0374 0x086C 0x1 0x1 ++#define MX6SX_PAD_GPIO1_IO06__ENET2_MDC 0x002C 0x0374 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO06__CSI1_MCLK 0x002C 0x0374 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO06__UART1_RTS_B 0x002C 0x0374 0x082C 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO06__UART1_CTS_B 0x002C 0x0374 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO06__GPIO1_IO_6 0x002C 0x0374 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO06__SRC_ANY_PU_RESET 0x002C 0x0374 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO06__OCOTP_CTRL_WRAPPER_FUSE_LATCHED 0x002C 0x0374 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO07__UART2_RX 0x0030 0x0378 0x0838 0x0 0x1 ++#define MX6SX_PAD_GPIO1_IO07__UART2_TX 0x0030 0x0378 0x0000 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO07__USDHC2_WP 0x0030 0x0378 0x0870 0x1 0x1 ++#define MX6SX_PAD_GPIO1_IO07__ENET2_MDIO 0x0030 0x0378 0x0770 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO07__AUDMUX_MCLK 0x0030 0x0378 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B 0x0030 0x0378 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO07__UART1_RTS_B 0x0030 0x0378 0x082C 0x4 0x1 ++#define MX6SX_PAD_GPIO1_IO07__GPIO1_IO_7 0x0030 0x0378 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO07__SRC_EARLY_RESET 0x0030 0x0378 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO07__DCIC2_OUT 0x0030 0x0378 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO07__VDEC_DEBUG_44 0x0030 0x0378 0x0000 0x8 0x0 ++#define MX6SX_PAD_GPIO1_IO08__USB_OTG1_OC 0x0034 0x037C 0x0860 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO08__WDOG1_WDOG_B 0x0034 0x037C 0x0000 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO08__SDMA_EXT_EVENT_0 0x0034 0x037C 0x081C 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO08__CCM_PMIC_RDY 0x0034 0x037C 0x069C 0x3 0x1 ++#define MX6SX_PAD_GPIO1_IO08__UART2_RTS_B 0x0034 0x037C 0x0834 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO08__UART2_CTS_B 0x0034 0x037C 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO08__GPIO1_IO_8 0x0034 0x037C 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO08__SRC_SYSTEM_RESET 0x0034 0x037C 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO08__DCIC1_OUT 0x0034 0x037C 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO08__VDEC_DEBUG_43 0x0034 0x037C 0x0000 0x8 0x0 ++#define MX6SX_PAD_GPIO1_IO09__USB_OTG1_PWR 0x0038 0x0380 0x0000 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO09__WDOG2_WDOG_B 0x0038 0x0380 0x0000 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO09__SDMA_EXT_EVENT_1 0x0038 0x0380 0x0820 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO09__CCM_OUT0 0x0038 0x0380 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B 0x0038 0x0380 0x0000 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO09__UART2_RTS_B 0x0038 0x0380 0x0834 0x4 0x1 ++#define MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9 0x0038 0x0380 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO09__SRC_INT_BOOT 0x0038 0x0380 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO09__OBSERVE_MUX_OUT_4 0x0038 0x0380 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO09__VDEC_DEBUG_42 0x0038 0x0380 0x0000 0x8 0x0 ++#define MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x003C 0x0384 0x0624 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO10__SPDIF_EXT_CLK 0x003C 0x0384 0x0828 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO10__PWM1_OUT 0x003C 0x0384 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO10__CCM_OUT1 0x003C 0x0384 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO10__CSI1_FIELD 0x003C 0x0384 0x070C 0x4 0x1 ++#define MX6SX_PAD_GPIO1_IO10__GPIO1_IO_10 0x003C 0x0384 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO10__CSU_CSU_INT_DEB 0x003C 0x0384 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO10__OBSERVE_MUX_OUT_3 0x003C 0x0384 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO10__VDEC_DEBUG_41 0x003C 0x0384 0x0000 0x8 0x0 ++#define MX6SX_PAD_GPIO1_IO11__USB_OTG2_OC 0x0040 0x0388 0x085C 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO11__SPDIF_IN 0x0040 0x0388 0x0824 0x1 0x2 ++#define MX6SX_PAD_GPIO1_IO11__PWM2_OUT 0x0040 0x0388 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO11__CCM_CLKO1 0x0040 0x0388 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO11__MLB_DATA 0x0040 0x0388 0x07EC 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO11__GPIO1_IO_11 0x0040 0x0388 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO11__CSU_CSU_ALARM_AUT_0 0x0040 0x0388 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO11__OBSERVE_MUX_OUT_2 0x0040 0x0388 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO11__VDEC_DEBUG_40 0x0040 0x0388 0x0000 0x8 0x0 ++#define MX6SX_PAD_GPIO1_IO12__USB_OTG2_PWR 0x0044 0x038C 0x0000 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO12__SPDIF_OUT 0x0044 0x038C 0x0000 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO12__PWM3_OUT 0x0044 0x038C 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO12__CCM_CLKO2 0x0044 0x038C 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO12__MLB_CLK 0x0044 0x038C 0x07E8 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO12__GPIO1_IO_12 0x0044 0x038C 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO12__CSU_CSU_ALARM_AUT_1 0x0044 0x038C 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO12__OBSERVE_MUX_OUT_1 0x0044 0x038C 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO12__VDEC_DEBUG_39 0x0044 0x038C 0x0000 0x8 0x0 ++#define MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x0048 0x0390 0x0000 0x0 0x0 ++#define MX6SX_PAD_GPIO1_IO13__ANATOP_OTG2_ID 0x0048 0x0390 0x0628 0x1 0x0 ++#define MX6SX_PAD_GPIO1_IO13__PWM4_OUT 0x0048 0x0390 0x0000 0x2 0x0 ++#define MX6SX_PAD_GPIO1_IO13__CCM_OUT2 0x0048 0x0390 0x0000 0x3 0x0 ++#define MX6SX_PAD_GPIO1_IO13__MLB_SIG 0x0048 0x0390 0x07F0 0x4 0x0 ++#define MX6SX_PAD_GPIO1_IO13__GPIO1_IO_13 0x0048 0x0390 0x0000 0x5 0x0 ++#define MX6SX_PAD_GPIO1_IO13__CSU_CSU_ALARM_AUT_2 0x0048 0x0390 0x0000 0x6 0x0 ++#define MX6SX_PAD_GPIO1_IO13__OBSERVE_MUX_OUT_0 0x0048 0x0390 0x0000 0x7 0x0 ++#define MX6SX_PAD_GPIO1_IO13__VDEC_DEBUG_38 0x0048 0x0390 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA00__CSI1_DATA_2 0x004C 0x0394 0x06A8 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA00__ESAI_TX_CLK 0x004C 0x0394 0x078C 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA00__AUDMUX_AUD6_TXC 0x004C 0x0394 0x0684 0x2 0x1 ++#define MX6SX_PAD_CSI_DATA00__I2C1_SCL 0x004C 0x0394 0x07A8 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA00__UART6_RI_B 0x004C 0x0394 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA00__GPIO1_IO_14 0x004C 0x0394 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA00__WEIM_DATA_23 0x004C 0x0394 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x004C 0x0394 0x0800 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA00__VADC_DATA_4 0x004C 0x0394 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA00__MMDC_DEBUG_37 0x004C 0x0394 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_DATA01__CSI1_DATA_3 0x0050 0x0398 0x06AC 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA01__ESAI_TX_FS 0x0050 0x0398 0x077C 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA01__AUDMUX_AUD6_TXFS 0x0050 0x0398 0x0688 0x2 0x1 ++#define MX6SX_PAD_CSI_DATA01__I2C1_SDA 0x0050 0x0398 0x07AC 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA01__UART6_DSR_B 0x0050 0x0398 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA01__GPIO1_IO_15 0x0050 0x0398 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA01__WEIM_DATA_22 0x0050 0x0398 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x0050 0x0398 0x0804 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA01__VADC_DATA_5 0x0050 0x0398 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA01__MMDC_DEBUG_38 0x0050 0x0398 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_DATA02__CSI1_DATA_4 0x0054 0x039C 0x06B0 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA02__ESAI_RX_CLK 0x0054 0x039C 0x0788 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA02__AUDMUX_AUD6_RXC 0x0054 0x039C 0x067C 0x2 0x1 ++#define MX6SX_PAD_CSI_DATA02__KPP_COL_5 0x0054 0x039C 0x07C8 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA02__UART6_DTR_B 0x0054 0x039C 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA02__GPIO1_IO_16 0x0054 0x039C 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA02__WEIM_DATA_21 0x0054 0x039C 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA02__SAI1_RX_BCLK 0x0054 0x039C 0x07F4 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA02__VADC_DATA_6 0x0054 0x039C 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA02__MMDC_DEBUG_39 0x0054 0x039C 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_DATA03__CSI1_DATA_5 0x0058 0x03A0 0x06B4 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA03__ESAI_RX_FS 0x0058 0x03A0 0x0778 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA03__AUDMUX_AUD6_RXFS 0x0058 0x03A0 0x0680 0x2 0x1 ++#define MX6SX_PAD_CSI_DATA03__KPP_ROW_5 0x0058 0x03A0 0x07D4 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA03__UART6_DCD_B 0x0058 0x03A0 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA03__GPIO1_IO_17 0x0058 0x03A0 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA03__WEIM_DATA_20 0x0058 0x03A0 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA03__SAI1_RX_SYNC 0x0058 0x03A0 0x07FC 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA03__VADC_DATA_7 0x0058 0x03A0 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA03__MMDC_DEBUG_40 0x0058 0x03A0 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_DATA04__CSI1_DATA_6 0x005C 0x03A4 0x06B8 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA04__ESAI_TX1 0x005C 0x03A4 0x0794 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA04__SPDIF_OUT 0x005C 0x03A4 0x0000 0x2 0x0 ++#define MX6SX_PAD_CSI_DATA04__KPP_COL_6 0x005C 0x03A4 0x07CC 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA04__UART6_RX 0x005C 0x03A4 0x0858 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA04__UART6_TX 0x005C 0x03A4 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA04__GPIO1_IO_18 0x005C 0x03A4 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA04__WEIM_DATA_19 0x005C 0x03A4 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA04__PWM5_OUT 0x005C 0x03A4 0x0000 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA04__VADC_DATA_8 0x005C 0x03A4 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA04__MMDC_DEBUG_41 0x005C 0x03A4 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_DATA05__CSI1_DATA_7 0x0060 0x03A8 0x06BC 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA05__ESAI_TX4_RX1 0x0060 0x03A8 0x07A0 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA05__SPDIF_IN 0x0060 0x03A8 0x0824 0x2 0x1 ++#define MX6SX_PAD_CSI_DATA05__KPP_ROW_6 0x0060 0x03A8 0x07D8 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA05__UART6_RX 0x0060 0x03A8 0x0858 0x4 0x1 ++#define MX6SX_PAD_CSI_DATA05__UART6_TX 0x0060 0x03A8 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA05__GPIO1_IO_19 0x0060 0x03A8 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA05__WEIM_DATA_18 0x0060 0x03A8 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA05__PWM6_OUT 0x0060 0x03A8 0x0000 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA05__VADC_DATA_9 0x0060 0x03A8 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA05__MMDC_DEBUG_42 0x0060 0x03A8 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_DATA06__CSI1_DATA_8 0x0064 0x03AC 0x06C0 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA06__ESAI_TX2_RX3 0x0064 0x03AC 0x0798 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x0064 0x03AC 0x07C0 0x2 0x2 ++#define MX6SX_PAD_CSI_DATA06__KPP_COL_7 0x0064 0x03AC 0x07D0 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA06__UART6_RTS_B 0x0064 0x03AC 0x0854 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA06__UART6_CTS_B 0x0064 0x03AC 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA06__GPIO1_IO_20 0x0064 0x03AC 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA06__WEIM_DATA_17 0x0064 0x03AC 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA06__DCIC2_OUT 0x0064 0x03AC 0x0000 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA06__VADC_DATA_10 0x0064 0x03AC 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA06__MMDC_DEBUG_43 0x0064 0x03AC 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_DATA07__CSI1_DATA_9 0x0068 0x03B0 0x06C4 0x0 0x0 ++#define MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2 0x0068 0x03B0 0x079C 0x1 0x1 ++#define MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x0068 0x03B0 0x07C4 0x2 0x2 ++#define MX6SX_PAD_CSI_DATA07__KPP_ROW_7 0x0068 0x03B0 0x07DC 0x3 0x0 ++#define MX6SX_PAD_CSI_DATA07__UART6_CTS_B 0x0068 0x03B0 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_DATA07__UART6_RTS_B 0x0068 0x03B0 0x0854 0x4 0x1 ++#define MX6SX_PAD_CSI_DATA07__GPIO1_IO_21 0x0068 0x03B0 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_DATA07__WEIM_DATA_16 0x0068 0x03B0 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_DATA07__DCIC1_OUT 0x0068 0x03B0 0x0000 0x7 0x0 ++#define MX6SX_PAD_CSI_DATA07__VADC_DATA_11 0x0068 0x03B0 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_DATA07__MMDC_DEBUG_44 0x0068 0x03B0 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_HSYNC__CSI1_HSYNC 0x006C 0x03B4 0x0700 0x0 0x0 ++#define MX6SX_PAD_CSI_HSYNC__ESAI_TX0 0x006C 0x03B4 0x0790 0x1 0x1 ++#define MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD 0x006C 0x03B4 0x0678 0x2 0x1 ++#define MX6SX_PAD_CSI_HSYNC__UART4_RTS_B 0x006C 0x03B4 0x0844 0x3 0x2 ++#define MX6SX_PAD_CSI_HSYNC__UART4_CTS_B 0x006C 0x03B4 0x0000 0x3 0x0 ++#define MX6SX_PAD_CSI_HSYNC__MQS_LEFT 0x006C 0x03B4 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_HSYNC__GPIO1_IO_22 0x006C 0x03B4 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_HSYNC__WEIM_DATA_25 0x006C 0x03B4 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x006C 0x03B4 0x0000 0x7 0x0 ++#define MX6SX_PAD_CSI_HSYNC__VADC_DATA_2 0x006C 0x03B4 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_HSYNC__MMDC_DEBUG_35 0x006C 0x03B4 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_MCLK__CSI1_MCLK 0x0070 0x03B8 0x0000 0x0 0x0 ++#define MX6SX_PAD_CSI_MCLK__ESAI_TX_HF_CLK 0x0070 0x03B8 0x0784 0x1 0x1 ++#define MX6SX_PAD_CSI_MCLK__OSC32K_32K_OUT 0x0070 0x03B8 0x0000 0x2 0x0 ++#define MX6SX_PAD_CSI_MCLK__UART4_RX 0x0070 0x03B8 0x0848 0x3 0x2 ++#define MX6SX_PAD_CSI_MCLK__UART4_TX 0x0070 0x03B8 0x0000 0x3 0x0 ++#define MX6SX_PAD_CSI_MCLK__ANATOP_32K_OUT 0x0070 0x03B8 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_MCLK__GPIO1_IO_23 0x0070 0x03B8 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_MCLK__WEIM_DATA_26 0x0070 0x03B8 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_MCLK__CSI1_FIELD 0x0070 0x03B8 0x070C 0x7 0x0 ++#define MX6SX_PAD_CSI_MCLK__VADC_DATA_1 0x0070 0x03B8 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_MCLK__MMDC_DEBUG_34 0x0070 0x03B8 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__CSI1_PIXCLK 0x0074 0x03BC 0x0704 0x0 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__ESAI_RX_HF_CLK 0x0074 0x03BC 0x0780 0x1 0x1 ++#define MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x0074 0x03BC 0x0000 0x2 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__UART4_RX 0x0074 0x03BC 0x0848 0x3 0x3 ++#define MX6SX_PAD_CSI_PIXCLK__UART4_TX 0x0074 0x03BC 0x0000 0x3 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__ANATOP_24M_OUT 0x0074 0x03BC 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__GPIO1_IO_24 0x0074 0x03BC 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__WEIM_DATA_27 0x0074 0x03BC 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__ESAI_TX_HF_CLK 0x0074 0x03BC 0x0784 0x7 0x2 ++#define MX6SX_PAD_CSI_PIXCLK__VADC_CLK 0x0074 0x03BC 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_PIXCLK__MMDC_DEBUG_33 0x0074 0x03BC 0x0000 0x9 0x0 ++#define MX6SX_PAD_CSI_VSYNC__CSI1_VSYNC 0x0078 0x03C0 0x0708 0x0 0x0 ++#define MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0 0x0078 0x03C0 0x07A4 0x1 0x1 ++#define MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x0078 0x03C0 0x0674 0x2 0x1 ++#define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B 0x0078 0x03C0 0x0000 0x3 0x0 ++#define MX6SX_PAD_CSI_VSYNC__UART4_RTS_B 0x0078 0x03C0 0x0844 0x3 0x3 ++#define MX6SX_PAD_CSI_VSYNC__MQS_RIGHT 0x0078 0x03C0 0x0000 0x4 0x0 ++#define MX6SX_PAD_CSI_VSYNC__GPIO1_IO_25 0x0078 0x03C0 0x0000 0x5 0x0 ++#define MX6SX_PAD_CSI_VSYNC__WEIM_DATA_24 0x0078 0x03C0 0x0000 0x6 0x0 ++#define MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x0078 0x03C0 0x07F8 0x7 0x0 ++#define MX6SX_PAD_CSI_VSYNC__VADC_DATA_3 0x0078 0x03C0 0x0000 0x8 0x0 ++#define MX6SX_PAD_CSI_VSYNC__MMDC_DEBUG_36 0x0078 0x03C0 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET1_COL__ENET1_COL 0x007C 0x03C4 0x0000 0x0 0x0 ++#define MX6SX_PAD_ENET1_COL__ENET2_MDC 0x007C 0x03C4 0x0000 0x1 0x0 ++#define MX6SX_PAD_ENET1_COL__AUDMUX_AUD4_TXC 0x007C 0x03C4 0x0654 0x2 0x1 ++#define MX6SX_PAD_ENET1_COL__UART1_RI_B 0x007C 0x03C4 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET1_COL__SPDIF_EXT_CLK 0x007C 0x03C4 0x0828 0x4 0x1 ++#define MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x007C 0x03C4 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET1_COL__CSI2_DATA_23 0x007C 0x03C4 0x0000 0x6 0x0 ++#define MX6SX_PAD_ENET1_COL__LCDIF2_DATA_16 0x007C 0x03C4 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET1_COL__VDEC_DEBUG_37 0x007C 0x03C4 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET1_COL__PCIE_CTRL_DEBUG_31 0x007C 0x03C4 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET1_CRS__ENET1_CRS 0x0080 0x03C8 0x0000 0x0 0x0 ++#define MX6SX_PAD_ENET1_CRS__ENET2_MDIO 0x0080 0x03C8 0x0770 0x1 0x1 ++#define MX6SX_PAD_ENET1_CRS__AUDMUX_AUD4_TXD 0x0080 0x03C8 0x0648 0x2 0x1 ++#define MX6SX_PAD_ENET1_CRS__UART1_DCD_B 0x0080 0x03C8 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET1_CRS__SPDIF_LOCK 0x0080 0x03C8 0x0000 0x4 0x0 ++#define MX6SX_PAD_ENET1_CRS__GPIO2_IO_1 0x0080 0x03C8 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET1_CRS__CSI2_DATA_22 0x0080 0x03C8 0x0000 0x6 0x0 ++#define MX6SX_PAD_ENET1_CRS__LCDIF2_DATA_17 0x0080 0x03C8 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET1_CRS__VDEC_DEBUG_36 0x0080 0x03C8 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET1_CRS__PCIE_CTRL_DEBUG_30 0x0080 0x03C8 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET1_MDC__ENET1_MDC 0x0084 0x03CC 0x0000 0x0 0x0 ++#define MX6SX_PAD_ENET1_MDC__ENET2_MDC 0x0084 0x03CC 0x0000 0x1 0x0 ++#define MX6SX_PAD_ENET1_MDC__AUDMUX_AUD3_RXFS 0x0084 0x03CC 0x0638 0x2 0x1 ++#define MX6SX_PAD_ENET1_MDC__ANATOP_24M_OUT 0x0084 0x03CC 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET1_MDC__EPIT2_OUT 0x0084 0x03CC 0x0000 0x4 0x0 ++#define MX6SX_PAD_ENET1_MDC__GPIO2_IO_2 0x0084 0x03CC 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET1_MDC__USB_OTG1_PWR 0x0084 0x03CC 0x0000 0x6 0x0 ++#define MX6SX_PAD_ENET1_MDC__PWM7_OUT 0x0084 0x03CC 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0x0088 0x03D0 0x0764 0x0 0x1 ++#define MX6SX_PAD_ENET1_MDIO__ENET2_MDIO 0x0088 0x03D0 0x0770 0x1 0x2 ++#define MX6SX_PAD_ENET1_MDIO__AUDMUX_MCLK 0x0088 0x03D0 0x0000 0x2 0x0 ++#define MX6SX_PAD_ENET1_MDIO__OSC32K_32K_OUT 0x0088 0x03D0 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET1_MDIO__EPIT1_OUT 0x0088 0x03D0 0x0000 0x4 0x0 ++#define MX6SX_PAD_ENET1_MDIO__GPIO2_IO_3 0x0088 0x03D0 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET1_MDIO__USB_OTG1_OC 0x0088 0x03D0 0x0860 0x6 0x1 ++#define MX6SX_PAD_ENET1_MDIO__PWM8_OUT 0x0088 0x03D0 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__ENET1_RX_CLK 0x008C 0x03D4 0x0768 0x0 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__ENET1_REF_CLK_25M 0x008C 0x03D4 0x0000 0x1 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__AUDMUX_AUD4_TXFS 0x008C 0x03D4 0x0658 0x2 0x1 ++#define MX6SX_PAD_ENET1_RX_CLK__UART1_DSR_B 0x008C 0x03D4 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__SPDIF_OUT 0x008C 0x03D4 0x0000 0x4 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__GPIO2_IO_4 0x008C 0x03D4 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__CSI2_DATA_21 0x008C 0x03D4 0x0000 0x6 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__LCDIF2_DATA_18 0x008C 0x03D4 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__VDEC_DEBUG_35 0x008C 0x03D4 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET1_RX_CLK__PCIE_CTRL_DEBUG_29 0x008C 0x03D4 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__ENET1_TX_CLK 0x0090 0x03D8 0x0000 0x0 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x0090 0x03D8 0x0760 0x1 0x1 ++#define MX6SX_PAD_ENET1_TX_CLK__AUDMUX_AUD4_RXD 0x0090 0x03D8 0x0644 0x2 0x1 ++#define MX6SX_PAD_ENET1_TX_CLK__UART1_DTR_B 0x0090 0x03D8 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__SPDIF_SR_CLK 0x0090 0x03D8 0x0000 0x4 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__GPIO2_IO_5 0x0090 0x03D8 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__CSI2_DATA_20 0x0090 0x03D8 0x0000 0x6 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__LCDIF2_DATA_19 0x0090 0x03D8 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__VDEC_DEBUG_34 0x0090 0x03D8 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET1_TX_CLK__PCIE_CTRL_DEBUG_28 0x0090 0x03D8 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET2_COL__ENET2_COL 0x0094 0x03DC 0x0000 0x0 0x0 ++#define MX6SX_PAD_ENET2_COL__ENET1_MDC 0x0094 0x03DC 0x0000 0x1 0x0 ++#define MX6SX_PAD_ENET2_COL__AUDMUX_AUD4_RXC 0x0094 0x03DC 0x064C 0x2 0x1 ++#define MX6SX_PAD_ENET2_COL__UART1_RX 0x0094 0x03DC 0x0830 0x3 0x2 ++#define MX6SX_PAD_ENET2_COL__UART1_TX 0x0094 0x03DC 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET2_COL__SPDIF_IN 0x0094 0x03DC 0x0824 0x4 0x3 ++#define MX6SX_PAD_ENET2_COL__GPIO2_IO_6 0x0094 0x03DC 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET2_COL__ANATOP_OTG1_ID 0x0094 0x03DC 0x0624 0x6 0x1 ++#define MX6SX_PAD_ENET2_COL__LCDIF2_DATA_20 0x0094 0x03DC 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET2_COL__VDEC_DEBUG_33 0x0094 0x03DC 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET2_COL__PCIE_CTRL_DEBUG_27 0x0094 0x03DC 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET2_CRS__ENET2_CRS 0x0098 0x03E0 0x0000 0x0 0x0 ++#define MX6SX_PAD_ENET2_CRS__ENET1_MDIO 0x0098 0x03E0 0x0764 0x1 0x2 ++#define MX6SX_PAD_ENET2_CRS__AUDMUX_AUD4_RXFS 0x0098 0x03E0 0x0650 0x2 0x1 ++#define MX6SX_PAD_ENET2_CRS__UART1_RX 0x0098 0x03E0 0x0830 0x3 0x3 ++#define MX6SX_PAD_ENET2_CRS__UART1_TX 0x0098 0x03E0 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET2_CRS__MLB_SIG 0x0098 0x03E0 0x07F0 0x4 0x1 ++#define MX6SX_PAD_ENET2_CRS__GPIO2_IO_7 0x0098 0x03E0 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET2_CRS__ANATOP_OTG2_ID 0x0098 0x03E0 0x0628 0x6 0x1 ++#define MX6SX_PAD_ENET2_CRS__LCDIF2_DATA_21 0x0098 0x03E0 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET2_CRS__VDEC_DEBUG_32 0x0098 0x03E0 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET2_CRS__PCIE_CTRL_DEBUG_26 0x0098 0x03E0 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET2_RX_CLK__ENET2_RX_CLK 0x009C 0x03E4 0x0774 0x0 0x0 ++#define MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x009C 0x03E4 0x0000 0x1 0x0 ++#define MX6SX_PAD_ENET2_RX_CLK__I2C3_SCL 0x009C 0x03E4 0x07B8 0x2 0x1 ++#define MX6SX_PAD_ENET2_RX_CLK__UART1_RTS_B 0x009C 0x03E4 0x082C 0x3 0x2 ++#define MX6SX_PAD_ENET2_RX_CLK__UART1_CTS_B 0x009C 0x03E4 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET2_RX_CLK__MLB_DATA 0x009C 0x03E4 0x07EC 0x4 0x1 ++#define MX6SX_PAD_ENET2_RX_CLK__GPIO2_IO_8 0x009C 0x03E4 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET2_RX_CLK__USB_OTG2_OC 0x009C 0x03E4 0x085C 0x6 0x1 ++#define MX6SX_PAD_ENET2_RX_CLK__LCDIF2_DATA_22 0x009C 0x03E4 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET2_RX_CLK__VDEC_DEBUG_31 0x009C 0x03E4 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET2_RX_CLK__PCIE_CTRL_DEBUG_25 0x009C 0x03E4 0x0000 0x9 0x0 ++#define MX6SX_PAD_ENET2_TX_CLK__ENET2_TX_CLK 0x00A0 0x03E8 0x0000 0x0 0x0 ++#define MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x00A0 0x03E8 0x076C 0x1 0x1 ++#define MX6SX_PAD_ENET2_TX_CLK__I2C3_SDA 0x00A0 0x03E8 0x07BC 0x2 0x1 ++#define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B 0x00A0 0x03E8 0x0000 0x3 0x0 ++#define MX6SX_PAD_ENET2_TX_CLK__UART1_RTS_B 0x00A0 0x03E8 0x082C 0x3 0x3 ++#define MX6SX_PAD_ENET2_TX_CLK__MLB_CLK 0x00A0 0x03E8 0x07E8 0x4 0x1 ++#define MX6SX_PAD_ENET2_TX_CLK__GPIO2_IO_9 0x00A0 0x03E8 0x0000 0x5 0x0 ++#define MX6SX_PAD_ENET2_TX_CLK__USB_OTG2_PWR 0x00A0 0x03E8 0x0000 0x6 0x0 ++#define MX6SX_PAD_ENET2_TX_CLK__LCDIF2_DATA_23 0x00A0 0x03E8 0x0000 0x7 0x0 ++#define MX6SX_PAD_ENET2_TX_CLK__VDEC_DEBUG_30 0x00A0 0x03E8 0x0000 0x8 0x0 ++#define MX6SX_PAD_ENET2_TX_CLK__PCIE_CTRL_DEBUG_24 0x00A0 0x03E8 0x0000 0x9 0x0 ++#define MX6SX_PAD_KEY_COL0__KPP_COL_0 0x00A4 0x03EC 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_COL0__USDHC3_CD_B 0x00A4 0x03EC 0x0000 0x1 0x0 ++#define MX6SX_PAD_KEY_COL0__UART6_RTS_B 0x00A4 0x03EC 0x0854 0x2 0x2 ++#define MX6SX_PAD_KEY_COL0__UART6_CTS_B 0x00A4 0x03EC 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_COL0__ECSPI1_SCLK 0x00A4 0x03EC 0x0710 0x3 0x0 ++#define MX6SX_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x00A4 0x03EC 0x066C 0x4 0x0 ++#define MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x00A4 0x03EC 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_COL0__SDMA_EXT_EVENT_1 0x00A4 0x03EC 0x0820 0x6 0x1 ++#define MX6SX_PAD_KEY_COL0__SAI2_TX_BCLK 0x00A4 0x03EC 0x0814 0x7 0x0 ++#define MX6SX_PAD_KEY_COL0__VADC_DATA_0 0x00A4 0x03EC 0x0000 0x8 0x0 ++#define MX6SX_PAD_KEY_COL1__KPP_COL_1 0x00A8 0x03F0 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_COL1__USDHC3_RESET_B 0x00A8 0x03F0 0x0000 0x1 0x0 ++#define MX6SX_PAD_KEY_COL1__UART6_RX 0x00A8 0x03F0 0x0858 0x2 0x2 ++#define MX6SX_PAD_KEY_COL1__UART6_TX 0x00A8 0x03F0 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_COL1__ECSPI1_MISO 0x00A8 0x03F0 0x0714 0x3 0x0 ++#define MX6SX_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x00A8 0x03F0 0x0670 0x4 0x0 ++#define MX6SX_PAD_KEY_COL1__GPIO2_IO_11 0x00A8 0x03F0 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_COL1__USDHC3_RESET 0x00A8 0x03F0 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_COL1__SAI2_TX_SYNC 0x00A8 0x03F0 0x0818 0x7 0x0 ++#define MX6SX_PAD_KEY_COL2__KPP_COL_2 0x00AC 0x03F4 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_COL2__USDHC4_CD_B 0x00AC 0x03F4 0x0874 0x1 0x1 ++#define MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x00AC 0x03F4 0x084C 0x2 0x2 ++#define MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x00AC 0x03F4 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_COL2__CAN1_TX 0x00AC 0x03F4 0x0000 0x3 0x0 ++#define MX6SX_PAD_KEY_COL2__CANFD_TX1 0x00AC 0x03F4 0x0000 0x4 0x0 ++#define MX6SX_PAD_KEY_COL2__GPIO2_IO_12 0x00AC 0x03F4 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_COL2__WEIM_DATA_30 0x00AC 0x03F4 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_COL2__ECSPI1_RDY 0x00AC 0x03F4 0x0000 0x7 0x0 ++#define MX6SX_PAD_KEY_COL3__KPP_COL_3 0x00B0 0x03F8 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_COL3__USDHC4_LCTL 0x00B0 0x03F8 0x0000 0x1 0x0 ++#define MX6SX_PAD_KEY_COL3__UART5_RX 0x00B0 0x03F8 0x0850 0x2 0x2 ++#define MX6SX_PAD_KEY_COL3__UART5_TX 0x00B0 0x03F8 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_COL3__CAN2_TX 0x00B0 0x03F8 0x0000 0x3 0x0 ++#define MX6SX_PAD_KEY_COL3__CANFD_TX2 0x00B0 0x03F8 0x0000 0x4 0x0 ++#define MX6SX_PAD_KEY_COL3__GPIO2_IO_13 0x00B0 0x03F8 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_COL3__WEIM_DATA_28 0x00B0 0x03F8 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_COL3__ECSPI1_SS2 0x00B0 0x03F8 0x0000 0x7 0x0 ++#define MX6SX_PAD_KEY_COL4__KPP_COL_4 0x00B4 0x03FC 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_COL4__ENET2_MDC 0x00B4 0x03FC 0x0000 0x1 0x0 ++#define MX6SX_PAD_KEY_COL4__I2C3_SCL 0x00B4 0x03FC 0x07B8 0x2 0x2 ++#define MX6SX_PAD_KEY_COL4__USDHC2_LCTL 0x00B4 0x03FC 0x0000 0x3 0x0 ++#define MX6SX_PAD_KEY_COL4__AUDMUX_AUD5_RXC 0x00B4 0x03FC 0x0664 0x4 0x0 ++#define MX6SX_PAD_KEY_COL4__GPIO2_IO_14 0x00B4 0x03FC 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_COL4__WEIM_CRE 0x00B4 0x03FC 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_COL4__SAI2_RX_BCLK 0x00B4 0x03FC 0x0808 0x7 0x0 ++#define MX6SX_PAD_KEY_ROW0__KPP_ROW_0 0x00B8 0x0400 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_ROW0__USDHC3_WP 0x00B8 0x0400 0x0000 0x1 0x0 ++#define MX6SX_PAD_KEY_ROW0__UART6_CTS_B 0x00B8 0x0400 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_ROW0__UART6_RTS_B 0x00B8 0x0400 0x0854 0x2 0x3 ++#define MX6SX_PAD_KEY_ROW0__ECSPI1_MOSI 0x00B8 0x0400 0x0718 0x3 0x0 ++#define MX6SX_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x00B8 0x0400 0x0660 0x4 0x0 ++#define MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x00B8 0x0400 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_ROW0__SDMA_EXT_EVENT_0 0x00B8 0x0400 0x081C 0x6 0x1 ++#define MX6SX_PAD_KEY_ROW0__SAI2_TX_DATA_0 0x00B8 0x0400 0x0000 0x7 0x0 ++#define MX6SX_PAD_KEY_ROW0__GPU_IDLE 0x00B8 0x0400 0x0000 0x8 0x0 ++#define MX6SX_PAD_KEY_ROW1__KPP_ROW_1 0x00BC 0x0404 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_ROW1__USDHC4_VSELECT 0x00BC 0x0404 0x0000 0x1 0x0 ++#define MX6SX_PAD_KEY_ROW1__UART6_RX 0x00BC 0x0404 0x0858 0x2 0x3 ++#define MX6SX_PAD_KEY_ROW1__UART6_TX 0x00BC 0x0404 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_ROW1__ECSPI1_SS0 0x00BC 0x0404 0x071C 0x3 0x0 ++#define MX6SX_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x00BC 0x0404 0x065C 0x4 0x0 ++#define MX6SX_PAD_KEY_ROW1__GPIO2_IO_16 0x00BC 0x0404 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_ROW1__WEIM_DATA_31 0x00BC 0x0404 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_ROW1__SAI2_RX_DATA_0 0x00BC 0x0404 0x080C 0x7 0x0 ++#define MX6SX_PAD_KEY_ROW1__M4_NMI 0x00BC 0x0404 0x0000 0x8 0x0 ++#define MX6SX_PAD_KEY_ROW2__KPP_ROW_2 0x00C0 0x0408 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_ROW2__USDHC4_WP 0x00C0 0x0408 0x0878 0x1 0x1 ++#define MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x00C0 0x0408 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x00C0 0x0408 0x084C 0x2 0x3 ++#define MX6SX_PAD_KEY_ROW2__CAN1_RX 0x00C0 0x0408 0x068C 0x3 0x1 ++#define MX6SX_PAD_KEY_ROW2__CANFD_RX1 0x00C0 0x0408 0x0694 0x4 0x1 ++#define MX6SX_PAD_KEY_ROW2__GPIO2_IO_17 0x00C0 0x0408 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_ROW2__WEIM_DATA_29 0x00C0 0x0408 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_ROW2__ECSPI1_SS3 0x00C0 0x0408 0x0000 0x7 0x0 ++#define MX6SX_PAD_KEY_ROW3__KPP_ROW_3 0x00C4 0x040C 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_ROW3__USDHC3_LCTL 0x00C4 0x040C 0x0000 0x1 0x0 ++#define MX6SX_PAD_KEY_ROW3__UART5_RX 0x00C4 0x040C 0x0850 0x2 0x3 ++#define MX6SX_PAD_KEY_ROW3__UART5_TX 0x00C4 0x040C 0x0000 0x2 0x0 ++#define MX6SX_PAD_KEY_ROW3__CAN2_RX 0x00C4 0x040C 0x0690 0x3 0x1 ++#define MX6SX_PAD_KEY_ROW3__CANFD_RX2 0x00C4 0x040C 0x0698 0x4 0x1 ++#define MX6SX_PAD_KEY_ROW3__GPIO2_IO_18 0x00C4 0x040C 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_ROW3__WEIM_DTACK_B 0x00C4 0x040C 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_ROW3__ECSPI1_SS1 0x00C4 0x040C 0x0000 0x7 0x0 ++#define MX6SX_PAD_KEY_ROW4__KPP_ROW_4 0x00C8 0x0410 0x0000 0x0 0x0 ++#define MX6SX_PAD_KEY_ROW4__ENET2_MDIO 0x00C8 0x0410 0x0770 0x1 0x3 ++#define MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x00C8 0x0410 0x07BC 0x2 0x2 ++#define MX6SX_PAD_KEY_ROW4__USDHC1_LCTL 0x00C8 0x0410 0x0000 0x3 0x0 ++#define MX6SX_PAD_KEY_ROW4__AUDMUX_AUD5_RXFS 0x00C8 0x0410 0x0668 0x4 0x0 ++#define MX6SX_PAD_KEY_ROW4__GPIO2_IO_19 0x00C8 0x0410 0x0000 0x5 0x0 ++#define MX6SX_PAD_KEY_ROW4__WEIM_ACLK_FREERUN 0x00C8 0x0410 0x0000 0x6 0x0 ++#define MX6SX_PAD_KEY_ROW4__SAI2_RX_SYNC 0x00C8 0x0410 0x0810 0x7 0x0 ++#define MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x00CC 0x0414 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_CLK__LCDIF1_WR_RWN 0x00CC 0x0414 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_CLK__AUDMUX_AUD3_RXC 0x00CC 0x0414 0x0634 0x2 0x1 ++#define MX6SX_PAD_LCD1_CLK__ENET1_1588_EVENT2_IN 0x00CC 0x0414 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_CLK__CSI1_DATA_16 0x00CC 0x0414 0x06DC 0x4 0x0 ++#define MX6SX_PAD_LCD1_CLK__GPIO3_IO_0 0x00CC 0x0414 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_CLK__USDHC1_WP 0x00CC 0x0414 0x0868 0x6 0x0 ++#define MX6SX_PAD_LCD1_CLK__SIM_M_HADDR_16 0x00CC 0x0414 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_CLK__VADC_TEST_0 0x00CC 0x0414 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_CLK__MMDC_DEBUG_0 0x00CC 0x0414 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x00D0 0x0418 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA00__WEIM_CS1_B 0x00D0 0x0418 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA00__M4_TRACE_0 0x00D0 0x0418 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA00__KITTEN_TRACE_0 0x00D0 0x0418 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA00__CSI1_DATA_20 0x00D0 0x0418 0x06EC 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA00__GPIO3_IO_1 0x00D0 0x0418 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA00__SRC_BT_CFG_0 0x00D0 0x0418 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA00__SIM_M_HADDR_21 0x00D0 0x0418 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA00__VADC_TEST_5 0x00D0 0x0418 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA00__MMDC_DEBUG_5 0x00D0 0x0418 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x00D4 0x041C 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA01__WEIM_CS2_B 0x00D4 0x041C 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA01__M4_TRACE_1 0x00D4 0x041C 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA01__KITTEN_TRACE_1 0x00D4 0x041C 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA01__CSI1_DATA_21 0x00D4 0x041C 0x06F0 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA01__GPIO3_IO_2 0x00D4 0x041C 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA01__SRC_BT_CFG_1 0x00D4 0x041C 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA01__SIM_M_HADDR_22 0x00D4 0x041C 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA01__VADC_TEST_6 0x00D4 0x041C 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA01__MMDC_DEBUG_6 0x00D4 0x041C 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x00D8 0x0420 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA02__WEIM_CS3_B 0x00D8 0x0420 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA02__M4_TRACE_2 0x00D8 0x0420 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA02__KITTEN_TRACE_2 0x00D8 0x0420 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA02__CSI1_DATA_22 0x00D8 0x0420 0x06F4 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA02__GPIO3_IO_3 0x00D8 0x0420 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA02__SRC_BT_CFG_2 0x00D8 0x0420 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA02__SIM_M_HADDR_23 0x00D8 0x0420 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA02__VADC_TEST_7 0x00D8 0x0420 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA02__MMDC_DEBUG_7 0x00D8 0x0420 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x00DC 0x0424 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA03__WEIM_ADDR_24 0x00DC 0x0424 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA03__M4_TRACE_3 0x00DC 0x0424 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA03__KITTEN_TRACE_3 0x00DC 0x0424 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA03__CSI1_DATA_23 0x00DC 0x0424 0x06F8 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA03__GPIO3_IO_4 0x00DC 0x0424 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA03__SRC_BT_CFG_3 0x00DC 0x0424 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA03__SIM_M_HADDR_24 0x00DC 0x0424 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA03__VADC_TEST_8 0x00DC 0x0424 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA03__MMDC_DEBUG_8 0x00DC 0x0424 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x00E0 0x0428 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA04__WEIM_ADDR_25 0x00E0 0x0428 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA04__KITTEN_TRACE_4 0x00E0 0x0428 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA04__CSI1_VSYNC 0x00E0 0x0428 0x0708 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA04__GPIO3_IO_5 0x00E0 0x0428 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA04__SRC_BT_CFG_4 0x00E0 0x0428 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA04__SIM_M_HADDR_25 0x00E0 0x0428 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA04__VADC_TEST_9 0x00E0 0x0428 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA04__MMDC_DEBUG_9 0x00E0 0x0428 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x00E4 0x042C 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA05__WEIM_ADDR_26 0x00E4 0x042C 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA05__KITTEN_TRACE_5 0x00E4 0x042C 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA05__CSI1_HSYNC 0x00E4 0x042C 0x0700 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA05__GPIO3_IO_6 0x00E4 0x042C 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA05__SRC_BT_CFG_5 0x00E4 0x042C 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA05__SIM_M_HADDR_26 0x00E4 0x042C 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA05__VADC_TEST_10 0x00E4 0x042C 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA05__MMDC_DEBUG_10 0x00E4 0x042C 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x00E8 0x0430 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA06__WEIM_EB_B_2 0x00E8 0x0430 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA06__KITTEN_TRACE_6 0x00E8 0x0430 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA06__CSI1_PIXCLK 0x00E8 0x0430 0x0704 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA06__GPIO3_IO_7 0x00E8 0x0430 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA06__SRC_BT_CFG_6 0x00E8 0x0430 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA06__SIM_M_HADDR_27 0x00E8 0x0430 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA06__VADC_TEST_11 0x00E8 0x0430 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA06__MMDC_DEBUG_11 0x00E8 0x0430 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x00EC 0x0434 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA07__WEIM_EB_B_3 0x00EC 0x0434 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA07__KITTEN_TRACE_7 0x00EC 0x0434 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA07__CSI1_MCLK 0x00EC 0x0434 0x0000 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA07__GPIO3_IO_8 0x00EC 0x0434 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA07__SRC_BT_CFG_7 0x00EC 0x0434 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA07__SIM_M_HADDR_28 0x00EC 0x0434 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA07__VADC_TEST_12 0x00EC 0x0434 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA07__MMDC_DEBUG_12 0x00EC 0x0434 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x00F0 0x0438 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA08__WEIM_AD_8 0x00F0 0x0438 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA08__KITTEN_TRACE_8 0x00F0 0x0438 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA08__CSI1_DATA_9 0x00F0 0x0438 0x06C4 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA08__GPIO3_IO_9 0x00F0 0x0438 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA08__SRC_BT_CFG_8 0x00F0 0x0438 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA08__SIM_M_HADDR_29 0x00F0 0x0438 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA08__VADC_TEST_13 0x00F0 0x0438 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA08__MMDC_DEBUG_13 0x00F0 0x0438 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x00F4 0x043C 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA09__WEIM_AD_9 0x00F4 0x043C 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA09__KITTEN_TRACE_9 0x00F4 0x043C 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA09__CSI1_DATA_8 0x00F4 0x043C 0x06C0 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA09__GPIO3_IO_10 0x00F4 0x043C 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA09__SRC_BT_CFG_9 0x00F4 0x043C 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA09__SIM_M_HADDR_30 0x00F4 0x043C 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA09__VADC_TEST_14 0x00F4 0x043C 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA09__MMDC_DEBUG_14 0x00F4 0x043C 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x00F8 0x0440 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA10__WEIM_AD_10 0x00F8 0x0440 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA10__KITTEN_TRACE_10 0x00F8 0x0440 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA10__CSI1_DATA_7 0x00F8 0x0440 0x06BC 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA10__GPIO3_IO_11 0x00F8 0x0440 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA10__SRC_BT_CFG_10 0x00F8 0x0440 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA10__SIM_M_HADDR_31 0x00F8 0x0440 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA10__VADC_TEST_15 0x00F8 0x0440 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA10__MMDC_DEBUG_15 0x00F8 0x0440 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x00FC 0x0444 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA11__WEIM_AD_11 0x00FC 0x0444 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA11__KITTEN_TRACE_11 0x00FC 0x0444 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA11__CSI1_DATA_6 0x00FC 0x0444 0x06B8 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA11__GPIO3_IO_12 0x00FC 0x0444 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA11__SRC_BT_CFG_11 0x00FC 0x0444 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA11__SIM_M_HBURST_0 0x00FC 0x0444 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA11__VADC_TEST_16 0x00FC 0x0444 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA11__MMDC_DEBUG_16 0x00FC 0x0444 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x0100 0x0448 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA12__WEIM_AD_12 0x0100 0x0448 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA12__KITTEN_TRACE_12 0x0100 0x0448 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA12__CSI1_DATA_5 0x0100 0x0448 0x06B4 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA12__GPIO3_IO_13 0x0100 0x0448 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA12__SRC_BT_CFG_12 0x0100 0x0448 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA12__SIM_M_HBURST_1 0x0100 0x0448 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA12__VADC_TEST_17 0x0100 0x0448 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA12__MMDC_DEBUG_17 0x0100 0x0448 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x0104 0x044C 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA13__WEIM_AD_13 0x0104 0x044C 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA13__KITTEN_TRACE_13 0x0104 0x044C 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA13__CSI1_DATA_4 0x0104 0x044C 0x06B0 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA13__GPIO3_IO_14 0x0104 0x044C 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA13__SRC_BT_CFG_13 0x0104 0x044C 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA13__SIM_M_HBURST_2 0x0104 0x044C 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA13__VADC_TEST_18 0x0104 0x044C 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA13__MMDC_DEBUG_18 0x0104 0x044C 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x0108 0x0450 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA14__WEIM_AD_14 0x0108 0x0450 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA14__KITTEN_TRACE_14 0x0108 0x0450 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA14__CSI1_DATA_3 0x0108 0x0450 0x06AC 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA14__GPIO3_IO_15 0x0108 0x0450 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA14__SRC_BT_CFG_14 0x0108 0x0450 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA14__SIM_M_HMASTLOCK 0x0108 0x0450 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA14__VADC_TEST_19 0x0108 0x0450 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA14__MMDC_DEBUG_19 0x0108 0x0450 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x010C 0x0454 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA15__WEIM_AD_15 0x010C 0x0454 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA15__KITTEN_TRACE_15 0x010C 0x0454 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA15__CSI1_DATA_2 0x010C 0x0454 0x06A8 0x4 0x1 ++#define MX6SX_PAD_LCD1_DATA15__GPIO3_IO_16 0x010C 0x0454 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA15__SRC_BT_CFG_15 0x010C 0x0454 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA15__SIM_M_HPROT_0 0x010C 0x0454 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA15__VDEC_DEBUG_0 0x010C 0x0454 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA15__MMDC_DEBUG_20 0x010C 0x0454 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x0110 0x0458 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA16__WEIM_ADDR_16 0x0110 0x0458 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA16__M4_TRACE_CLK 0x0110 0x0458 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA16__KITTEN_TRACE_CLK 0x0110 0x0458 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA16__CSI1_DATA_1 0x0110 0x0458 0x06A4 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA16__GPIO3_IO_17 0x0110 0x0458 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA16__SRC_BT_CFG_24 0x0110 0x0458 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA16__SIM_M_HPROT_1 0x0110 0x0458 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA16__VDEC_DEBUG_1 0x0110 0x0458 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA16__MMDC_DEBUG_21 0x0110 0x0458 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x0114 0x045C 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA17__WEIM_ADDR_17 0x0114 0x045C 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA17__KITTEN_TRACE_CTL 0x0114 0x045C 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA17__CSI1_DATA_0 0x0114 0x045C 0x06A0 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA17__GPIO3_IO_18 0x0114 0x045C 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA17__SRC_BT_CFG_25 0x0114 0x045C 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA17__SIM_M_HPROT_2 0x0114 0x045C 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA17__VDEC_DEBUG_2 0x0114 0x045C 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA17__MMDC_DEBUG_22 0x0114 0x045C 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x0118 0x0460 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA18__WEIM_ADDR_18 0x0118 0x0460 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA18__M4_EVENTO 0x0118 0x0460 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA18__KITTEN_EVENTO 0x0118 0x0460 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA18__CSI1_DATA_15 0x0118 0x0460 0x06D8 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA18__GPIO3_IO_19 0x0118 0x0460 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA18__SRC_BT_CFG_26 0x0118 0x0460 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA18__SIM_M_HPROT_3 0x0118 0x0460 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA18__VDEC_DEBUG_3 0x0118 0x0460 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA18__MMDC_DEBUG_23 0x0118 0x0460 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x011C 0x0464 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA19__WEIM_ADDR_19 0x011C 0x0464 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA19__M4_TRACE_SWO 0x011C 0x0464 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA19__CSI1_DATA_14 0x011C 0x0464 0x06D4 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA19__GPIO3_IO_20 0x011C 0x0464 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA19__SRC_BT_CFG_27 0x011C 0x0464 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA19__SIM_M_HREADYOUT 0x011C 0x0464 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA19__VDEC_DEBUG_4 0x011C 0x0464 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA19__MMDC_DEBUG_24 0x011C 0x0464 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x0120 0x0468 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA20__WEIM_ADDR_20 0x0120 0x0468 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA20__PWM8_OUT 0x0120 0x0468 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA20__ENET1_1588_EVENT2_OUT 0x0120 0x0468 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA20__CSI1_DATA_13 0x0120 0x0468 0x06D0 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA20__GPIO3_IO_21 0x0120 0x0468 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA20__SRC_BT_CFG_28 0x0120 0x0468 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA20__SIM_M_HRESP 0x0120 0x0468 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA20__VDEC_DEBUG_5 0x0120 0x0468 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA20__MMDC_DEBUG_25 0x0120 0x0468 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x0124 0x046C 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA21__WEIM_ADDR_21 0x0124 0x046C 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA21__PWM7_OUT 0x0124 0x046C 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA21__ENET1_1588_EVENT3_OUT 0x0124 0x046C 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA21__CSI1_DATA_12 0x0124 0x046C 0x06CC 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA21__GPIO3_IO_22 0x0124 0x046C 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA21__SRC_BT_CFG_29 0x0124 0x046C 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA21__SIM_M_HSIZE_0 0x0124 0x046C 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA21__VDEC_DEBUG_6 0x0124 0x046C 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA21__MMDC_DEBUG_26 0x0124 0x046C 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x0128 0x0470 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA22__WEIM_ADDR_22 0x0128 0x0470 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA22__PWM6_OUT 0x0128 0x0470 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA22__ENET2_1588_EVENT2_OUT 0x0128 0x0470 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA22__CSI1_DATA_11 0x0128 0x0470 0x06C8 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA22__GPIO3_IO_23 0x0128 0x0470 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA22__SRC_BT_CFG_30 0x0128 0x0470 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA22__SIM_M_HSIZE_1 0x0128 0x0470 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA22__VDEC_DEBUG_7 0x0128 0x0470 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA22__MMDC_DEBUG_27 0x0128 0x0470 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x012C 0x0474 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_DATA23__WEIM_ADDR_23 0x012C 0x0474 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_DATA23__PWM5_OUT 0x012C 0x0474 0x0000 0x2 0x0 ++#define MX6SX_PAD_LCD1_DATA23__ENET2_1588_EVENT3_OUT 0x012C 0x0474 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_DATA23__CSI1_DATA_10 0x012C 0x0474 0x06FC 0x4 0x0 ++#define MX6SX_PAD_LCD1_DATA23__GPIO3_IO_24 0x012C 0x0474 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_DATA23__SRC_BT_CFG_31 0x012C 0x0474 0x0000 0x6 0x0 ++#define MX6SX_PAD_LCD1_DATA23__SIM_M_HSIZE_2 0x012C 0x0474 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_DATA23__VDEC_DEBUG_8 0x012C 0x0474 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_DATA23__MMDC_DEBUG_28 0x012C 0x0474 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x0130 0x0478 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__LCDIF1_RD_E 0x0130 0x0478 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__AUDMUX_AUD3_TXC 0x0130 0x0478 0x063C 0x2 0x1 ++#define MX6SX_PAD_LCD1_ENABLE__ENET1_1588_EVENT3_IN 0x0130 0x0478 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__CSI1_DATA_17 0x0130 0x0478 0x06E0 0x4 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__GPIO3_IO_25 0x0130 0x0478 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__USDHC1_CD_B 0x0130 0x0478 0x0864 0x6 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__SIM_M_HADDR_17 0x0130 0x0478 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__VADC_TEST_1 0x0130 0x0478 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_ENABLE__MMDC_DEBUG_1 0x0130 0x0478 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x0134 0x047C 0x07E0 0x0 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__LCDIF1_RS 0x0134 0x047C 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__AUDMUX_AUD3_TXD 0x0134 0x047C 0x0630 0x2 0x1 ++#define MX6SX_PAD_LCD1_HSYNC__ENET2_1588_EVENT2_IN 0x0134 0x047C 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__CSI1_DATA_18 0x0134 0x047C 0x06E4 0x4 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__GPIO3_IO_26 0x0134 0x047C 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__USDHC2_WP 0x0134 0x047C 0x0870 0x6 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__SIM_M_HADDR_18 0x0134 0x047C 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__VADC_TEST_2 0x0134 0x047C 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_HSYNC__MMDC_DEBUG_2 0x0134 0x047C 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_RESET__LCDIF1_RESET 0x0138 0x0480 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_RESET__LCDIF1_CS 0x0138 0x0480 0x0000 0x1 0x0 ++#define MX6SX_PAD_LCD1_RESET__AUDMUX_AUD3_RXD 0x0138 0x0480 0x062C 0x2 0x1 ++#define MX6SX_PAD_LCD1_RESET__KITTEN_EVENTI 0x0138 0x0480 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_RESET__M4_EVENTI 0x0138 0x0480 0x0000 0x4 0x0 ++#define MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x0138 0x0480 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_RESET__CCM_PMIC_RDY 0x0138 0x0480 0x069C 0x6 0x0 ++#define MX6SX_PAD_LCD1_RESET__SIM_M_HADDR_20 0x0138 0x0480 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_RESET__VADC_TEST_4 0x0138 0x0480 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_RESET__MMDC_DEBUG_4 0x0138 0x0480 0x0000 0x9 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x013C 0x0484 0x0000 0x0 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__LCDIF1_BUSY 0x013C 0x0484 0x07E0 0x1 0x1 ++#define MX6SX_PAD_LCD1_VSYNC__AUDMUX_AUD3_TXFS 0x013C 0x0484 0x0640 0x2 0x1 ++#define MX6SX_PAD_LCD1_VSYNC__ENET2_1588_EVENT3_IN 0x013C 0x0484 0x0000 0x3 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__CSI1_DATA_19 0x013C 0x0484 0x06E8 0x4 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__GPIO3_IO_28 0x013C 0x0484 0x0000 0x5 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__USDHC2_CD_B 0x013C 0x0484 0x086C 0x6 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__SIM_M_HADDR_19 0x013C 0x0484 0x0000 0x7 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__VADC_TEST_3 0x013C 0x0484 0x0000 0x8 0x0 ++#define MX6SX_PAD_LCD1_VSYNC__MMDC_DEBUG_3 0x013C 0x0484 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_ALE__RAWNAND_ALE 0x0140 0x0488 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_ALE__I2C3_SDA 0x0140 0x0488 0x07BC 0x1 0x0 ++#define MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B 0x0140 0x0488 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_ALE__ECSPI2_SS0 0x0140 0x0488 0x072C 0x3 0x0 ++#define MX6SX_PAD_NAND_ALE__ESAI_TX3_RX2 0x0140 0x0488 0x079C 0x4 0x0 ++#define MX6SX_PAD_NAND_ALE__GPIO4_IO_0 0x0140 0x0488 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_ALE__WEIM_CS0_B 0x0140 0x0488 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_ALE__TPSMP_HDATA_0 0x0140 0x0488 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_ALE__ANATOP_USBPHY1_TSTI_TX_EN 0x0140 0x0488 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_ALE__SDMA_DEBUG_PC_12 0x0140 0x0488 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_CE0_B__RAWNAND_CE0_B 0x0144 0x048C 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_CE0_B__USDHC2_VSELECT 0x0144 0x048C 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2 0x0144 0x048C 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_CE0_B__AUDMUX_AUD4_TXC 0x0144 0x048C 0x0654 0x3 0x0 ++#define MX6SX_PAD_NAND_CE0_B__ESAI_TX_CLK 0x0144 0x048C 0x078C 0x4 0x0 ++#define MX6SX_PAD_NAND_CE0_B__GPIO4_IO_1 0x0144 0x048C 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_CE0_B__WEIM_LBA_B 0x0144 0x048C 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_CE0_B__TPSMP_HDATA_3 0x0144 0x048C 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_CE0_B__ANATOP_USBPHY1_TSTI_TX_HIZ 0x0144 0x048C 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_CE0_B__SDMA_DEBUG_PC_9 0x0144 0x048C 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_CE1_B__RAWNAND_CE1_B 0x0148 0x0490 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_CE1_B__USDHC3_RESET_B 0x0148 0x0490 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3 0x0148 0x0490 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_CE1_B__AUDMUX_AUD4_TXD 0x0148 0x0490 0x0648 0x3 0x0 ++#define MX6SX_PAD_NAND_CE1_B__ESAI_TX0 0x0148 0x0490 0x0790 0x4 0x0 ++#define MX6SX_PAD_NAND_CE1_B__GPIO4_IO_2 0x0148 0x0490 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_CE1_B__WEIM_OE 0x0148 0x0490 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_CE1_B__TPSMP_HDATA_4 0x0148 0x0490 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_CE1_B__ANATOP_USBPHY1_TSTI_TX_LS_MODE 0x0148 0x0490 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_CE1_B__SDMA_DEBUG_PC_8 0x0148 0x0490 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_CLE__RAWNAND_CLE 0x014C 0x0494 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_CLE__I2C3_SCL 0x014C 0x0494 0x07B8 0x1 0x0 ++#define MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK 0x014C 0x0494 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_CLE__ECSPI2_SCLK 0x014C 0x0494 0x0720 0x3 0x0 ++#define MX6SX_PAD_NAND_CLE__ESAI_TX2_RX3 0x014C 0x0494 0x0798 0x4 0x0 ++#define MX6SX_PAD_NAND_CLE__GPIO4_IO_3 0x014C 0x0494 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_CLE__WEIM_BCLK 0x014C 0x0494 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_CLE__TPSMP_CLK 0x014C 0x0494 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_CLE__ANATOP_USBPHY1_TSTI_TX_DP 0x014C 0x0494 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_CLE__SDMA_DEBUG_PC_13 0x014C 0x0494 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA00__RAWNAND_DATA00 0x0150 0x0498 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA00__USDHC1_DATA4 0x0150 0x0498 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA00__QSPI2_B_DATA_1 0x0150 0x0498 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA00__ECSPI5_MISO 0x0150 0x0498 0x0754 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA00__ESAI_RX_CLK 0x0150 0x0498 0x0788 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA00__GPIO4_IO_4 0x0150 0x0498 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA00__WEIM_AD_0 0x0150 0x0498 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA00__TPSMP_HDATA_7 0x0150 0x0498 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA00__ANATOP_USBPHY1_TSTO_RX_DISCON_DET 0x0150 0x0498 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA00__SDMA_DEBUG_EVT_CHN_LINES_5 0x0150 0x0498 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA01__RAWNAND_DATA01 0x0154 0x049C 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA01__USDHC1_DATA5 0x0154 0x049C 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA01__QSPI2_B_DATA_0 0x0154 0x049C 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA01__ECSPI5_MOSI 0x0154 0x049C 0x0758 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA01__ESAI_RX_FS 0x0154 0x049C 0x0778 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA01__GPIO4_IO_5 0x0154 0x049C 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA01__WEIM_AD_1 0x0154 0x049C 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA01__TPSMP_HDATA_8 0x0154 0x049C 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA01__ANATOP_USBPHY1_TSTO_RX_HS_RXD 0x0154 0x049C 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA01__SDMA_DEBUG_EVT_CHN_LINES_4 0x0154 0x049C 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA02__RAWNAND_DATA02 0x0158 0x04A0 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA02__USDHC1_DATA6 0x0158 0x04A0 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA02__QSPI2_B_SCLK 0x0158 0x04A0 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA02__ECSPI5_SCLK 0x0158 0x04A0 0x0750 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA02__ESAI_TX_HF_CLK 0x0158 0x04A0 0x0784 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA02__GPIO4_IO_6 0x0158 0x04A0 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA02__WEIM_AD_2 0x0158 0x04A0 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA02__TPSMP_HDATA_9 0x0158 0x04A0 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA02__ANATOP_USBPHY2_TSTO_PLL_CLK20DIV 0x0158 0x04A0 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA02__SDMA_DEBUG_EVT_CHN_LINES_3 0x0158 0x04A0 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA03__RAWNAND_DATA03 0x015C 0x04A4 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA03__USDHC1_DATA7 0x015C 0x04A4 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA03__QSPI2_B_SS0_B 0x015C 0x04A4 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA03__ECSPI5_SS0 0x015C 0x04A4 0x075C 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA03__ESAI_RX_HF_CLK 0x015C 0x04A4 0x0780 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA03__GPIO4_IO_7 0x015C 0x04A4 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA03__WEIM_AD_3 0x015C 0x04A4 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA03__TPSMP_HDATA_10 0x015C 0x04A4 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA03__ANATOP_USBPHY1_TSTO_RX_SQUELCH 0x015C 0x04A4 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA03__SDMA_DEBUG_EVT_CHN_LINES_6 0x015C 0x04A4 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04 0x0160 0x04A8 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA04__USDHC2_DATA4 0x0160 0x04A8 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA04__QSPI2_B_SS1_B 0x0160 0x04A8 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA04__UART3_RTS_B 0x0160 0x04A8 0x083C 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA04__UART3_CTS_B 0x0160 0x04A8 0x0000 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA04__AUDMUX_AUD4_RXFS 0x0160 0x04A8 0x0650 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA04__GPIO4_IO_8 0x0160 0x04A8 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA04__WEIM_AD_4 0x0160 0x04A8 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA04__TPSMP_HDATA_11 0x0160 0x04A8 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA04__ANATOP_USBPHY2_TSTO_RX_SQUELCH 0x0160 0x04A8 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA04__SDMA_DEBUG_CORE_STATE_0 0x0160 0x04A8 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0x0164 0x04AC 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA05__USDHC2_DATA5 0x0164 0x04AC 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA05__QSPI2_B_DQS 0x0164 0x04AC 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA05__UART3_CTS_B 0x0164 0x04AC 0x0000 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA05__UART3_RTS_B 0x0164 0x04AC 0x083C 0x3 0x1 ++#define MX6SX_PAD_NAND_DATA05__AUDMUX_AUD4_RXC 0x0164 0x04AC 0x064C 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA05__GPIO4_IO_9 0x0164 0x04AC 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA05__WEIM_AD_5 0x0164 0x04AC 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA05__TPSMP_HDATA_12 0x0164 0x04AC 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA05__ANATOP_USBPHY2_TSTO_RX_DISCON_DET 0x0164 0x04AC 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA05__SDMA_DEBUG_CORE_STATE_1 0x0164 0x04AC 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06 0x0168 0x04B0 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA06__USDHC2_DATA6 0x0168 0x04B0 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA06__QSPI2_A_SS1_B 0x0168 0x04B0 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA06__UART3_RX 0x0168 0x04B0 0x0840 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA06__UART3_TX 0x0168 0x04B0 0x0000 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA06__PWM3_OUT 0x0168 0x04B0 0x0000 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA06__GPIO4_IO_10 0x0168 0x04B0 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA06__WEIM_AD_6 0x0168 0x04B0 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA06__TPSMP_HDATA_13 0x0168 0x04B0 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA06__ANATOP_USBPHY2_TSTO_RX_FS_RXD 0x0168 0x04B0 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA06__SDMA_DEBUG_CORE_STATE_2 0x0168 0x04B0 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07 0x016C 0x04B4 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_DATA07__USDHC2_DATA7 0x016C 0x04B4 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_DATA07__QSPI2_A_DQS 0x016C 0x04B4 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_DATA07__UART3_RX 0x016C 0x04B4 0x0840 0x3 0x1 ++#define MX6SX_PAD_NAND_DATA07__UART3_TX 0x016C 0x04B4 0x0000 0x3 0x0 ++#define MX6SX_PAD_NAND_DATA07__PWM4_OUT 0x016C 0x04B4 0x0000 0x4 0x0 ++#define MX6SX_PAD_NAND_DATA07__GPIO4_IO_11 0x016C 0x04B4 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_DATA07__WEIM_AD_7 0x016C 0x04B4 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_DATA07__TPSMP_HDATA_14 0x016C 0x04B4 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_DATA07__ANATOP_USBPHY1_TSTO_RX_FS_RXD 0x016C 0x04B4 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_DATA07__SDMA_DEBUG_CORE_STATE_3 0x016C 0x04B4 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_RE_B__RAWNAND_RE_B 0x0170 0x04B8 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_RE_B__USDHC2_RESET_B 0x0170 0x04B8 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_RE_B__QSPI2_B_DATA_3 0x0170 0x04B8 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_RE_B__AUDMUX_AUD4_TXFS 0x0170 0x04B8 0x0658 0x3 0x0 ++#define MX6SX_PAD_NAND_RE_B__ESAI_TX_FS 0x0170 0x04B8 0x077C 0x4 0x0 ++#define MX6SX_PAD_NAND_RE_B__GPIO4_IO_12 0x0170 0x04B8 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_RE_B__WEIM_RW 0x0170 0x04B8 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_RE_B__TPSMP_HDATA_5 0x0170 0x04B8 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_RE_B__ANATOP_USBPHY2_TSTO_RX_HS_RXD 0x0170 0x04B8 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_RE_B__SDMA_DEBUG_PC_7 0x0170 0x04B8 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_READY_B__RAWNAND_READY_B 0x0174 0x04BC 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_READY_B__USDHC1_VSELECT 0x0174 0x04BC 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1 0x0174 0x04BC 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_READY_B__ECSPI2_MISO 0x0174 0x04BC 0x0724 0x3 0x0 ++#define MX6SX_PAD_NAND_READY_B__ESAI_TX1 0x0174 0x04BC 0x0794 0x4 0x0 ++#define MX6SX_PAD_NAND_READY_B__GPIO4_IO_13 0x0174 0x04BC 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_READY_B__WEIM_EB_B_1 0x0174 0x04BC 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_READY_B__TPSMP_HDATA_2 0x0174 0x04BC 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_READY_B__ANATOP_USBPHY1_TSTI_TX_DN 0x0174 0x04BC 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_READY_B__SDMA_DEBUG_PC_10 0x0174 0x04BC 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_WE_B__RAWNAND_WE_B 0x0178 0x04C0 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_WE_B__USDHC4_VSELECT 0x0178 0x04C0 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_WE_B__QSPI2_B_DATA_2 0x0178 0x04C0 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_WE_B__AUDMUX_AUD4_RXD 0x0178 0x04C0 0x0644 0x3 0x0 ++#define MX6SX_PAD_NAND_WE_B__ESAI_TX5_RX0 0x0178 0x04C0 0x07A4 0x4 0x0 ++#define MX6SX_PAD_NAND_WE_B__GPIO4_IO_14 0x0178 0x04C0 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_WE_B__WEIM_WAIT 0x0178 0x04C0 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_WE_B__TPSMP_HDATA_6 0x0178 0x04C0 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_WE_B__ANATOP_USBPHY1_TSTO_PLL_CLK20DIV 0x0178 0x04C0 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_WE_B__SDMA_DEBUG_PC_6 0x0178 0x04C0 0x0000 0x9 0x0 ++#define MX6SX_PAD_NAND_WP_B__RAWNAND_WP_B 0x017C 0x04C4 0x0000 0x0 0x0 ++#define MX6SX_PAD_NAND_WP_B__USDHC1_RESET_B 0x017C 0x04C4 0x0000 0x1 0x0 ++#define MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0 0x017C 0x04C4 0x0000 0x2 0x0 ++#define MX6SX_PAD_NAND_WP_B__ECSPI2_MOSI 0x017C 0x04C4 0x0728 0x3 0x0 ++#define MX6SX_PAD_NAND_WP_B__ESAI_TX4_RX1 0x017C 0x04C4 0x07A0 0x4 0x0 ++#define MX6SX_PAD_NAND_WP_B__GPIO4_IO_15 0x017C 0x04C4 0x0000 0x5 0x0 ++#define MX6SX_PAD_NAND_WP_B__WEIM_EB_B_0 0x017C 0x04C4 0x0000 0x6 0x0 ++#define MX6SX_PAD_NAND_WP_B__TPSMP_HDATA_1 0x017C 0x04C4 0x0000 0x7 0x0 ++#define MX6SX_PAD_NAND_WP_B__ANATOP_USBPHY1_TSTI_TX_HS_MODE 0x017C 0x04C4 0x0000 0x8 0x0 ++#define MX6SX_PAD_NAND_WP_B__SDMA_DEBUG_PC_11 0x017C 0x04C4 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_DATA0__QSPI1_A_DATA_0 0x0180 0x04C8 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_DATA0__USB_OTG2_OC 0x0180 0x04C8 0x085C 0x1 0x2 ++#define MX6SX_PAD_QSPI1A_DATA0__ECSPI1_MOSI 0x0180 0x04C8 0x0718 0x2 0x1 ++#define MX6SX_PAD_QSPI1A_DATA0__ESAI_TX4_RX1 0x0180 0x04C8 0x07A0 0x3 0x2 ++#define MX6SX_PAD_QSPI1A_DATA0__CSI1_DATA_14 0x0180 0x04C8 0x06D4 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_DATA0__GPIO4_IO_16 0x0180 0x04C8 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_DATA0__WEIM_DATA_6 0x0180 0x04C8 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_DATA0__SIM_M_HADDR_3 0x0180 0x04C8 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_DATA0__SDMA_DEBUG_BUS_DEVICE_3 0x0180 0x04C8 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_DATA1__QSPI1_A_DATA_1 0x0184 0x04CC 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_DATA1__ANATOP_OTG1_ID 0x0184 0x04CC 0x0624 0x1 0x2 ++#define MX6SX_PAD_QSPI1A_DATA1__ECSPI1_MISO 0x0184 0x04CC 0x0714 0x2 0x1 ++#define MX6SX_PAD_QSPI1A_DATA1__ESAI_TX1 0x0184 0x04CC 0x0794 0x3 0x2 ++#define MX6SX_PAD_QSPI1A_DATA1__CSI1_DATA_13 0x0184 0x04CC 0x06D0 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_DATA1__GPIO4_IO_17 0x0184 0x04CC 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_DATA1__WEIM_DATA_5 0x0184 0x04CC 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_DATA1__SIM_M_HADDR_4 0x0184 0x04CC 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_DATA1__SDMA_DEBUG_PC_0 0x0184 0x04CC 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_DATA2__QSPI1_A_DATA_2 0x0188 0x04D0 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_DATA2__USB_OTG1_PWR 0x0188 0x04D0 0x0000 0x1 0x0 ++#define MX6SX_PAD_QSPI1A_DATA2__ECSPI5_SS1 0x0188 0x04D0 0x0000 0x2 0x0 ++#define MX6SX_PAD_QSPI1A_DATA2__ESAI_TX_CLK 0x0188 0x04D0 0x078C 0x3 0x2 ++#define MX6SX_PAD_QSPI1A_DATA2__CSI1_DATA_12 0x0188 0x04D0 0x06CC 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_DATA2__GPIO4_IO_18 0x0188 0x04D0 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_DATA2__WEIM_DATA_4 0x0188 0x04D0 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_DATA2__SIM_M_HADDR_6 0x0188 0x04D0 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_DATA2__SDMA_DEBUG_PC_1 0x0188 0x04D0 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_DATA3__QSPI1_A_DATA_3 0x018C 0x04D4 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_DATA3__USB_OTG1_OC 0x018C 0x04D4 0x0860 0x1 0x2 ++#define MX6SX_PAD_QSPI1A_DATA3__ECSPI5_SS2 0x018C 0x04D4 0x0000 0x2 0x0 ++#define MX6SX_PAD_QSPI1A_DATA3__ESAI_TX0 0x018C 0x04D4 0x0790 0x3 0x2 ++#define MX6SX_PAD_QSPI1A_DATA3__CSI1_DATA_11 0x018C 0x04D4 0x06C8 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_DATA3__GPIO4_IO_19 0x018C 0x04D4 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_DATA3__WEIM_DATA_3 0x018C 0x04D4 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_DATA3__SIM_M_HADDR_7 0x018C 0x04D4 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_DATA3__SDMA_DEBUG_PC_2 0x018C 0x04D4 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_DQS__QSPI1_A_DQS 0x0190 0x04D8 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x0190 0x04D8 0x0000 0x1 0x0 ++#define MX6SX_PAD_QSPI1A_DQS__CANFD_TX2 0x0190 0x04D8 0x0000 0x2 0x0 ++#define MX6SX_PAD_QSPI1A_DQS__ECSPI5_MOSI 0x0190 0x04D8 0x0758 0x3 0x1 ++#define MX6SX_PAD_QSPI1A_DQS__CSI1_DATA_15 0x0190 0x04D8 0x06D8 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_DQS__GPIO4_IO_20 0x0190 0x04D8 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_DQS__WEIM_DATA_7 0x0190 0x04D8 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_DQS__SIM_M_HADDR_13 0x0190 0x04D8 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_DQS__SDMA_DEBUG_BUS_DEVICE_4 0x0190 0x04D8 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_SCLK__QSPI1_A_SCLK 0x0194 0x04DC 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_SCLK__ANATOP_OTG2_ID 0x0194 0x04DC 0x0628 0x1 0x2 ++#define MX6SX_PAD_QSPI1A_SCLK__ECSPI1_SCLK 0x0194 0x04DC 0x0710 0x2 0x1 ++#define MX6SX_PAD_QSPI1A_SCLK__ESAI_TX2_RX3 0x0194 0x04DC 0x0798 0x3 0x2 ++#define MX6SX_PAD_QSPI1A_SCLK__CSI1_DATA_1 0x0194 0x04DC 0x06A4 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_SCLK__GPIO4_IO_21 0x0194 0x04DC 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_SCLK__WEIM_DATA_0 0x0194 0x04DC 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_SCLK__SIM_M_HADDR_0 0x0194 0x04DC 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_SCLK__SDMA_DEBUG_PC_5 0x0194 0x04DC 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_SS0_B__QSPI1_A_SS0_B 0x0198 0x04E0 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_SS0_B__USB_OTG2_PWR 0x0198 0x04E0 0x0000 0x1 0x0 ++#define MX6SX_PAD_QSPI1A_SS0_B__ECSPI1_SS0 0x0198 0x04E0 0x071C 0x2 0x1 ++#define MX6SX_PAD_QSPI1A_SS0_B__ESAI_TX3_RX2 0x0198 0x04E0 0x079C 0x3 0x2 ++#define MX6SX_PAD_QSPI1A_SS0_B__CSI1_DATA_0 0x0198 0x04E0 0x06A0 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_SS0_B__GPIO4_IO_22 0x0198 0x04E0 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_SS0_B__WEIM_DATA_1 0x0198 0x04E0 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_SS0_B__SIM_M_HADDR_1 0x0198 0x04E0 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_SS0_B__SDMA_DEBUG_PC_4 0x0198 0x04E0 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1A_SS1_B__QSPI1_A_SS1_B 0x019C 0x04E4 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x019C 0x04E4 0x068C 0x1 0x2 ++#define MX6SX_PAD_QSPI1A_SS1_B__CANFD_RX1 0x019C 0x04E4 0x0694 0x2 0x2 ++#define MX6SX_PAD_QSPI1A_SS1_B__ECSPI5_MISO 0x019C 0x04E4 0x0754 0x3 0x1 ++#define MX6SX_PAD_QSPI1A_SS1_B__CSI1_DATA_10 0x019C 0x04E4 0x06FC 0x4 0x1 ++#define MX6SX_PAD_QSPI1A_SS1_B__GPIO4_IO_23 0x019C 0x04E4 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1A_SS1_B__WEIM_DATA_2 0x019C 0x04E4 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1A_SS1_B__SIM_M_HADDR_12 0x019C 0x04E4 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1A_SS1_B__SDMA_DEBUG_PC_3 0x019C 0x04E4 0x0000 0x9 0x0 ++#define MX6SX_PAD_QSPI1B_DATA0__QSPI1_B_DATA_0 0x01A0 0x04E8 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B 0x01A0 0x04E8 0x0000 0x1 0x0 ++#define MX6SX_PAD_QSPI1B_DATA0__UART3_RTS_B 0x01A0 0x04E8 0x083C 0x1 0x4 ++#define MX6SX_PAD_QSPI1B_DATA0__ECSPI3_MOSI 0x01A0 0x04E8 0x0738 0x2 0x1 ++#define MX6SX_PAD_QSPI1B_DATA0__ESAI_RX_FS 0x01A0 0x04E8 0x0778 0x3 0x2 ++#define MX6SX_PAD_QSPI1B_DATA0__CSI1_DATA_22 0x01A0 0x04E8 0x06F4 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_DATA0__GPIO4_IO_24 0x01A0 0x04E8 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_DATA0__WEIM_DATA_14 0x01A0 0x04E8 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_DATA0__SIM_M_HADDR_9 0x01A0 0x04E8 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1B_DATA1__QSPI1_B_DATA_1 0x01A4 0x04EC 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_DATA1__UART3_RTS_B 0x01A4 0x04EC 0x083C 0x1 0x5 ++#define MX6SX_PAD_QSPI1B_DATA1__UART3_CTS_B 0x01A4 0x04EC 0x0000 0x1 0x0 ++#define MX6SX_PAD_QSPI1B_DATA1__ECSPI3_MISO 0x01A4 0x04EC 0x0734 0x2 0x1 ++#define MX6SX_PAD_QSPI1B_DATA1__ESAI_RX_CLK 0x01A4 0x04EC 0x0788 0x3 0x2 ++#define MX6SX_PAD_QSPI1B_DATA1__CSI1_DATA_21 0x01A4 0x04EC 0x06F0 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_DATA1__GPIO4_IO_25 0x01A4 0x04EC 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_DATA1__WEIM_DATA_13 0x01A4 0x04EC 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_DATA1__SIM_M_HADDR_8 0x01A4 0x04EC 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1B_DATA2__QSPI1_B_DATA_2 0x01A8 0x04F0 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_DATA2__I2C2_SDA 0x01A8 0x04F0 0x07B4 0x1 0x2 ++#define MX6SX_PAD_QSPI1B_DATA2__ECSPI5_RDY 0x01A8 0x04F0 0x0000 0x2 0x0 ++#define MX6SX_PAD_QSPI1B_DATA2__ESAI_TX5_RX0 0x01A8 0x04F0 0x07A4 0x3 0x2 ++#define MX6SX_PAD_QSPI1B_DATA2__CSI1_DATA_20 0x01A8 0x04F0 0x06EC 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_DATA2__GPIO4_IO_26 0x01A8 0x04F0 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_DATA2__WEIM_DATA_12 0x01A8 0x04F0 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_DATA2__SIM_M_HADDR_5 0x01A8 0x04F0 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1B_DATA3__QSPI1_B_DATA_3 0x01AC 0x04F4 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_DATA3__I2C2_SCL 0x01AC 0x04F4 0x07B0 0x1 0x2 ++#define MX6SX_PAD_QSPI1B_DATA3__ECSPI5_SS3 0x01AC 0x04F4 0x0000 0x2 0x0 ++#define MX6SX_PAD_QSPI1B_DATA3__ESAI_TX_FS 0x01AC 0x04F4 0x077C 0x3 0x2 ++#define MX6SX_PAD_QSPI1B_DATA3__CSI1_DATA_19 0x01AC 0x04F4 0x06E8 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_DATA3__GPIO4_IO_27 0x01AC 0x04F4 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_DATA3__WEIM_DATA_11 0x01AC 0x04F4 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_DATA3__SIM_M_HADDR_2 0x01AC 0x04F4 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1B_DQS__QSPI1_B_DQS 0x01B0 0x04F8 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x01B0 0x04F8 0x0000 0x1 0x0 ++#define MX6SX_PAD_QSPI1B_DQS__CANFD_TX1 0x01B0 0x04F8 0x0000 0x2 0x0 ++#define MX6SX_PAD_QSPI1B_DQS__ECSPI5_SS0 0x01B0 0x04F8 0x075C 0x3 0x1 ++#define MX6SX_PAD_QSPI1B_DQS__CSI1_DATA_23 0x01B0 0x04F8 0x06F8 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_DQS__GPIO4_IO_28 0x01B0 0x04F8 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_DQS__WEIM_DATA_15 0x01B0 0x04F8 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_DQS__SIM_M_HADDR_15 0x01B0 0x04F8 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1B_SCLK__QSPI1_B_SCLK 0x01B4 0x04FC 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_SCLK__UART3_RX 0x01B4 0x04FC 0x0840 0x1 0x4 ++#define MX6SX_PAD_QSPI1B_SCLK__UART3_TX 0x01B4 0x04FC 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_SCLK__ECSPI3_SCLK 0x01B4 0x04FC 0x0730 0x2 0x1 ++#define MX6SX_PAD_QSPI1B_SCLK__ESAI_RX_HF_CLK 0x01B4 0x04FC 0x0780 0x3 0x2 ++#define MX6SX_PAD_QSPI1B_SCLK__CSI1_DATA_16 0x01B4 0x04FC 0x06DC 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_SCLK__GPIO4_IO_29 0x01B4 0x04FC 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_SCLK__WEIM_DATA_8 0x01B4 0x04FC 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_SCLK__SIM_M_HADDR_11 0x01B4 0x04FC 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1B_SS0_B__QSPI1_B_SS0_B 0x01B8 0x0500 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_SS0_B__UART3_RX 0x01B8 0x0500 0x0840 0x1 0x5 ++#define MX6SX_PAD_QSPI1B_SS0_B__UART3_TX 0x01B8 0x0500 0x0000 0x1 0x0 ++#define MX6SX_PAD_QSPI1B_SS0_B__ECSPI3_SS0 0x01B8 0x0500 0x073C 0x2 0x1 ++#define MX6SX_PAD_QSPI1B_SS0_B__ESAI_TX_HF_CLK 0x01B8 0x0500 0x0784 0x3 0x3 ++#define MX6SX_PAD_QSPI1B_SS0_B__CSI1_DATA_17 0x01B8 0x0500 0x06E0 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_SS0_B__GPIO4_IO_30 0x01B8 0x0500 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_SS0_B__WEIM_DATA_9 0x01B8 0x0500 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_SS0_B__SIM_M_HADDR_10 0x01B8 0x0500 0x0000 0x7 0x0 ++#define MX6SX_PAD_QSPI1B_SS1_B__QSPI1_B_SS1_B 0x01BC 0x0504 0x0000 0x0 0x0 ++#define MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x01BC 0x0504 0x0690 0x1 0x2 ++#define MX6SX_PAD_QSPI1B_SS1_B__CANFD_RX2 0x01BC 0x0504 0x0698 0x2 0x2 ++#define MX6SX_PAD_QSPI1B_SS1_B__ECSPI5_SCLK 0x01BC 0x0504 0x0750 0x3 0x1 ++#define MX6SX_PAD_QSPI1B_SS1_B__CSI1_DATA_18 0x01BC 0x0504 0x06E4 0x4 0x1 ++#define MX6SX_PAD_QSPI1B_SS1_B__GPIO4_IO_31 0x01BC 0x0504 0x0000 0x5 0x0 ++#define MX6SX_PAD_QSPI1B_SS1_B__WEIM_DATA_10 0x01BC 0x0504 0x0000 0x6 0x0 ++#define MX6SX_PAD_QSPI1B_SS1_B__SIM_M_HADDR_14 0x01BC 0x0504 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x01C0 0x0508 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_RD0__GPIO5_IO_0 0x01C0 0x0508 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_RD0__CSI2_DATA_10 0x01C0 0x0508 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_RD0__ANATOP_TESTI_0 0x01C0 0x0508 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_RD0__RAWNAND_TESTER_TRIGGER 0x01C0 0x0508 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_RD0__PCIE_CTRL_DEBUG_0 0x01C0 0x0508 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x01C4 0x050C 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_RD1__GPIO5_IO_1 0x01C4 0x050C 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_RD1__CSI2_DATA_11 0x01C4 0x050C 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_RD1__ANATOP_TESTI_1 0x01C4 0x050C 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_RD1__USDHC1_TESTER_TRIGGER 0x01C4 0x050C 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_RD1__PCIE_CTRL_DEBUG_1 0x01C4 0x050C 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x01C8 0x0510 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_RD2__GPIO5_IO_2 0x01C8 0x0510 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_RD2__CSI2_DATA_12 0x01C8 0x0510 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_RD2__ANATOP_TESTI_2 0x01C8 0x0510 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_RD2__USDHC2_TESTER_TRIGGER 0x01C8 0x0510 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_RD2__PCIE_CTRL_DEBUG_2 0x01C8 0x0510 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x01CC 0x0514 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_RD3__GPIO5_IO_3 0x01CC 0x0514 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_RD3__CSI2_DATA_13 0x01CC 0x0514 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_RD3__ANATOP_TESTI_3 0x01CC 0x0514 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_RD3__USDHC3_TESTER_TRIGGER 0x01CC 0x0514 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_RD3__PCIE_CTRL_DEBUG_3 0x01CC 0x0514 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x01D0 0x0518 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_RX_CTL__GPIO5_IO_4 0x01D0 0x0518 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_RX_CTL__CSI2_DATA_14 0x01D0 0x0518 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_RX_CTL__ANATOP_TESTO_0 0x01D0 0x0518 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_RX_CTL__USDHC4_TESTER_TRIGGER 0x01D0 0x0518 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_RX_CTL__PCIE_CTRL_DEBUG_4 0x01D0 0x0518 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x01D4 0x051C 0x0768 0x0 0x1 ++#define MX6SX_PAD_RGMII1_RXC__ENET1_RX_ER 0x01D4 0x051C 0x0000 0x1 0x0 ++#define MX6SX_PAD_RGMII1_RXC__GPIO5_IO_5 0x01D4 0x051C 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_RXC__CSI2_DATA_15 0x01D4 0x051C 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_RXC__ANATOP_TESTO_1 0x01D4 0x051C 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_RXC__ECSPI1_TESTER_TRIGGER 0x01D4 0x051C 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_RXC__PCIE_CTRL_DEBUG_5 0x01D4 0x051C 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0x01D8 0x0520 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_TD0__SAI2_RX_SYNC 0x01D8 0x0520 0x0810 0x2 0x1 ++#define MX6SX_PAD_RGMII1_TD0__GPIO5_IO_6 0x01D8 0x0520 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_TD0__CSI2_DATA_16 0x01D8 0x0520 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_TD0__ANATOP_TESTO_2 0x01D8 0x0520 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_TD0__ECSPI2_TESTER_TRIGGER 0x01D8 0x0520 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_TD0__PCIE_CTRL_DEBUG_6 0x01D8 0x0520 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0x01DC 0x0524 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_TD1__SAI2_RX_BCLK 0x01DC 0x0524 0x0808 0x2 0x1 ++#define MX6SX_PAD_RGMII1_TD1__GPIO5_IO_7 0x01DC 0x0524 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_TD1__CSI2_DATA_17 0x01DC 0x0524 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_TD1__ANATOP_TESTO_3 0x01DC 0x0524 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_TD1__ECSPI3_TESTER_TRIGGER 0x01DC 0x0524 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_TD1__PCIE_CTRL_DEBUG_7 0x01DC 0x0524 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0x01E0 0x0528 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_TD2__SAI2_TX_SYNC 0x01E0 0x0528 0x0818 0x2 0x1 ++#define MX6SX_PAD_RGMII1_TD2__GPIO5_IO_8 0x01E0 0x0528 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_TD2__CSI2_DATA_18 0x01E0 0x0528 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_TD2__ANATOP_TESTO_4 0x01E0 0x0528 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_TD2__ECSPI4_TESTER_TRIGGER 0x01E0 0x0528 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_TD2__PCIE_CTRL_DEBUG_8 0x01E0 0x0528 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0x01E4 0x052C 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_TD3__SAI2_TX_BCLK 0x01E4 0x052C 0x0814 0x2 0x1 ++#define MX6SX_PAD_RGMII1_TD3__GPIO5_IO_9 0x01E4 0x052C 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_TD3__CSI2_DATA_19 0x01E4 0x052C 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_TD3__ANATOP_TESTO_5 0x01E4 0x052C 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_TD3__ECSPI5_TESTER_TRIGGER 0x01E4 0x052C 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_TD3__PCIE_CTRL_DEBUG_9 0x01E4 0x052C 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0x01E8 0x0530 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_TX_CTL__SAI2_RX_DATA_0 0x01E8 0x0530 0x080C 0x2 0x1 ++#define MX6SX_PAD_RGMII1_TX_CTL__GPIO5_IO_10 0x01E8 0x0530 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_TX_CTL__CSI2_DATA_0 0x01E8 0x0530 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_TX_CTL__ANATOP_TESTO_6 0x01E8 0x0530 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_TX_CTL__QSPI1_TESTER_TRIGGER 0x01E8 0x0530 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_TX_CTL__PCIE_CTRL_DEBUG_10 0x01E8 0x0530 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0x01EC 0x0534 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII1_TXC__ENET1_TX_ER 0x01EC 0x0534 0x0000 0x1 0x0 ++#define MX6SX_PAD_RGMII1_TXC__SAI2_TX_DATA_0 0x01EC 0x0534 0x0000 0x2 0x0 ++#define MX6SX_PAD_RGMII1_TXC__GPIO5_IO_11 0x01EC 0x0534 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII1_TXC__CSI2_DATA_1 0x01EC 0x0534 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII1_TXC__ANATOP_TESTO_7 0x01EC 0x0534 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII1_TXC__QSPI2_TESTER_TRIGGER 0x01EC 0x0534 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII1_TXC__PCIE_CTRL_DEBUG_11 0x01EC 0x0534 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x01F0 0x0538 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_RD0__PWM4_OUT 0x01F0 0x0538 0x0000 0x2 0x0 ++#define MX6SX_PAD_RGMII2_RD0__GPIO5_IO_12 0x01F0 0x0538 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_RD0__CSI2_DATA_2 0x01F0 0x0538 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_RD0__ANATOP_TESTO_8 0x01F0 0x0538 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_RD0__VDEC_DEBUG_18 0x01F0 0x0538 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_RD0__PCIE_CTRL_DEBUG_12 0x01F0 0x0538 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x01F4 0x053C 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_RD1__PWM3_OUT 0x01F4 0x053C 0x0000 0x2 0x0 ++#define MX6SX_PAD_RGMII2_RD1__GPIO5_IO_13 0x01F4 0x053C 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_RD1__CSI2_DATA_3 0x01F4 0x053C 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_RD1__ANATOP_TESTO_9 0x01F4 0x053C 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_RD1__VDEC_DEBUG_19 0x01F4 0x053C 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_RD1__PCIE_CTRL_DEBUG_13 0x01F4 0x053C 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x01F8 0x0540 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_RD2__PWM2_OUT 0x01F8 0x0540 0x0000 0x2 0x0 ++#define MX6SX_PAD_RGMII2_RD2__GPIO5_IO_14 0x01F8 0x0540 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_RD2__CSI2_DATA_4 0x01F8 0x0540 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_RD2__ANATOP_TESTO_10 0x01F8 0x0540 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_RD2__VDEC_DEBUG_20 0x01F8 0x0540 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_RD2__PCIE_CTRL_DEBUG_14 0x01F8 0x0540 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x01FC 0x0544 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_RD3__PWM1_OUT 0x01FC 0x0544 0x0000 0x2 0x0 ++#define MX6SX_PAD_RGMII2_RD3__GPIO5_IO_15 0x01FC 0x0544 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_RD3__CSI2_DATA_5 0x01FC 0x0544 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_RD3__ANATOP_TESTO_11 0x01FC 0x0544 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_RD3__VDEC_DEBUG_21 0x01FC 0x0544 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_RD3__PCIE_CTRL_DEBUG_15 0x01FC 0x0544 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x0200 0x0548 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_RX_CTL__GPIO5_IO_16 0x0200 0x0548 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_RX_CTL__CSI2_DATA_6 0x0200 0x0548 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_RX_CTL__ANATOP_TESTO_12 0x0200 0x0548 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_RX_CTL__VDEC_DEBUG_22 0x0200 0x0548 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_RX_CTL__PCIE_CTRL_DEBUG_16 0x0200 0x0548 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x0204 0x054C 0x0774 0x0 0x1 ++#define MX6SX_PAD_RGMII2_RXC__ENET2_RX_ER 0x0204 0x054C 0x0000 0x1 0x0 ++#define MX6SX_PAD_RGMII2_RXC__GPIO5_IO_17 0x0204 0x054C 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_RXC__CSI2_DATA_7 0x0204 0x054C 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_RXC__ANATOP_TESTO_13 0x0204 0x054C 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_RXC__VDEC_DEBUG_23 0x0204 0x054C 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_RXC__PCIE_CTRL_DEBUG_17 0x0204 0x054C 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0x0208 0x0550 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_TD0__SAI1_RX_SYNC 0x0208 0x0550 0x07FC 0x2 0x1 ++#define MX6SX_PAD_RGMII2_TD0__PWM8_OUT 0x0208 0x0550 0x0000 0x3 0x0 ++#define MX6SX_PAD_RGMII2_TD0__GPIO5_IO_18 0x0208 0x0550 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_TD0__CSI2_DATA_8 0x0208 0x0550 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_TD0__ANATOP_TESTO_14 0x0208 0x0550 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_TD0__VDEC_DEBUG_24 0x0208 0x0550 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_TD0__PCIE_CTRL_DEBUG_18 0x0208 0x0550 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0x020C 0x0554 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_TD1__SAI1_RX_BCLK 0x020C 0x0554 0x07F4 0x2 0x1 ++#define MX6SX_PAD_RGMII2_TD1__PWM7_OUT 0x020C 0x0554 0x0000 0x3 0x0 ++#define MX6SX_PAD_RGMII2_TD1__GPIO5_IO_19 0x020C 0x0554 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_TD1__CSI2_DATA_9 0x020C 0x0554 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_TD1__ANATOP_TESTO_15 0x020C 0x0554 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_TD1__VDEC_DEBUG_25 0x020C 0x0554 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_TD1__PCIE_CTRL_DEBUG_19 0x020C 0x0554 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0x0210 0x0558 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_TD2__SAI1_TX_SYNC 0x0210 0x0558 0x0804 0x2 0x1 ++#define MX6SX_PAD_RGMII2_TD2__PWM6_OUT 0x0210 0x0558 0x0000 0x3 0x0 ++#define MX6SX_PAD_RGMII2_TD2__GPIO5_IO_20 0x0210 0x0558 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_TD2__CSI2_VSYNC 0x0210 0x0558 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_TD2__SJC_FAIL 0x0210 0x0558 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_TD2__VDEC_DEBUG_26 0x0210 0x0558 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_TD2__PCIE_CTRL_DEBUG_20 0x0210 0x0558 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0x0214 0x055C 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_TD3__SAI1_TX_BCLK 0x0214 0x055C 0x0800 0x2 0x1 ++#define MX6SX_PAD_RGMII2_TD3__PWM5_OUT 0x0214 0x055C 0x0000 0x3 0x0 ++#define MX6SX_PAD_RGMII2_TD3__GPIO5_IO_21 0x0214 0x055C 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_TD3__CSI2_HSYNC 0x0214 0x055C 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_TD3__SJC_JTAG_ACT 0x0214 0x055C 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_TD3__VDEC_DEBUG_27 0x0214 0x055C 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_TD3__PCIE_CTRL_DEBUG_21 0x0214 0x055C 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0x0218 0x0560 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_TX_CTL__SAI1_RX_DATA_0 0x0218 0x0560 0x07F8 0x2 0x1 ++#define MX6SX_PAD_RGMII2_TX_CTL__GPIO5_IO_22 0x0218 0x0560 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_TX_CTL__CSI2_FIELD 0x0218 0x0560 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_TX_CTL__SJC_DE_B 0x0218 0x0560 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_TX_CTL__VDEC_DEBUG_28 0x0218 0x0560 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_TX_CTL__PCIE_CTRL_DEBUG_22 0x0218 0x0560 0x0000 0x9 0x0 ++#define MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0x021C 0x0564 0x0000 0x0 0x0 ++#define MX6SX_PAD_RGMII2_TXC__ENET2_TX_ER 0x021C 0x0564 0x0000 0x1 0x0 ++#define MX6SX_PAD_RGMII2_TXC__SAI1_TX_DATA_0 0x021C 0x0564 0x0000 0x2 0x0 ++#define MX6SX_PAD_RGMII2_TXC__GPIO5_IO_23 0x021C 0x0564 0x0000 0x5 0x0 ++#define MX6SX_PAD_RGMII2_TXC__CSI2_PIXCLK 0x021C 0x0564 0x0000 0x6 0x0 ++#define MX6SX_PAD_RGMII2_TXC__SJC_DONE 0x021C 0x0564 0x0000 0x7 0x0 ++#define MX6SX_PAD_RGMII2_TXC__VDEC_DEBUG_29 0x021C 0x0564 0x0000 0x8 0x0 ++#define MX6SX_PAD_RGMII2_TXC__PCIE_CTRL_DEBUG_23 0x021C 0x0564 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD1_CLK__USDHC1_CLK 0x0220 0x0568 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD1_CLK__AUDMUX_AUD5_RXFS 0x0220 0x0568 0x0668 0x1 0x1 ++#define MX6SX_PAD_SD1_CLK__WDOG2_WDOG_B 0x0220 0x0568 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD1_CLK__GPT_CLK 0x0220 0x0568 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD1_CLK__WDOG2_WDOG_RST_B_DEB 0x0220 0x0568 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD1_CLK__GPIO6_IO_0 0x0220 0x0568 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD1_CLK__ENET2_1588_EVENT1_OUT 0x0220 0x0568 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD1_CLK__CCM_OUT1 0x0220 0x0568 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD1_CLK__VADC_ADC_PROC_CLK 0x0220 0x0568 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD1_CLK__MMDC_DEBUG_45 0x0220 0x0568 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD1_CMD__USDHC1_CMD 0x0224 0x056C 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD1_CMD__AUDMUX_AUD5_RXC 0x0224 0x056C 0x0664 0x1 0x1 ++#define MX6SX_PAD_SD1_CMD__WDOG1_WDOG_B 0x0224 0x056C 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD1_CMD__GPT_COMPARE1 0x0224 0x056C 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD1_CMD__WDOG1_WDOG_RST_B_DEB 0x0224 0x056C 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD1_CMD__GPIO6_IO_1 0x0224 0x056C 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD1_CMD__ENET2_1588_EVENT1_IN 0x0224 0x056C 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD1_CMD__CCM_CLKO1 0x0224 0x056C 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD1_CMD__VADC_EXT_SYSCLK 0x0224 0x056C 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD1_CMD__MMDC_DEBUG_46 0x0224 0x056C 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD1_DATA0__USDHC1_DATA0 0x0228 0x0570 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD1_DATA0__AUDMUX_AUD5_RXD 0x0228 0x0570 0x065C 0x1 0x1 ++#define MX6SX_PAD_SD1_DATA0__CAAM_WRAPPER_RNG_OSC_OBS 0x0228 0x0570 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD1_DATA0__GPT_CAPTURE1 0x0228 0x0570 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD1_DATA0__UART2_RX 0x0228 0x0570 0x0838 0x4 0x2 ++#define MX6SX_PAD_SD1_DATA0__UART2_TX 0x0228 0x0570 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD1_DATA0__GPIO6_IO_2 0x0228 0x0570 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD1_DATA0__ENET1_1588_EVENT1_IN 0x0228 0x0570 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD1_DATA0__CCM_OUT2 0x0228 0x0570 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD1_DATA0__VADC_CLAMP_UP 0x0228 0x0570 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD1_DATA0__MMDC_DEBUG_48 0x0228 0x0570 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD1_DATA1__USDHC1_DATA1 0x022C 0x0574 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD1_DATA1__AUDMUX_AUD5_TXC 0x022C 0x0574 0x066C 0x1 0x1 ++#define MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x022C 0x0574 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD1_DATA1__GPT_CAPTURE2 0x022C 0x0574 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD1_DATA1__UART2_RX 0x022C 0x0574 0x0838 0x4 0x3 ++#define MX6SX_PAD_SD1_DATA1__UART2_TX 0x022C 0x0574 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD1_DATA1__GPIO6_IO_3 0x022C 0x0574 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD1_DATA1__ENET1_1588_EVENT1_OUT 0x022C 0x0574 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD1_DATA1__CCM_CLKO2 0x022C 0x0574 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD1_DATA1__VADC_CLAMP_DOWN 0x022C 0x0574 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD1_DATA1__MMDC_DEBUG_47 0x022C 0x0574 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD1_DATA2__USDHC1_DATA2 0x0230 0x0578 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD1_DATA2__AUDMUX_AUD5_TXFS 0x0230 0x0578 0x0670 0x1 0x1 ++#define MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x0230 0x0578 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD1_DATA2__GPT_COMPARE2 0x0230 0x0578 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD1_DATA2__UART2_CTS_B 0x0230 0x0578 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD1_DATA2__UART2_RTS_B 0x0230 0x0578 0x0834 0x4 0x2 ++#define MX6SX_PAD_SD1_DATA2__GPIO6_IO_4 0x0230 0x0578 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD1_DATA2__ECSPI4_RDY 0x0230 0x0578 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD1_DATA2__CCM_OUT0 0x0230 0x0578 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD1_DATA2__VADC_EXT_PD_N 0x0230 0x0578 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD1_DATA3__USDHC1_DATA3 0x0234 0x057C 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD1_DATA3__AUDMUX_AUD5_TXD 0x0234 0x057C 0x0660 0x1 0x1 ++#define MX6SX_PAD_SD1_DATA3__AUDMUX_AUD5_RXD 0x0234 0x057C 0x065C 0x2 0x2 ++#define MX6SX_PAD_SD1_DATA3__GPT_COMPARE3 0x0234 0x057C 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD1_DATA3__UART2_RTS_B 0x0234 0x057C 0x0834 0x4 0x3 ++#define MX6SX_PAD_SD1_DATA3__UART2_CTS_B 0x0234 0x057C 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD1_DATA3__GPIO6_IO_5 0x0234 0x057C 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD1_DATA3__ECSPI4_SS1 0x0234 0x057C 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD1_DATA3__CCM_PMIC_RDY 0x0234 0x057C 0x069C 0x7 0x2 ++#define MX6SX_PAD_SD1_DATA3__VADC_RST_N 0x0234 0x057C 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x0238 0x0580 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD2_CLK__AUDMUX_AUD6_RXFS 0x0238 0x0580 0x0680 0x1 0x2 ++#define MX6SX_PAD_SD2_CLK__KPP_COL_5 0x0238 0x0580 0x07C8 0x2 0x1 ++#define MX6SX_PAD_SD2_CLK__ECSPI4_SCLK 0x0238 0x0580 0x0740 0x3 0x1 ++#define MX6SX_PAD_SD2_CLK__MLB_SIG 0x0238 0x0580 0x07F0 0x4 0x2 ++#define MX6SX_PAD_SD2_CLK__GPIO6_IO_6 0x0238 0x0580 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD2_CLK__MQS_RIGHT 0x0238 0x0580 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD2_CLK__WDOG1_WDOG_ANY 0x0238 0x0580 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD2_CLK__VADC_CLAMP_CURRENT_5 0x0238 0x0580 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD2_CLK__MMDC_DEBUG_29 0x0238 0x0580 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x023C 0x0584 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD2_CMD__AUDMUX_AUD6_RXC 0x023C 0x0584 0x067C 0x1 0x2 ++#define MX6SX_PAD_SD2_CMD__KPP_ROW_5 0x023C 0x0584 0x07D4 0x2 0x1 ++#define MX6SX_PAD_SD2_CMD__ECSPI4_MOSI 0x023C 0x0584 0x0748 0x3 0x1 ++#define MX6SX_PAD_SD2_CMD__MLB_CLK 0x023C 0x0584 0x07E8 0x4 0x2 ++#define MX6SX_PAD_SD2_CMD__GPIO6_IO_7 0x023C 0x0584 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD2_CMD__MQS_LEFT 0x023C 0x0584 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD2_CMD__WDOG3_WDOG_B 0x023C 0x0584 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD2_CMD__VADC_CLAMP_CURRENT_4 0x023C 0x0584 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD2_CMD__MMDC_DEBUG_30 0x023C 0x0584 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x0240 0x0588 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD2_DATA0__AUDMUX_AUD6_RXD 0x0240 0x0588 0x0674 0x1 0x2 ++#define MX6SX_PAD_SD2_DATA0__KPP_ROW_7 0x0240 0x0588 0x07DC 0x2 0x1 ++#define MX6SX_PAD_SD2_DATA0__PWM1_OUT 0x0240 0x0588 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD2_DATA0__I2C4_SDA 0x0240 0x0588 0x07C4 0x4 0x3 ++#define MX6SX_PAD_SD2_DATA0__GPIO6_IO_8 0x0240 0x0588 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD2_DATA0__ECSPI4_SS3 0x0240 0x0588 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD2_DATA0__UART4_RX 0x0240 0x0588 0x0848 0x7 0x4 ++#define MX6SX_PAD_SD2_DATA0__UART4_TX 0x0240 0x0588 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD2_DATA0__VADC_CLAMP_CURRENT_0 0x0240 0x0588 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD2_DATA0__MMDC_DEBUG_50 0x0240 0x0588 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x0244 0x058C 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD2_DATA1__AUDMUX_AUD6_TXC 0x0244 0x058C 0x0684 0x1 0x2 ++#define MX6SX_PAD_SD2_DATA1__KPP_COL_7 0x0244 0x058C 0x07D0 0x2 0x1 ++#define MX6SX_PAD_SD2_DATA1__PWM2_OUT 0x0244 0x058C 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD2_DATA1__I2C4_SCL 0x0244 0x058C 0x07C0 0x4 0x3 ++#define MX6SX_PAD_SD2_DATA1__GPIO6_IO_9 0x0244 0x058C 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD2_DATA1__ECSPI4_SS2 0x0244 0x058C 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD2_DATA1__UART4_RX 0x0244 0x058C 0x0848 0x7 0x5 ++#define MX6SX_PAD_SD2_DATA1__UART4_TX 0x0244 0x058C 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD2_DATA1__VADC_CLAMP_CURRENT_1 0x0244 0x058C 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD2_DATA1__MMDC_DEBUG_49 0x0244 0x058C 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x0248 0x0590 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD2_DATA2__AUDMUX_AUD6_TXFS 0x0248 0x0590 0x0688 0x1 0x2 ++#define MX6SX_PAD_SD2_DATA2__KPP_ROW_6 0x0248 0x0590 0x07D8 0x2 0x1 ++#define MX6SX_PAD_SD2_DATA2__ECSPI4_SS0 0x0248 0x0590 0x074C 0x3 0x1 ++#define MX6SX_PAD_SD2_DATA2__SDMA_EXT_EVENT_0 0x0248 0x0590 0x081C 0x4 0x2 ++#define MX6SX_PAD_SD2_DATA2__GPIO6_IO_10 0x0248 0x0590 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD2_DATA2__SPDIF_OUT 0x0248 0x0590 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD2_DATA2__UART6_RX 0x0248 0x0590 0x0858 0x7 0x4 ++#define MX6SX_PAD_SD2_DATA2__UART6_TX 0x0248 0x0590 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD2_DATA2__VADC_CLAMP_CURRENT_2 0x0248 0x0590 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD2_DATA2__MMDC_DEBUG_32 0x0248 0x0590 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x024C 0x0594 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD2_DATA3__AUDMUX_AUD6_TXD 0x024C 0x0594 0x0678 0x1 0x2 ++#define MX6SX_PAD_SD2_DATA3__KPP_COL_6 0x024C 0x0594 0x07CC 0x2 0x1 ++#define MX6SX_PAD_SD2_DATA3__ECSPI4_MISO 0x024C 0x0594 0x0744 0x3 0x1 ++#define MX6SX_PAD_SD2_DATA3__MLB_DATA 0x024C 0x0594 0x07EC 0x4 0x2 ++#define MX6SX_PAD_SD2_DATA3__GPIO6_IO_11 0x024C 0x0594 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD2_DATA3__SPDIF_IN 0x024C 0x0594 0x0824 0x6 0x4 ++#define MX6SX_PAD_SD2_DATA3__UART6_RX 0x024C 0x0594 0x0858 0x7 0x5 ++#define MX6SX_PAD_SD2_DATA3__UART6_TX 0x024C 0x0594 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD2_DATA3__VADC_CLAMP_CURRENT_3 0x024C 0x0594 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD2_DATA3__MMDC_DEBUG_31 0x024C 0x0594 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x0250 0x0598 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_CLK__UART4_CTS_B 0x0250 0x0598 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD3_CLK__UART4_RTS_B 0x0250 0x0598 0x0844 0x1 0x0 ++#define MX6SX_PAD_SD3_CLK__ECSPI4_SCLK 0x0250 0x0598 0x0740 0x2 0x0 ++#define MX6SX_PAD_SD3_CLK__AUDMUX_AUD6_RXFS 0x0250 0x0598 0x0680 0x3 0x0 ++#define MX6SX_PAD_SD3_CLK__LCDIF2_VSYNC 0x0250 0x0598 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_CLK__GPIO7_IO_0 0x0250 0x0598 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_CLK__LCDIF2_BUSY 0x0250 0x0598 0x07E4 0x6 0x0 ++#define MX6SX_PAD_SD3_CLK__TPSMP_HDATA_29 0x0250 0x0598 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_CLK__SDMA_DEBUG_EVENT_CHANNEL_5 0x0250 0x0598 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x0254 0x059C 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_CMD__UART4_RX 0x0254 0x059C 0x0848 0x1 0x0 ++#define MX6SX_PAD_SD3_CMD__UART4_TX 0x0254 0x059C 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD3_CMD__ECSPI4_MOSI 0x0254 0x059C 0x0748 0x2 0x0 ++#define MX6SX_PAD_SD3_CMD__AUDMUX_AUD6_RXC 0x0254 0x059C 0x067C 0x3 0x0 ++#define MX6SX_PAD_SD3_CMD__LCDIF2_HSYNC 0x0254 0x059C 0x07E4 0x4 0x1 ++#define MX6SX_PAD_SD3_CMD__GPIO7_IO_1 0x0254 0x059C 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_CMD__LCDIF2_RS 0x0254 0x059C 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_CMD__TPSMP_HDATA_28 0x0254 0x059C 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_CMD__SDMA_DEBUG_EVENT_CHANNEL_4 0x0254 0x059C 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x0258 0x05A0 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA0__I2C4_SCL 0x0258 0x05A0 0x07C0 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA0__ECSPI2_SS1 0x0258 0x05A0 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA0__AUDMUX_AUD6_RXD 0x0258 0x05A0 0x0674 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA0__LCDIF2_DATA_1 0x0258 0x05A0 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA0__GPIO7_IO_2 0x0258 0x05A0 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA0__DCIC1_OUT 0x0258 0x05A0 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA0__TPSMP_HDATA_30 0x0258 0x05A0 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA0__GPU_DEBUG_0 0x0258 0x05A0 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA0__SDMA_DEBUG_EVT_CHN_LINES_0 0x0258 0x05A0 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x025C 0x05A4 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA1__I2C4_SDA 0x025C 0x05A4 0x07C4 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA1__ECSPI2_SS2 0x025C 0x05A4 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA1__AUDMUX_AUD6_TXC 0x025C 0x05A4 0x0684 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA1__LCDIF2_DATA_0 0x025C 0x05A4 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA1__GPIO7_IO_3 0x025C 0x05A4 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA1__DCIC2_OUT 0x025C 0x05A4 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA1__TPSMP_HDATA_31 0x025C 0x05A4 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA1__GPU_DEBUG_1 0x025C 0x05A4 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA1__SDMA_DEBUG_EVT_CHN_LINES_1 0x025C 0x05A4 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x0260 0x05A8 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA2__UART4_RTS_B 0x0260 0x05A8 0x0844 0x1 0x1 ++#define MX6SX_PAD_SD3_DATA2__UART4_CTS_B 0x0260 0x05A8 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA2__ECSPI4_SS0 0x0260 0x05A8 0x074C 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA2__AUDMUX_AUD6_TXFS 0x0260 0x05A8 0x0688 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA2__LCDIF2_CLK 0x0260 0x05A8 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA2__GPIO7_IO_4 0x0260 0x05A8 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA2__LCDIF2_WR_RWN 0x0260 0x05A8 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA2__TPSMP_HDATA_26 0x0260 0x05A8 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA2__GPU_DEBUG_2 0x0260 0x05A8 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA2__SDMA_DEBUG_EVENT_CHANNEL_2 0x0260 0x05A8 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x0264 0x05AC 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA3__UART4_RX 0x0264 0x05AC 0x0848 0x1 0x1 ++#define MX6SX_PAD_SD3_DATA3__UART4_TX 0x0264 0x05AC 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA3__ECSPI4_MISO 0x0264 0x05AC 0x0744 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA3__AUDMUX_AUD6_TXD 0x0264 0x05AC 0x0678 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA3__LCDIF2_ENABLE 0x0264 0x05AC 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA3__GPIO7_IO_5 0x0264 0x05AC 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA3__LCDIF2_RD_E 0x0264 0x05AC 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA3__TPSMP_HDATA_27 0x0264 0x05AC 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA3__GPU_DEBUG_3 0x0264 0x05AC 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA3__SDMA_DEBUG_EVENT_CHANNEL_3 0x0264 0x05AC 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x0268 0x05B0 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA4__CAN2_RX 0x0268 0x05B0 0x0690 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA4__CANFD_RX2 0x0268 0x05B0 0x0698 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA4__UART3_RX 0x0268 0x05B0 0x0840 0x3 0x2 ++#define MX6SX_PAD_SD3_DATA4__UART3_TX 0x0268 0x05B0 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA4__LCDIF2_DATA_3 0x0268 0x05B0 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA4__GPIO7_IO_6 0x0268 0x05B0 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA4__ENET2_1588_EVENT0_IN 0x0268 0x05B0 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA4__TPSMP_HTRANS_1 0x0268 0x05B0 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA4__GPU_DEBUG_4 0x0268 0x05B0 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA4__SDMA_DEBUG_BUS_DEVICE_0 0x0268 0x05B0 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x026C 0x05B4 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA5__CAN1_TX 0x026C 0x05B4 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA5__CANFD_TX1 0x026C 0x05B4 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA5__UART3_RX 0x026C 0x05B4 0x0840 0x3 0x3 ++#define MX6SX_PAD_SD3_DATA5__UART3_TX 0x026C 0x05B4 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA5__LCDIF2_DATA_2 0x026C 0x05B4 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA5__GPIO7_IO_7 0x026C 0x05B4 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA5__ENET2_1588_EVENT0_OUT 0x026C 0x05B4 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA5__SIM_M_HWRITE 0x026C 0x05B4 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA5__GPU_DEBUG_5 0x026C 0x05B4 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA5__SDMA_DEBUG_BUS_DEVICE_1 0x026C 0x05B4 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x0270 0x05B8 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA6__CAN2_TX 0x0270 0x05B8 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA6__CANFD_TX2 0x0270 0x05B8 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA6__UART3_RTS_B 0x0270 0x05B8 0x083C 0x3 0x2 ++#define MX6SX_PAD_SD3_DATA6__UART3_CTS_B 0x0270 0x05B8 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA6__LCDIF2_DATA_4 0x0270 0x05B8 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA6__GPIO7_IO_8 0x0270 0x05B8 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA6__ENET1_1588_EVENT0_OUT 0x0270 0x05B8 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA6__TPSMP_HTRANS_0 0x0270 0x05B8 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA6__GPU_DEBUG_7 0x0270 0x05B8 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA6__SDMA_DEBUG_EVT_CHN_LINES_7 0x0270 0x05B8 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x0274 0x05BC 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD3_DATA7__CAN1_RX 0x0274 0x05BC 0x068C 0x1 0x0 ++#define MX6SX_PAD_SD3_DATA7__CANFD_RX1 0x0274 0x05BC 0x0694 0x2 0x0 ++#define MX6SX_PAD_SD3_DATA7__UART3_CTS_B 0x0274 0x05BC 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD3_DATA7__UART3_RTS_B 0x0274 0x05BC 0x083C 0x3 0x3 ++#define MX6SX_PAD_SD3_DATA7__LCDIF2_DATA_5 0x0274 0x05BC 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD3_DATA7__GPIO7_IO_9 0x0274 0x05BC 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD3_DATA7__ENET1_1588_EVENT0_IN 0x0274 0x05BC 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD3_DATA7__TPSMP_HDATA_DIR 0x0274 0x05BC 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD3_DATA7__GPU_DEBUG_6 0x0274 0x05BC 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD3_DATA7__SDMA_DEBUG_EVT_CHN_LINES_2 0x0274 0x05BC 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x0278 0x05C0 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_CLK__RAWNAND_DATA15 0x0278 0x05C0 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_CLK__ECSPI2_MISO 0x0278 0x05C0 0x0724 0x2 0x1 ++#define MX6SX_PAD_SD4_CLK__AUDMUX_AUD3_RXFS 0x0278 0x05C0 0x0638 0x3 0x0 ++#define MX6SX_PAD_SD4_CLK__LCDIF2_DATA_13 0x0278 0x05C0 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_CLK__GPIO6_IO_12 0x0278 0x05C0 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_CLK__ECSPI3_SS2 0x0278 0x05C0 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_CLK__TPSMP_HDATA_20 0x0278 0x05C0 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_CLK__VDEC_DEBUG_12 0x0278 0x05C0 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_CLK__SDMA_DEBUG_EVENT_CHANNEL_SEL 0x0278 0x05C0 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x027C 0x05C4 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_CMD__RAWNAND_DATA14 0x027C 0x05C4 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_CMD__ECSPI2_MOSI 0x027C 0x05C4 0x0728 0x2 0x1 ++#define MX6SX_PAD_SD4_CMD__AUDMUX_AUD3_RXC 0x027C 0x05C4 0x0634 0x3 0x0 ++#define MX6SX_PAD_SD4_CMD__LCDIF2_DATA_14 0x027C 0x05C4 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_CMD__GPIO6_IO_13 0x027C 0x05C4 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_CMD__ECSPI3_SS1 0x027C 0x05C4 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_CMD__TPSMP_HDATA_19 0x027C 0x05C4 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_CMD__VDEC_DEBUG_11 0x027C 0x05C4 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_CMD__SDMA_DEBUG_CORE_RUN 0x027C 0x05C4 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x0280 0x05C8 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA0__RAWNAND_DATA10 0x0280 0x05C8 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA0__ECSPI2_SS0 0x0280 0x05C8 0x072C 0x2 0x1 ++#define MX6SX_PAD_SD4_DATA0__AUDMUX_AUD3_RXD 0x0280 0x05C8 0x062C 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA0__LCDIF2_DATA_12 0x0280 0x05C8 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA0__GPIO6_IO_14 0x0280 0x05C8 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA0__ECSPI3_SS3 0x0280 0x05C8 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA0__TPSMP_HDATA_21 0x0280 0x05C8 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA0__VDEC_DEBUG_13 0x0280 0x05C8 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA0__SDMA_DEBUG_MODE 0x0280 0x05C8 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x0284 0x05CC 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA1__RAWNAND_DATA11 0x0284 0x05CC 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA1__ECSPI2_SCLK 0x0284 0x05CC 0x0720 0x2 0x1 ++#define MX6SX_PAD_SD4_DATA1__AUDMUX_AUD3_TXC 0x0284 0x05CC 0x063C 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA1__LCDIF2_DATA_11 0x0284 0x05CC 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA1__GPIO6_IO_15 0x0284 0x05CC 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA1__ECSPI3_RDY 0x0284 0x05CC 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA1__TPSMP_HDATA_22 0x0284 0x05CC 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA1__VDEC_DEBUG_14 0x0284 0x05CC 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA1__SDMA_DEBUG_BUS_ERROR 0x0284 0x05CC 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x0288 0x05D0 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA2__RAWNAND_DATA12 0x0288 0x05D0 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA2__I2C2_SDA 0x0288 0x05D0 0x07B4 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA2__AUDMUX_AUD3_TXFS 0x0288 0x05D0 0x0640 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA2__LCDIF2_DATA_10 0x0288 0x05D0 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA2__GPIO6_IO_16 0x0288 0x05D0 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA2__ECSPI2_SS3 0x0288 0x05D0 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA2__TPSMP_HDATA_23 0x0288 0x05D0 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA2__VDEC_DEBUG_15 0x0288 0x05D0 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA2__SDMA_DEBUG_BUS_RWB 0x0288 0x05D0 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x028C 0x05D4 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA3__RAWNAND_DATA13 0x028C 0x05D4 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA3__I2C2_SCL 0x028C 0x05D4 0x07B0 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA3__AUDMUX_AUD3_TXD 0x028C 0x05D4 0x0630 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA3__LCDIF2_DATA_9 0x028C 0x05D4 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA3__GPIO6_IO_17 0x028C 0x05D4 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA3__ECSPI2_RDY 0x028C 0x05D4 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA3__TPSMP_HDATA_24 0x028C 0x05D4 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA3__VDEC_DEBUG_16 0x028C 0x05D4 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA3__SDMA_DEBUG_MATCHED_DMBUS 0x028C 0x05D4 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x0290 0x05D8 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA4__RAWNAND_DATA09 0x0290 0x05D8 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA4__UART5_RX 0x0290 0x05D8 0x0850 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA4__UART5_TX 0x0290 0x05D8 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA4__ECSPI3_SCLK 0x0290 0x05D8 0x0730 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA4__LCDIF2_DATA_8 0x0290 0x05D8 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA4__GPIO6_IO_18 0x0290 0x05D8 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA4__SPDIF_OUT 0x0290 0x05D8 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA4__TPSMP_HDATA_16 0x0290 0x05D8 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA4__USB_OTG_HOST_MODE 0x0290 0x05D8 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA4__SDMA_DEBUG_RTBUFFER_WRITE 0x0290 0x05D8 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x0294 0x05DC 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA5__RAWNAND_CE2_B 0x0294 0x05DC 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA5__UART5_RX 0x0294 0x05DC 0x0850 0x2 0x1 ++#define MX6SX_PAD_SD4_DATA5__UART5_TX 0x0294 0x05DC 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA5__ECSPI3_MOSI 0x0294 0x05DC 0x0738 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA5__LCDIF2_DATA_7 0x0294 0x05DC 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA5__GPIO6_IO_19 0x0294 0x05DC 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA5__SPDIF_IN 0x0294 0x05DC 0x0824 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA5__TPSMP_HDATA_17 0x0294 0x05DC 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA5__VDEC_DEBUG_9 0x0294 0x05DC 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA5__SDMA_DEBUG_EVENT_CHANNEL_0 0x0294 0x05DC 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x0298 0x05E0 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA6__RAWNAND_CE3_B 0x0298 0x05E0 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA6__UART5_RTS_B 0x0298 0x05E0 0x084C 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA6__UART5_CTS_B 0x0298 0x05E0 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA6__ECSPI3_MISO 0x0298 0x05E0 0x0734 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA6__LCDIF2_DATA_6 0x0298 0x05E0 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA6__GPIO6_IO_20 0x0298 0x05E0 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA6__USDHC4_WP 0x0298 0x05E0 0x0878 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA6__TPSMP_HDATA_18 0x0298 0x05E0 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA6__VDEC_DEBUG_10 0x0298 0x05E0 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA6__SDMA_DEBUG_EVENT_CHANNEL_1 0x0298 0x05E0 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x029C 0x05E4 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_DATA7__RAWNAND_DATA08 0x029C 0x05E4 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_DATA7__UART5_CTS_B 0x029C 0x05E4 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD4_DATA7__UART5_RTS_B 0x029C 0x05E4 0x084C 0x2 0x1 ++#define MX6SX_PAD_SD4_DATA7__ECSPI3_SS0 0x029C 0x05E4 0x073C 0x3 0x0 ++#define MX6SX_PAD_SD4_DATA7__LCDIF2_DATA_15 0x029C 0x05E4 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x029C 0x05E4 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_DATA7__USDHC4_CD_B 0x029C 0x05E4 0x0874 0x6 0x0 ++#define MX6SX_PAD_SD4_DATA7__TPSMP_HDATA_15 0x029C 0x05E4 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_DATA7__USB_OTG_PWR_WAKE 0x029C 0x05E4 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_DATA7__SDMA_DEBUG_YIELD 0x029C 0x05E4 0x0000 0x9 0x0 ++#define MX6SX_PAD_SD4_RESET_B__USDHC4_RESET_B 0x02A0 0x05E8 0x0000 0x0 0x0 ++#define MX6SX_PAD_SD4_RESET_B__RAWNAND_DQS 0x02A0 0x05E8 0x0000 0x1 0x0 ++#define MX6SX_PAD_SD4_RESET_B__USDHC4_RESET 0x02A0 0x05E8 0x0000 0x2 0x0 ++#define MX6SX_PAD_SD4_RESET_B__AUDMUX_MCLK 0x02A0 0x05E8 0x0000 0x3 0x0 ++#define MX6SX_PAD_SD4_RESET_B__LCDIF2_RESET 0x02A0 0x05E8 0x0000 0x4 0x0 ++#define MX6SX_PAD_SD4_RESET_B__GPIO6_IO_22 0x02A0 0x05E8 0x0000 0x5 0x0 ++#define MX6SX_PAD_SD4_RESET_B__LCDIF2_CS 0x02A0 0x05E8 0x0000 0x6 0x0 ++#define MX6SX_PAD_SD4_RESET_B__TPSMP_HDATA_25 0x02A0 0x05E8 0x0000 0x7 0x0 ++#define MX6SX_PAD_SD4_RESET_B__VDEC_DEBUG_17 0x02A0 0x05E8 0x0000 0x8 0x0 ++#define MX6SX_PAD_SD4_RESET_B__SDMA_DEBUG_BUS_DEVICE_2 0x02A0 0x05E8 0x0000 0x9 0x0 ++#define MX6SX_PAD_USB_H_DATA__USB_H_DATA 0x02A4 0x05EC 0x0000 0x0 0x0 ++#define MX6SX_PAD_USB_H_DATA__PWM2_OUT 0x02A4 0x05EC 0x0000 0x1 0x0 ++#define MX6SX_PAD_USB_H_DATA__ANATOP_24M_OUT 0x02A4 0x05EC 0x0000 0x2 0x0 ++#define MX6SX_PAD_USB_H_DATA__I2C4_SDA 0x02A4 0x05EC 0x07C4 0x3 0x1 ++#define MX6SX_PAD_USB_H_DATA__WDOG3_WDOG_B 0x02A4 0x05EC 0x0000 0x4 0x0 ++#define MX6SX_PAD_USB_H_DATA__GPIO7_IO_10 0x02A4 0x05EC 0x0000 0x5 0x0 ++#define MX6SX_PAD_USB_H_STROBE__USB_H_STROBE 0x02A8 0x05F0 0x0000 0x0 0x0 ++#define MX6SX_PAD_USB_H_STROBE__PWM1_OUT 0x02A8 0x05F0 0x0000 0x1 0x0 ++#define MX6SX_PAD_USB_H_STROBE__ANATOP_32K_OUT 0x02A8 0x05F0 0x0000 0x2 0x0 ++#define MX6SX_PAD_USB_H_STROBE__I2C4_SCL 0x02A8 0x05F0 0x07C0 0x3 0x1 ++#define MX6SX_PAD_USB_H_STROBE__WDOG3_WDOG_RST_B_DEB 0x02A8 0x05F0 0x0000 0x4 0x0 ++#define MX6SX_PAD_USB_H_STROBE__GPIO7_IO_11 0x02A8 0x05F0 0x0000 0x5 0x0 ++ ++#endif /* __DTS_IMX6SX_PINFUNC_H */ +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sabreauto.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sabreauto.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sabreauto.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sabreauto.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,925 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++/dts-v1/; ++ ++#include "imx6sx.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 SoloX Sabre Auto Board"; ++ compatible = "fsl,imx6sx-sabreauto", "fsl,imx6sx"; ++ ++ backlight2 { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ fb-names = "mxs-lcdif1"; ++ }; ++ ++ clocks { ++ codec_osc: anaclk2 { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <24576000>; ++ }; ++ }; ++ ++ max7322_reset: max7322-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <1>; ++ #reset-cells = <0>; ++ }; ++ ++ hannstar_cabc { ++ compatible = "hannstar,cabc"; ++ ++ lvds0 { ++ gpios = <&max7310_a 0 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ max7310_reset: max7310-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <1>; ++ #reset-cells = <0>; ++ }; ++ ++ memory { ++ reg = <0x80000000 0x80000000>; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_audio: cs42888_supply { ++ compatible = "regulator-fixed"; ++ regulator-name = "cs42888_supply"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_vio1: vio1_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "vio1"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_vio2: vio2_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "vio2"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_vd: f3v3_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "vd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_va: f5v_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "va"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_lcd_3v3: lcd-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "lcd-3v3"; ++ gpio = <&gpio3 27 0>; ++ enable-active-high; ++ status = "disabled"; ++ }; ++ ++ reg_sd3_vmmc: sd3_vmmc{ ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_SD3"; ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_vref_3v3: regulator@0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vref-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_psu_5v: psu_5v0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "PSU-5V0"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ }; ++ ++ reg_usb_otg1_vbus: usb_otg1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 9 0>; ++ enable-active-high; ++ }; ++ ++ reg_usb_otg2_vbus: usb_otg2_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg2_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 12 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ sound-cs42888 { ++ compatible = "fsl,imx6-sabreauto-cs42888", ++ "fsl,imx-audio-cs42888"; ++ model = "imx-cs42888"; ++ esai-controller = <&esai>; ++ asrc-controller = <&asrc>; ++ audio-codec = <&codec>; ++ }; ++ ++ sound-fm { ++ compatible = "fsl,imx-audio-si476x", ++ "fsl,imx-tuner-si476x"; ++ model = "imx-radio-si4763"; ++ ++ ssi-controller = <&ssi2>; ++ fm-controller = <&si476x_codec>; ++ mux-int-port = <2>; ++ mux-ext-port = <5>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-in; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6x-sabreauto { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6SX_PAD_USB_H_STROBE__GPIO7_IO_11 0x17059 ++ MX6SX_PAD_USB_H_DATA__GPIO7_IO_10 0x17059 ++ MX6SX_PAD_LCD1_DATA18__GPIO3_IO_19 0x17059 ++ MX6SX_PAD_SD4_RESET_B__GPIO6_IO_22 0x80000000 ++ MX6SX_PAD_LCD1_DATA23__GPIO3_IO_24 0x80000000 ++ MX6SX_PAD_SD2_CLK__GPIO6_IO_6 0x80000000 ++ MX6SX_PAD_LCD1_DATA22__GPIO3_IO_23 0x80000000 ++ MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x10b0 ++ >; ++ }; ++ ++ pinctrl_audmux_3: audmux-3 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_CMD__AUDMUX_AUD5_RXC 0x130b0 ++ MX6SX_PAD_SD1_CLK__AUDMUX_AUD5_RXFS 0x130b0 ++ MX6SX_PAD_SD1_DATA3__AUDMUX_AUD5_RXD 0x130b0 ++ >; ++ }; ++ ++ pinctrl_enet1_1: enet1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 ++ MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 ++ MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 ++ >; ++ }; ++ ++ pinctrl_enet2_1: enet2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x3081 ++ >; ++ }; ++ ++ pinctrl_esai_2: esaigrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__ESAI_TX_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA01__ESAI_TX_FS 0x1b030 ++ MX6SX_PAD_CSI_HSYNC__ESAI_TX0 0x1b030 ++ MX6SX_PAD_CSI_DATA04__ESAI_TX1 0x1b030 ++ MX6SX_PAD_CSI_DATA06__ESAI_TX2_RX3 0x1b030 ++ MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2 0x1b030 ++ MX6SX_PAD_CSI_DATA02__ESAI_RX_CLK 0x1b030 ++ MX6SX_PAD_CSI_DATA03__ESAI_RX_FS 0x1b030 ++ MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0 0x1b030 ++ MX6SX_PAD_CSI_DATA05__ESAI_TX4_RX1 0x1b030 ++ >; ++ }; ++ ++ pinctrl_flexcan1_1: flexcan1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b020 ++ MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b020 ++ >; ++ }; ++ ++ pinctrl_flexcan2_1: flexcan2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b020 ++ MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b020 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand_1: gpmi-nand-1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 ++ MX6SX_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 ++ MX6SX_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 ++ MX6SX_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 ++ MX6SX_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 ++ MX6SX_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 ++ MX6SX_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 ++ MX6SX_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 ++ MX6SX_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 ++ MX6SX_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 ++ MX6SX_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 ++ MX6SX_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 ++ MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 ++ MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 ++ MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 ++ MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 ++ >; ++ }; ++ ++ pinctrl_i2c2_1: i2c2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3_2: i2c3grp-2 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_mlb_2: mlbgrp-2 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_RX_CLK__MLB_DATA 0x31 ++ MX6SX_PAD_ENET2_CRS__MLB_SIG 0x31 ++ MX6SX_PAD_ENET2_TX_CLK__MLB_CLK 0x31 ++ >; ++ }; ++ ++ pinctrl_pwm4_0: pwm4grp-0 { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_qspi1_1: qspi1grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_DATA0__QSPI1_A_DATA_0 0x70a1 ++ MX6SX_PAD_QSPI1A_DATA1__QSPI1_A_DATA_1 0x70a1 ++ MX6SX_PAD_QSPI1A_DATA2__QSPI1_A_DATA_2 0x70a1 ++ MX6SX_PAD_QSPI1A_DATA3__QSPI1_A_DATA_3 0x70a1 ++ MX6SX_PAD_QSPI1A_SCLK__QSPI1_A_SCLK 0x70a1 ++ MX6SX_PAD_QSPI1A_SS0_B__QSPI1_A_SS0_B 0x70a1 ++ MX6SX_PAD_QSPI1B_DATA0__QSPI1_B_DATA_0 0x70a1 ++ MX6SX_PAD_QSPI1B_DATA1__QSPI1_B_DATA_1 0x70a1 ++ MX6SX_PAD_QSPI1B_DATA2__QSPI1_B_DATA_2 0x70a1 ++ MX6SX_PAD_QSPI1B_DATA3__QSPI1_B_DATA_3 0x70a1 ++ MX6SX_PAD_QSPI1B_SCLK__QSPI1_B_SCLK 0x70a1 ++ MX6SX_PAD_QSPI1B_SS0_B__QSPI1_B_SS0_B 0x70a1 ++ >; ++ }; ++ ++ pinctrl_spdif_3: spdifgrp-3 { ++ fsl,pins = < ++ MX6SX_PAD_ENET2_COL__SPDIF_IN 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_uart1_1: uart1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO05__UART1_RX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2_1: uart2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO07__UART2_RX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO06__UART2_TX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5_1: uart5grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5dte_1: uart5dtegrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg1_1: usbotg1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1: usdhc3grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10059 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17059 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17059 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17059 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17059 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17059 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17059 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17059 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 ++ >; ++ }; ++ ++ pinctrl_usdhc4_3: usdhc4grp-3 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17071 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10071 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17071 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17071 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17071 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17071 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x17071 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x17071 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x17071 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x17071 ++ >; ++ }; ++ }; ++}; ++ ++&adc1 { ++ vref-supply = <®_vref_3v3>; ++ status = "okay"; ++}; ++ ++&adc2 { ++ vref-supply = <®_vref_3v3>; ++ status = "okay"; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux_3>; ++ status = "okay"; ++}; ++ ++&clks { ++ assigned-clocks = <&clks IMX6SX_PLL4_BYPASS_SRC>, ++ <&clks IMX6SX_PLL4_BYPASS>, ++ <&clks IMX6SX_CLK_PLL4_POST_DIV>; ++ assigned-clock-parents = <&clks IMX6SX_CLK_LVDS2_IN>, ++ <&clks IMX6SX_PLL4_BYPASS_SRC>; ++ assigned-clock-rates = <0>, <0>, <24576000>; ++}; ++ ++&csi2 { ++ status = "okay"; ++ port { ++ csi2_ep: endpoint { ++ remote-endpoint = <&vadc_ep>; ++ }; ++ }; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-lcdif1"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds"; ++ status = "okay"; ++}; ++ ++&esai { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_esai_2>; ++ assigned-clocks = <&clks IMX6SX_CLK_ESAI_SEL>, ++ <&clks IMX6SX_CLK_ESAI_EXTAL>; ++ assigned-clock-parents = <&clks IMX6SX_CLK_PLL4_AUDIO_DIV>; ++ assigned-clock-rates = <0>, <24576000>; ++ status = "okay"; ++}; ++ ++&fec1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet1_1>; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy1>; ++ pinctrl-assert-gpios = <&max7322 0 GPIO_ACTIVE_HIGH>; ++ fsl,magic-packet; ++ status = "okay"; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ethphy0: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++ ++ ethphy1: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ }; ++ }; ++}; ++ ++&fec2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet2_1>; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy0>; ++ fsl,magic-packet; ++ status = "okay"; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1_1>; ++ trx-en-gpio = <&max7310_b 5 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&max7310_b 4 GPIO_ACTIVE_HIGH>; ++ trx-wakeup-gpio = <&max7310_b 7 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan2_1>; ++ trx-en-gpio = <&max7310_b 5 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&max7310_b 4 GPIO_ACTIVE_HIGH>; ++ trx-wakeup-gpio = <&max7310_b 7 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_1>; ++ status = "okay"; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <22 2>; ++ wakeup-gpios = <&gpio6 22 0>; ++ }; ++ ++ codec: cs42888@048 { ++ compatible = "cirrus,cs42888"; ++ reg = <0x048>; ++ clocks = <&codec_osc 0>; ++ clock-names = "mclk"; ++ VA-supply = <®_audio>; ++ VD-supply = <®_audio>; ++ VLS-supply = <®_audio>; ++ VLC-supply = <®_audio>; ++ }; ++ ++ si4763: si4763@63 { ++ compatible = "si4761"; ++ reg = <0x63>; ++ va-supply = <&si4763_va>; ++ vd-supply = <&si4763_vd>; ++ vio1-supply = <&si4763_vio1>; ++ vio2-supply = <&si4763_vio2>; ++ revision-a10; /* set to default A10 compatible command set */ ++ ++ si476x_codec: si476x-codec { ++ compatible = "si476x-codec"; ++ }; ++ }; ++ ++ max7322: gpio@68 { ++ compatible = "maxim,max7322"; ++ reg = <0x68>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ resets = <&max7322_reset>; ++ }; ++ ++ 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>; ++ 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; ++ }; ++ }; ++ }; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif_3>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-master"; ++ status = "okay"; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_2>; ++ 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>; ++ resets = <&max7310_reset>; ++ }; ++ ++ mma8451@1c { ++ compatible = "fsl,mma8451"; ++ reg = <0x1c>; ++ position = <7>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <24 8>; ++ interrupt-route = <1>; ++ }; ++ ++ mag3110@0e { ++ compatible = "fsl,mag3110"; ++ reg = <0x0e>; ++ position = <2>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <6 1>; ++ }; ++ ++ isl29023@44 { ++ compatible = "fsl,isl29023"; ++ reg = <0x44>; ++ rext = <499>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <23 2>; ++ }; ++}; ++ ++&lcdif2 { ++ display = <&display1>; ++ disp-dev = "ldb"; ++ status = "okay"; ++ ++ display1: display { ++ bits-per-pixel = <16>; ++ bus-width = <18>; ++ }; ++}; ++ ++&ldb { ++ status = "okay"; ++ ++ lvds-channel@0 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ crtc = "lcdif2"; ++ status = "okay"; ++ ++ display-timings { ++ native-mode = <&timing1>; ++ timing1: 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>; ++ }; ++ }; ++ }; ++}; ++ ++&mlb { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_mlb_2>; ++ status = "okay"; ++}; ++ ++&pcie { ++ reset-gpio = <&max7310_b 3 0>; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1_1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2_1>; ++ status = "okay"; ++}; ++ ++&uart5 { /* for bluetooth */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5_1>; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++ /* for DTE mode, add below change */ ++ /* fsl,dte-mode;*/ ++ /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ ++}; ++ ++&usbotg1 { ++ vbus-supply = <®_usb_otg1_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg1_1>; ++ status = "okay"; ++}; ++ ++&usbotg2 { ++ vbus-supply = <®_usb_otg2_vbus>; ++ dr_mode = "host"; ++ 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>; ++ bus-width = <8>; ++ cd-gpios = <&gpio7 10 0>; ++ wp-gpios = <&gpio3 19 0>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ vmmc-supply = <®_sd3_vmmc>; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4_3>; ++ bus-width = <8>; ++ cd-gpios = <&gpio7 11 0>; ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakup; ++ status = "okay"; ++}; ++ ++&pwm4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm4_0>; ++ status = "okay"; ++}; ++ ++&pxp { ++ status = "okay"; ++}; ++ ++&qspi1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_qspi1_1>; ++ /* only map 128MB */ ++ reg = <0x021e0000 0x4000>, <0x60000000 0x8000000>; ++ status = "okay"; ++ ddrsmp=<2>; ++ ++ flash0: n25q256a@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ reg = <0>; ++ }; ++ ++ flash1: n25q256a@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ reg = <1>; ++ }; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ status = "okay"; ++ nand-on-flash-bbt; ++}; ++ ++&vadc { ++ vadc_in = <0>; ++ csi_id = <1>; ++ status = "okay"; ++ port { ++ vadc_ep: endpoint { ++ remote-endpoint = <&csi2_ep>; ++ }; ++ }; ++}; ++ +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sabreauto-m4.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sabreauto-m4.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sabreauto-m4.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sabreauto-m4.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-sabreauto.dts" ++ ++/{ ++ memory { ++ linux,usable-memory = <0x80000000 0x3ff00000>; ++ reg = <0x80000000 0x40000000>; ++ }; ++}; ++ ++/* ++ * The flollowing modules are conflicting with M4, disable them when m4 ++ * is running. ++ */ ++&flexcan1 { ++ status = "disabled"; ++}; ++ ++&flexcan2 { ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ status = "disabled"; ++}; ++ ++&mcctest{ ++ status = "okay"; ++}; ++ ++&mcctty{ ++ status = "okay"; ++}; ++ ++&uart2 { ++ status = "disabled"; ++}; ++ ++&adc1 { ++ status = "disabled"; ++}; ++ ++&adc2 { ++ status = "disabled"; ++}; ++ ++&qspi1 { ++ status = "disabled"; ++}; ++ ++&qspi_m4 { ++ reg = <0x021e0000 0x4000>; ++ status = "okay"; ++}; ++ ++&ocram { ++ reg = <0x00901000 0x1E000>; ++}; ++ ++&clks { ++ fsl,shared-clks-number = <0x23>; ++ fsl,shared-clks-index = ; ++ fsl,shared-mem-addr = <0x91F000>; ++ fsl,shared-mem-size = <0x1000>; ++}; ++ +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,1121 @@ ++/* ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/dts-v1/; ++ ++#include ++#include "imx6sx.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 SoloX SDB Board"; ++ compatible = "fsl,imx6sx-sdb", "fsl,imx6sx"; ++ ++ chosen { ++ stdout-path = &uart1; ++ }; ++ ++ memory { ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ backlight1 { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ fb-names = "mxs-lcdif0"; ++ }; ++ ++ backlight2 { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ fb-names = "mxs-lcdif1"; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ volume-up { ++ label = "Volume Up"; ++ gpios = <&gpio1 18 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ volume-down { ++ label = "Volume Down"; ++ gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ hannstar_cabc { ++ compatible = "hannstar,cabc"; ++ ++ lvds0 { ++ gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_lcd_3v3: lcd-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "lcd-3v3"; ++ gpio = <&gpio3 27 0>; ++ enable-active-high; ++ status = "disabled"; ++ }; ++ ++ vcc_sd3: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_vcc_sd3>; ++ regulator-name = "VCC_SD3"; ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_psu_5v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "PSU-5V0"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ }; ++ ++ reg_vref_3v3: regulator@2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vref-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_usb_otg1_vbus: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usb_otg1>; ++ regulator-name = "usb_otg1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_usb_otg2_vbus: regulator@4 { ++ compatible = "regulator-fixed"; ++ reg = <4>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usb_otg2>; ++ regulator-name = "usb_otg2_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_pcie: regulator@5 { ++ compatible = "regulator-fixed"; ++ reg = <5>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pcie_reg>; ++ regulator-name = "MPCIE_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio2 1 0>; ++ regulator-always-on; ++ enable-active-high; ++ }; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabresd-wm8962", ++ "fsl,imx-audio-wm8962"; ++ model = "wm8962-audio"; ++ cpu-dai = <&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 = <6>; ++ hp-det-gpios = <&gpio1 17 1>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx6sx-sdb-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-out; ++ }; ++ ++ sii902x_reset: sii902x-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio3 27 1>; ++ reset-delay-us = <100000>; ++ #reset-cells = <0>; ++ status = "disabled"; ++ }; ++}; ++ ++&adc1 { ++ vref-supply = <®_vref_3v3>; ++ status = "okay"; ++}; ++ ++&adc2 { ++ vref-supply = <®_vref_3v3>; ++ status = "okay"; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&csi1 { ++ status = "okay"; ++ ++ port { ++ csi1_ep: endpoint { ++ remote-endpoint = <&ov5640_ep>; ++ }; ++ }; ++}; ++ ++&csi2 { ++ status = "okay"; ++ port { ++ csi2_ep: endpoint { ++ remote-endpoint = <&vadc_ep>; ++ }; ++ }; ++}; ++ ++&cpu0 { ++ operating-points = < ++ /* kHz uV */ ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1175000 ++ 198000 1175000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC uV */ ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1175000 ++ 198000 1175000 ++ >; ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1a_reg>; ++ fsl,arm-soc-shared = <1>; ++}; ++ ++&gpc { ++ /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,ldo-bypass = <1>; ++}; ++ ++&lcdif1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_lcdif_dat ++ &pinctrl_lcdif_ctrl>; ++ lcd-supply = <®_lcd_3v3>; ++ display = <&display0>; ++ status = "disabled"; ++ ++ display0: 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>; ++ }; ++ }; ++ }; ++}; ++ ++&lcdif2 { ++ display = <&display1>; ++ disp-dev = "ldb"; ++ status = "okay"; ++ ++ display1: display { ++ bits-per-pixel = <16>; ++ bus-width = <18>; ++ }; ++}; ++ ++&ldb { ++ status = "okay"; ++ ++ lvds-channel@0 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ crtc = "lcdif2"; ++ status = "okay"; ++ ++ display-timings { ++ native-mode = <&timing1>; ++ timing1: 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>; ++ }; ++ }; ++ }; ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3>; ++ status = "okay"; ++}; ++ ++&pwm4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm4>; ++ status = "okay"; ++}; ++ ++&dcic1 { ++ dcic_id = <0>; ++ dcic_mux = "dcic-lcdif1"; ++ status = "okay"; ++}; ++ ++&dcic2 { ++ dcic_id = <1>; ++ dcic_mux = "dcic-lvds"; ++ status = "okay"; ++}; ++ ++&fec1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet1>; ++ pinctrl-assert-gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>, <&gpio2 6 GPIO_ACTIVE_LOW>; ++ phy-mode = "rgmii"; ++ status = "okay"; ++}; ++ ++&fec2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet2>; ++ phy-mode = "rgmii"; ++ status = "okay"; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1>; ++ trx-en-gpio = <&gpio4 25 GPIO_ACTIVE_LOW>; ++ trx-stby-gpio = <&gpio4 27 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan2>; ++ trx-en-gpio = <&gpio4 25 GPIO_ACTIVE_LOW>; ++ trx-stby-gpio = <&gpio4 27 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pcie>; ++ reset-gpio = <&gpio2 0 0>; ++ status = "okay"; ++}; ++ ++&qspi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_qspi2_1>; ++ status = "okay"; ++ ++#ifndef SPANSIONFLASH ++ ddrsmp=<0>; ++ ++ flash0: n25q256a@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ spi-nor,ddr-quad-read-dummy = <6>; ++ reg = <0>; ++ }; ++ ++ flash1: n25q256a@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "micron,n25q256a"; ++ spi-max-frequency = <29000000>; ++ spi-nor,ddr-quad-read-dummy = <6>; ++ reg = <1>; ++ }; ++#endif ++}; ++ ++&pxp { ++ status = "okay"; ++}; ++ ++&sai1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sai1>; ++ status = "disabled"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart5 { /* for bluetooth */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++ /* for DTE mode, add below change */ ++ /* fsl,dte-mode;*/ ++ /* pinctrl-0 = <&pinctrl_uart5dte_1>; */ ++}; ++ ++&usbotg1 { ++ vbus-supply = <®_usb_otg1_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usb_otg1_id>; ++ status = "okay"; ++}; ++ ++&usbotg2 { ++ vbus-supply = <®_usb_otg2_vbus>; ++ dr_mode = "host"; ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ non-removable; ++ no-1-8-v; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ pinctrl-1 = <&pinctrl_usdhc3_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_200mhz>; ++ bus-width = <8>; ++ cd-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>; ++ keep-power-in-suspend; ++ enable-sdio-wakeup; ++ vmmc-supply = <&vcc_sd3>; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ cd-gpios = <&gpio6 21 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ pmic: pfuze100@08 { ++ compatible = "fsl,pfuze200"; ++ reg = <0x08>; ++ ++ regulators { ++ sw1a_reg: sw1ab { ++ 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; ++ }; ++ ++ 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>; ++ 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; ++ }; ++ }; ++ }; ++ ++ ov5640: ov5640@3c { ++ compatible = "ovti,ov5640"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_csi_0>; ++ clocks = <&clks IMX6SX_CLK_CSI>; ++ clock-names = "csi_mclk"; ++ AVDD-supply = <&vgen3_reg>; /* 2.8v */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio3 28 1>; ++ rst-gpios = <&gpio3 27 0>; ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ port { ++ ov5640_ep: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ }; ++ }; ++ }; ++ ++ sii902x@39 { ++ compatible = "SiI,sii902x"; ++ interrupt-parent = <&gpio4>; ++ interrupts = <21 2>; ++ mode_str ="1280x720M@60"; ++ bits-per-pixel = <16>; ++ resets = <&sii902x_reset>; ++ reg = <0x39>; ++ status = "disabled"; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_egalax_int>; ++ interrupt-parent = <&gpio4>; ++ interrupts = <19 2>; ++ wakeup-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ mma8451@1c { ++ compatible = "fsl,mma8451"; ++ reg = <0x1c>; ++ position = <1>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <2 8>; ++ interrupt-route = <2>; ++ }; ++ ++ mag3110@0e { ++ compatible = "fsl,mag3110"; ++ reg = <0x0e>; ++ position = <2>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <5 1>; ++ shared-interrupt; ++ }; ++ ++ isl29023@44 { ++ compatible = "fsl,isl29023"; ++ reg = <0x44>; ++ rext = <499>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <5 1>; ++ shared-interrupt; ++ }; ++}; ++ ++&i2c4 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c4>; ++ status = "okay"; ++ ++ codec: wm8962@1a { ++ compatible = "wlf,wm8962"; ++ reg = <0x1a>; ++ clocks = <&clks IMX6SX_CLK_AUDIO>; ++ DCVDD-supply = <&vgen4_reg>; ++ DBVDD-supply = <&vgen4_reg>; ++ AVDD-supply = <&vgen4_reg>; ++ CPVDD-supply = <&vgen4_reg>; ++ MICVDD-supply = <&vgen3_reg>; ++ PLLVDD-supply = <&vgen4_reg>; ++ SPKVDD1-supply = <®_psu_5v>; ++ SPKVDD2-supply = <®_psu_5v>; ++ amic-mono; ++ }; ++}; ++ ++&vadc { ++ vadc_in = <0>; ++ csi_id = <1>; ++ status = "okay"; ++ port { ++ vadc_ep: endpoint { ++ remote-endpoint = <&csi2_ep>; ++ }; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog &pinctrl_can_gpios>; ++ ++ imx6x-sdb { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA0__GPIO6_IO_2 0x17059 ++ MX6SX_PAD_SD1_DATA3__GPIO6_IO_5 0xb000 ++ MX6SX_PAD_CSI_DATA03__GPIO1_IO_17 0x17059 ++ MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x30b0 ++ MX6SX_PAD_QSPI1A_SCLK__GPIO4_IO_21 0x17059 ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__AUDMUX_AUD6_TXC 0x130b0 ++ MX6SX_PAD_CSI_DATA01__AUDMUX_AUD6_TXFS 0x130b0 ++ MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD 0x120b0 ++ MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x130b0 ++ MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130b0 ++ >; ++ }; ++ ++ pinctrl_canfd1: canfd1grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CANFD_TX1 0x1b0b0 ++ MX6SX_PAD_QSPI1A_SS1_B__CANFD_RX1 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_canfd2: canfd2grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CANFD_RX2 0x1b0b0 ++ MX6SX_PAD_QSPI1A_DQS__CANFD_TX2 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_csi_0: csigrp-0 { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA07__CSI1_MCLK 0x110b0 ++ MX6SX_PAD_LCD1_DATA06__CSI1_PIXCLK 0x110b0 ++ MX6SX_PAD_LCD1_DATA04__CSI1_VSYNC 0x110b0 ++ MX6SX_PAD_LCD1_DATA05__CSI1_HSYNC 0x110b0 ++ MX6SX_PAD_LCD1_DATA17__CSI1_DATA_0 0x110b0 ++ MX6SX_PAD_LCD1_DATA16__CSI1_DATA_1 0x110b0 ++ MX6SX_PAD_LCD1_DATA15__CSI1_DATA_2 0x110b0 ++ MX6SX_PAD_LCD1_DATA14__CSI1_DATA_3 0x110b0 ++ MX6SX_PAD_LCD1_DATA13__CSI1_DATA_4 0x110b0 ++ MX6SX_PAD_LCD1_DATA12__CSI1_DATA_5 0x110b0 ++ MX6SX_PAD_LCD1_DATA11__CSI1_DATA_6 0x110b0 ++ MX6SX_PAD_LCD1_DATA10__CSI1_DATA_7 0x110b0 ++ MX6SX_PAD_LCD1_DATA09__CSI1_DATA_8 0x110b0 ++ MX6SX_PAD_LCD1_DATA08__CSI1_DATA_9 0x110b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x80000000 ++ MX6SX_PAD_LCD1_VSYNC__GPIO3_IO_28 0x80000000 ++ >; ++ }; ++ ++ pinctrl_egalax_int: egalax_intgrp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1A_DATA3__GPIO4_IO_19 0x80000000 ++ >; ++ }; ++ ++ pinctrl_enet1: enet1grp { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 ++ MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 ++ MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 ++ MX6SX_PAD_QSPI1A_DATA0__GPIO4_IO_16 0x80000000 ++ MX6SX_PAD_ENET2_COL__GPIO2_IO_6 0x80000000 ++ MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x91 ++ >; ++ }; ++ ++ pinctrl_enet2: enet2grp { ++ fsl,pins = < ++ MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0xa0b9 ++ MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0xa0b1 ++ MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0xa0b1 ++ MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0xa0b1 ++ MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0xa0b1 ++ MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0xa0b1 ++ MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x3081 ++ MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x3081 ++ MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x3081 ++ MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x3081 ++ MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x3081 ++ MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x3081 ++ >; ++ }; ++ ++ pinctrl_flexcan1: flexcan1grp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b020 ++ MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b020 ++ >; ++ }; ++ ++ pinctrl_flexcan2: flexcan2grp { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b020 ++ MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b020 ++ >; ++ }; ++ ++ pinctrl_gpio_keys: gpio_keysgrp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA04__GPIO1_IO_18 0x17059 ++ MX6SX_PAD_CSI_DATA05__GPIO1_IO_19 0x17059 ++ >; ++ }; ++ ++ pinctrl_can_gpios: can-gpios { ++ fsl,pins = < ++ MX6SX_PAD_QSPI1B_DATA1__GPIO4_IO_25 0x17059 ++ MX6SX_PAD_QSPI1B_DATA3__GPIO4_IO_27 0x17059 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO03__I2C2_SDA 0x4001b8b1 ++ MX6SX_PAD_GPIO1_IO02__I2C2_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 ++ MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c4: i2c4grp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x4001b8b1 ++ MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_lcdif_dat: lcdifdatgrp { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x4001b0b0 ++ MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_lcdif_ctrl: lcdifctrlgrp { ++ fsl,pins = < ++ MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x4001b0b0 ++ MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x4001b0b0 ++ MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x4001b0b0 ++ MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x4001b0b0 ++ >; ++ }; ++ ++ pinctrl_pwm3: pwm3grp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6SX_PAD_SD1_DATA1__PWM4_OUT 0x110b0 ++ >; ++ }; ++ ++ pinctrl_qspi2_1: qspi2grp_1 { ++ fsl,pins = < ++ MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0 0x70f1 ++ MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1 0x70f1 ++ MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2 0x70f1 ++ MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3 0x70f1 ++ MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK 0x70f1 ++ MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B 0x70f1 ++ MX6SX_PAD_NAND_DATA01__QSPI2_B_DATA_0 0x70f1 ++ MX6SX_PAD_NAND_DATA00__QSPI2_B_DATA_1 0x70f1 ++ MX6SX_PAD_NAND_WE_B__QSPI2_B_DATA_2 0x70f1 ++ MX6SX_PAD_NAND_RE_B__QSPI2_B_DATA_3 0x70f1 ++ MX6SX_PAD_NAND_DATA02__QSPI2_B_SCLK 0x70f1 ++ MX6SX_PAD_NAND_DATA03__QSPI2_B_SS0_B 0x70f1 ++ >; ++ }; ++ ++ pinctrl_sai1: sai1grp { ++ fsl,pins = < ++ MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x130b0 ++ MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x130b0 ++ MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x120b0 ++ MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x130b0 ++ MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130b0 ++ >; ++ }; ++ ++ pinctrl_spdif: spdifgrp { ++ fsl,pins = < ++ MX6SX_PAD_SD4_DATA4__SPDIF_OUT 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_pcie: pciegrp { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x10b0 ++ >; ++ }; ++ ++ pinctrl_pcie_reg: pciereggrp { ++ fsl,pins = < ++ MX6SX_PAD_ENET1_CRS__GPIO2_IO_1 0x10b0 ++ >; ++ }; ++ ++ pinctrl_vcc_sd3: vccsd3grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_COL1__GPIO2_IO_11 0x17059 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO04__UART1_TX 0x1b0b1 ++ MX6SX_PAD_GPIO1_IO05__UART1_RX 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5dte_1: uart5dtegrp-1 { ++ fsl,pins = < ++ MX6SX_PAD_KEY_ROW3__UART5_TX 0x1b0b1 ++ MX6SX_PAD_KEY_COL3__UART5_RX 0x1b0b1 ++ MX6SX_PAD_KEY_ROW2__UART5_RTS_B 0x1b0b1 ++ MX6SX_PAD_KEY_COL2__UART5_CTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usb_otg1: usbotg1grp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9 0x10b0 ++ >; ++ }; ++ ++ pinctrl_usb_otg1_id: usbotg1idgrp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usb_otg2: usbot2ggrp { ++ fsl,pins = < ++ MX6SX_PAD_GPIO1_IO12__GPIO1_IO_12 0x10b0 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ fsl,pins = < ++ MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 ++ MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 ++ MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x17059 ++ MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x17059 ++ MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x17059 ++ MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17069 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10071 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17069 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17069 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17069 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17069 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17069 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17069 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17069 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17069 ++ MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x17059 /* CD */ ++ MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x17059 /* WP */ ++ >; ++ }; ++ ++ pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 ++ MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 ++ MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 ++ MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 ++ MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 ++ MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 ++ MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 ++ MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 ++ MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 ++ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x17059 /* CD */ ++ MX6SX_PAD_SD4_DATA6__GPIO6_IO_20 0x17059 /* WP */ ++ >; ++ }; ++ ++ pinctrl_usdhc4_1: usdhc4grp-1 { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x17059 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x17059 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x17059 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc4_1_100mhz: usdhc4grp-1-100mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170b9 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100b9 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170b9 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170b9 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170b9 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170b9 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170b9 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170b9 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170b9 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc4_1_200mhz: usdhc4grp-1-200mhz { ++ fsl,pins = < ++ MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170f9 ++ MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100f9 ++ MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x170f9 ++ MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x170f9 ++ MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x170f9 ++ MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x170f9 ++ MX6SX_PAD_SD4_DATA4__USDHC4_DATA4 0x170f9 ++ MX6SX_PAD_SD4_DATA5__USDHC4_DATA5 0x170f9 ++ MX6SX_PAD_SD4_DATA6__USDHC4_DATA6 0x170f9 ++ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170f9 ++ >; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-emmc.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-emmc.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-emmc.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-emmc.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-sdb.dts" ++ ++/* ++ * The eMMC chip on imx6sx sdb board is DNP by default. ++ * Need do hw rework to burn the eMMC4.5 chip on the eMMC socket on uSDHC4 ++ * and connect eMMC signals as well as disconnect BOOT SD CARD slot signals ++ */ ++&usdhc4 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc4_1>; ++ pinctrl-1 = <&pinctrl_usdhc4_1_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc4_1_200mhz>; ++ bus-width = <8>; ++ /* ++ * overwrite cd-gpios and wp-gpios since they are reused as eMMC DATA ++ * signals after rework ++ */ ++ cd-gpios = <>; ++ wp-gpios = <>; ++ non-removable; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-lcdif1.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-lcdif1.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-lcdif1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-lcdif1.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2014-2015 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 "imx6sx-sdb.dts" ++ ++/ { ++ regulators { ++ reg_lcd_3v3: lcd-3v3 { ++ status = "okay"; ++ }; ++ }; ++ ++ sii902x_reset: sii902x-reset { ++ status = "okay"; ++ }; ++}; ++ ++&csi1 { ++ status = "disabled"; ++}; ++ ++&lcdif1 { ++ status = "okay"; ++}; ++ ++&i2c1 { ++ sii902x@39 { ++ status = "okay"; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-ldo.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-ldo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-ldo.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (C) 2015 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 "imx6sx-sdb.dts" ++ ++&cpu0 { ++ operating-points = < ++ /* kHz uV */ ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1075000 ++ 198000 975000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC uV */ ++ 996000 1175000 ++ 792000 1175000 ++ 396000 1175000 ++ 198000 1175000 ++ >; ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++ fsl,arm-soc-shared = <0>; ++}; ++ ++&gpc { ++ fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-m4.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-m4.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-m4.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-m4.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-sdb.dts" ++ ++/{ ++ memory { ++ linux,usable-memory = <0x80000000 0x3ff00000>; ++ reg = <0x80000000 0x40000000>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++}; ++ ++/* ++ * The flollowing modules are conflicting with M4, disable them when m4 ++ * is running. ++ */ ++&flexcan1 { ++ status = "disabled"; ++}; ++ ++&flexcan2 { ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ status = "disabled"; ++}; ++ ++&mcctest{ ++ status = "okay"; ++}; ++ ++&mcctty{ ++ status = "okay"; ++}; ++ ++&uart2 { ++ status = "disabled"; ++}; ++ ++&adc1 { ++ status = "disabled"; ++}; ++ ++&adc2 { ++ status = "disabled"; ++}; ++ ++&qspi2 { ++ status = "disabled"; ++}; ++ ++&qspi_m4 { ++ status = "okay"; ++}; ++ ++&ocram { ++ reg = <0x00901000 0x1E000>; ++}; ++ ++&clks { ++ fsl,shared-clks-number = <0x23>; ++ fsl,shared-clks-index = ; ++ fsl,shared-mem-addr = <0x91F000>; ++ fsl,shared-mem-size = <0x1000>; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-reva.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-reva.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-reva.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-reva.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (C) 2015 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define SPANSIONFLASH ++#include "imx6sx-sdb.dts" ++ ++/* ++ * The CAN transceiver is changed on RevB board. ++ * This dts is used for support the old CAN transceiver on RevA board ++ */ ++ ++&cpu0 { ++ operating-points = < ++ /* kHz uV */ ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1075000 ++ 198000 975000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC uV */ ++ 996000 1175000 ++ 792000 1175000 ++ 396000 1175000 ++ 198000 1175000 ++ >; ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1c_reg>; ++ fsl,arm-soc-shared = <0>; ++}; ++ ++&flexcan1 { ++ trx-en-gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>; ++}; ++ ++&flexcan2 { ++ trx-en-gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>; ++}; ++ ++&pmic { ++ compatible = "fsl,pfuze100"; ++ ++ regulators { ++ sw1c_reg: sw1c { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ sw4_reg: sw4 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ }; ++}; ++ ++&qspi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_qspi2_1>; ++ status = "okay"; ++ ddrsmp=<0>; ++ ++ flash0: s25fl128s@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,s25fl128s"; ++ spi-max-frequency = <29000000>; ++ reg = <0>; ++ }; ++ ++ flash1: s25fl128s@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,s25fl128s"; ++ spi-max-frequency = <29000000>; ++ reg = <1>; ++ }; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-reva-ldo.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-reva-ldo.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-reva-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-reva-ldo.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2015 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 "imx6sx-sdb-reva.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++}; ++ ++&gpc { ++ fsl,ldo-bypass = <0>; /* use ldo-enable, u-boot will check it and configure */ ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-sai.dts linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-sai.dts +--- linux-3.14.72.orig/arch/arm/boot/dts/imx6sx-sdb-sai.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/boot/dts/imx6sx-sdb-sai.dts 2016-06-19 22:11:55.033157684 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include "imx6sx-sdb.dts" ++ ++/ { ++ sound { ++ cpu-dai = <&sai1>; ++ }; ++}; ++ ++&audmux { ++ /* pin conflict with sai */ ++ status = "disabled"; ++}; ++ ++&sai1 { ++ status = "okay"; ++}; ++ ++&sdma { ++ gpr = <&gpr>; ++ /* SDMA event remap for SAI1 */ ++ fsl,sdma-event-remap = <0 15 1>, <0 16 1>; ++}; +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/Makefile linux-3.14.72/arch/arm/boot/dts/Makefile +--- linux-3.14.72.orig/arch/arm/boot/dts/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/Makefile 2016-06-19 22:11:55.037157623 +0200 +@@ -153,22 +153,72 @@ + imx53-mba53.dtb \ + imx53-qsb.dtb \ + imx53-smd.dtb \ ++ imx6dl-cm-fx6.dtb \ + imx6dl-cubox-i.dtb \ + imx6dl-hummingboard.dtb \ ++ imx6dl-hummingboard2.dtb \ + imx6dl-sabreauto.dtb \ ++ imx6dl-sabreauto-flexcan1.dtb \ ++ imx6dl-sabreauto-ecspi.dtb \ ++ imx6dl-sabreauto-gpmi-weim.dtb \ + imx6dl-sabresd.dtb \ ++ imx6dl-sabresd-enetirq.dtb \ ++ imx6dl-sabresd-ldo.dtb \ ++ imx6dl-sabresd-pf200.dtb \ ++ imx6dl-sabresd-hdcp.dtb \ ++ imx6dl-udoo.dtb \ ++ imx6dl-sbc-fx6.dtb \ ++ imx6dl-sbc-fx6m.dtb \ + imx6dl-wandboard.dtb \ + imx6q-arm2.dtb \ ++ imx6q-auvidea.dtb \ ++ imx6q-cm-fx6.dtb \ + imx6q-cubox-i.dtb \ ++ imx6q-hummingboard.dtb \ ++ imx6q-hummingboard2.dtb \ + imx6q-phytec-pbab01.dtb \ + imx6q-sabreauto.dtb \ ++ imx6q-sabreauto-flexcan1.dtb \ ++ imx6q-sabreauto-ecspi.dtb \ ++ imx6q-sabreauto-gpmi-weim.dtb \ + imx6q-sabrelite.dtb \ + imx6q-sabresd.dtb \ ++ imx6q-sabresd-ldo.dtb \ ++ imx6q-sabresd-enetirq.dtb \ ++ imx6q-sabresd-uart.dtb \ ++ imx6q-sabresd-hdcp.dtb \ ++ imx6q-sabresd-ldo.dtb \ ++ imx6q-sbc-fx6.dtb \ ++ imx6q-sbc-fx6m.dtb \ + imx6q-sbc6x.dtb \ + imx6q-udoo.dtb \ + imx6q-wandboard.dtb \ ++ imx6q-tbs2910.dtb \ + imx6sl-evk.dtb \ ++ imx6sl-evk-csi.dtb \ ++ imx6sl-evk-ldo.dtb \ ++ imx6sl-evk-pf200.dtb \ ++ imx6sl-evk-uart.dtb \ ++ imx6sx-17x17-arm2.dtb \ ++ imx6sx-17x17-arm2-ldo.dtb \ ++ imx6sx-17x17-arm2-ecspi.dtb \ ++ imx6sx-17x17-arm2-gpmi-weim.dtb \ ++ imx6sx-17x17-arm2-mlb.dtb \ ++ imx6sx-19x19-arm2.dtb \ ++ imx6sx-19x19-arm2-ldo.dtb \ ++ imx6sx-19x19-arm2-csi.dtb \ ++ imx6sx-19x19-arm2-lcdif1.dtb \ ++ imx6sx-19x19-arm2-gpmi-weim.dtb \ ++ imx6sx-sdb.dtb \ ++ imx6sx-sdb-ldo.dtb \ ++ imx6sx-sdb-reva.dtb \ ++ imx6sx-sdb-reva-ldo.dtb \ ++ imx6sx-sabreauto.dtb \ ++ imx6sx-sabreauto-m4.dtb \ ++ imx6sx-sdb-lcdif1.dtb \ + vf610-cosmic.dtb \ ++ imx6sx-sdb-emmc.dtb \ ++ imx6sx-sdb-m4.dtb \ + vf610-twr.dtb + dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \ + imx23-olinuxino.dtb \ +diff -Nur linux-3.14.72.orig/arch/arm/boot/dts/marco.dtsi linux-3.14.72/arch/arm/boot/dts/marco.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/marco.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/marco.dtsi 2016-06-19 22:11:55.037157623 +0200 +@@ -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.72.orig/arch/arm/boot/dts/prima2.dtsi linux-3.14.72/arch/arm/boot/dts/prima2.dtsi +--- linux-3.14.72.orig/arch/arm/boot/dts/prima2.dtsi 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/boot/dts/prima2.dtsi 2016-06-19 22:11:55.037157623 +0200 +@@ -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.72.orig/arch/arm/configs/cm_fx6_defconfig linux-3.14.72/arch/arm/configs/cm_fx6_defconfig +--- linux-3.14.72.orig/arch/arm/configs/cm_fx6_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/configs/cm_fx6_defconfig 2016-06-19 22:11:55.037157623 +0200 +@@ -0,0 +1,443 @@ ++CONFIG_LOCALVERSION="-cm-fx6" ++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_IMX6SX=y ++CONFIG_SOC_VF610=y ++# CONFIG_SWP_EMULATE is not set ++CONFIG_PCI=y ++CONFIG_PCI_IMX6=y ++CONFIG_SMP=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT=y ++CONFIG_AEABI=y ++CONFIG_HIGHMEM=y ++CONFIG_CMA=y ++CONFIG_CMDLINE="console=ttymxc3,115200 root=/dev/mmcblk0p1 rootwait" ++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_IMX6Q_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_NETFILTER_DEBUG=y ++CONFIG_NF_CONNTRACK=m ++CONFIG_NF_CONNTRACK_FTP=m ++CONFIG_NF_CONNTRACK_TFTP=m ++CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m ++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m ++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m ++CONFIG_NETFILTER_XT_TARGET_DSCP=m ++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m ++CONFIG_NETFILTER_XT_TARGET_LED=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_TEE=m ++CONFIG_NETFILTER_XT_TARGET_TRACE=m ++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m ++CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m ++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m ++CONFIG_NETFILTER_XT_MATCH_CLUSTER=m ++CONFIG_NETFILTER_XT_MATCH_COMMENT=m ++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m ++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m ++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m ++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m ++CONFIG_NETFILTER_XT_MATCH_CPU=m ++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m ++CONFIG_NETFILTER_XT_MATCH_DSCP=m ++CONFIG_NETFILTER_XT_MATCH_ESP=m ++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m ++CONFIG_NETFILTER_XT_MATCH_HELPER=m ++CONFIG_NETFILTER_XT_MATCH_IPRANGE=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_OSF=m ++CONFIG_NETFILTER_XT_MATCH_OWNER=m ++CONFIG_NETFILTER_XT_MATCH_POLICY=m ++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=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_STATE=m ++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_NF_CONNTRACK_IPV4=m ++CONFIG_IP_NF_IPTABLES=y ++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_FILTER=y ++CONFIG_IP_NF_TARGET_REJECT=y ++CONFIG_IP_NF_TARGET_ULOG=m ++CONFIG_NF_NAT_IPV4=m ++CONFIG_IP_NF_TARGET_MASQUERADE=m ++CONFIG_IP_NF_TARGET_NETMAP=m ++CONFIG_IP_NF_TARGET_REDIRECT=m ++CONFIG_IP_NF_MANGLE=m ++CONFIG_IP_NF_TARGET_ECN=m ++CONFIG_IP_NF_TARGET_TTL=m ++CONFIG_IP_NF_RAW=m ++CONFIG_IP_NF_ARPTABLES=m ++CONFIG_IP_NF_ARPFILTER=m ++CONFIG_IP_NF_ARP_MANGLE=m ++CONFIG_VLAN_8021Q=m ++CONFIG_VLAN_8021Q_GVRP=y ++CONFIG_CAN=y ++CONFIG_CAN_FLEXCAN=y ++CONFIG_BT=m ++CONFIG_BT_MRVL=m ++CONFIG_BT_MRVL_SDIO=m ++CONFIG_CFG80211=y ++CONFIG_CFG80211_WEXT=y ++CONFIG_MAC80211=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++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_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=y ++CONFIG_SATA_AHCI_PLATFORM=y ++CONFIG_AHCI_IMX=y ++CONFIG_PATA_IMX=y ++CONFIG_NETDEVICES=y ++CONFIG_TUN=m ++# CONFIG_NET_VENDOR_BROADCOM is not set ++CONFIG_CS89x0=y ++CONFIG_CS89x0_PLATFORM=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++CONFIG_IGB=m ++# 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_MWIFIEX=m ++CONFIG_MWIFIEX_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_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_MUX_GPIO=y ++CONFIG_I2C_MUX_PCA954x=y ++# CONFIG_I2C_HELPER_AUTO is not set ++CONFIG_I2C_ALGOPCF=m ++CONFIG_I2C_ALGOPCA=m ++CONFIG_I2C_IMX=y ++CONFIG_SPI=y ++CONFIG_SPI_IMX=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_POWER_SUPPLY=y ++CONFIG_SABRESD_MAX8903=y ++CONFIG_IMX6_USB_CHARGER=y ++CONFIG_SENSORS_MAX17135=y ++CONFIG_SENSORS_MAG3110=y ++CONFIG_THERMAL=y ++CONFIG_CPU_THERMAL=y ++CONFIG_IMX_THERMAL=y ++CONFIG_DEVICE_THERMAL=y ++CONFIG_WATCHDOG=y ++CONFIG_IMX2_WDT=y ++CONFIG_MFD_DA9052_I2C=y ++CONFIG_MFD_MC13XXX_SPI=y ++CONFIG_MFD_MC13XXX_I2C=y ++CONFIG_MFD_MAX17135=y ++CONFIG_MFD_SI476X_CORE=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_REGULATOR_ANATOP=y ++CONFIG_REGULATOR_DA9052=y ++CONFIG_REGULATOR_MAX17135=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_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_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_VIDEO_MXC_CSI_CAMERA=m ++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_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_HANNSTAR_CABC=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_SOC_FSL_ASRC=y ++CONFIG_SND_SOC_FSL_SAI=y ++CONFIG_SND_SOC_FSL_SSI=y ++CONFIG_SND_SOC_FSL_ESAI=y ++CONFIG_SND_SOC_IMX_AUDMUX=y ++CONFIG_SND_IMX_SOC=y ++CONFIG_SND_SOC_IMX_SPDIF=y ++CONFIG_SND_SOC_IMX_HDMI=y ++CONFIG_SND_SOC_CS42XX8_I2C=y ++CONFIG_USB=y ++CONFIG_USB_OTG=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_MXC=y ++CONFIG_USB_EHCI_HCD_PLATFORM=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_CHIPIDEA=y ++CONFIG_USB_CHIPIDEA_UDC=y ++CONFIG_USB_CHIPIDEA_HOST=y ++CONFIG_NOP_USB_XCEIV=y ++CONFIG_USB_MXS_PHY=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_FSL_USB2=y ++CONFIG_USB_ZERO=m ++CONFIG_USB_AUDIO=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_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_EM3027=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_DRM_IMX=y ++CONFIG_DRM_IMX_FB_HELPER=y ++CONFIG_DRM_IMX_PARALLEL_DISPLAY=y ++CONFIG_DRM_IMX_LDB=y ++CONFIG_DRM_IMX_IPUV3_CORE=y ++CONFIG_DRM_IMX_IPUV3=y ++CONFIG_DRM_IMX_HDMI=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_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 ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y +diff -Nur linux-3.14.72.orig/arch/arm/configs/imx_v6_v7_defconfig linux-3.14.72/arch/arm/configs/imx_v6_v7_defconfig +--- linux-3.14.72.orig/arch/arm/configs/imx_v6_v7_defconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/configs/imx_v6_v7_defconfig 2016-06-19 22:11:55.037157623 +0200 +@@ -87,6 +87,7 @@ + CONFIG_MTD_NAND=y + CONFIG_MTD_NAND_GPMI_NAND=y + CONFIG_MTD_NAND_MXC=y ++CONFIG_MTD_SPI_NOR=y + CONFIG_MTD_UBI=y + CONFIG_BLK_DEV_LOOP=y + CONFIG_BLK_DEV_RAM=y +diff -Nur linux-3.14.72.orig/arch/arm/configs/imx_v7_cbi_hb_base_defconfig linux-3.14.72/arch/arm/configs/imx_v7_cbi_hb_base_defconfig +--- linux-3.14.72.orig/arch/arm/configs/imx_v7_cbi_hb_base_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/configs/imx_v7_cbi_hb_base_defconfig 2016-06-19 22:11:55.037157623 +0200 +@@ -0,0 +1,405 @@ ++# 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_CGROUP_DEBUG is not set ++CONFIG_CGROUP_FREEZER=y ++CONFIG_CGROUP_DEVICE=y ++CONFIG_CPUSETS=y ++CONFIG_PROC_PID_CPUSET=y ++CONFIG_CGROUP_CPUACCT=y ++CONFIG_RESOURCE_COUNTERS=y ++CONFIG_MEMCG=y ++CONFIG_MEMCG_SWAP=y ++CONFIG_MEMCG_SWAP_ENABLED=y ++CONFIG_MEMCG_KMEM=y ++# CONFIG_CGROUP_PERF is not set ++CONFIG_CGROUP_SCHED=y ++# CONFIG_CFS_BANDWIDTH is not set ++CONFIG_RT_GROUP_SCHED=y ++CONFIG_BLK_CGROUP=y ++# CONFIG_DEBUG_BLK_CGROUP is not set ++CONFIG_CHECKPOINT_RESTORE=y ++CONFIG_NAMESPACES=y ++CONFIG_UTS_NS=y ++CONFIG_IPC_NS=y ++CONFIG_USER_NS=y ++CONFIG_PID_NS=y ++CONFIG_NET_NS=y ++CONFIG_SCHED_AUTOGROUP=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_EXPERT=y ++CONFIG_PERF_EVENTS=y ++CONFIG_CLEANCACHE=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 is not set ++# CONFIG_SOC_IMX6SX is not set ++# CONFIG_SWP_EMULATE is not set ++CONFIG_PCI=y ++CONFIG_PCIE_DW=y ++CONFIG_PCI_IMX6=y ++CONFIG_SMP=y ++CONFIG_VMSPLIT_3G=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_ONDEMAND=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=y ++CONFIG_SUSPEND=y ++# CONFIG_PM_DEBUG is not set ++# CONFIG_PM_TEST_SUSPEND is not set ++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_SPI_SPIDEV=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_VIVANTE_GALCORE=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 is not set ++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_FANOTIFY=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_CRYPTODEV=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_JR=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 ++# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y ++# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE=7 ++# CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST is not set ++# CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO is not set ++# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set ++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.72.orig/arch/arm/configs/imx_v7_cbi_hb_defconfig linux-3.14.72/arch/arm/configs/imx_v7_cbi_hb_defconfig +--- linux-3.14.72.orig/arch/arm/configs/imx_v7_cbi_hb_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/configs/imx_v7_cbi_hb_defconfig 2016-06-19 22:11:55.037157623 +0200 +@@ -0,0 +1,5154 @@ ++# ++# 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_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_CGROUP_DEBUG is not set ++CONFIG_CGROUP_FREEZER=y ++CONFIG_CGROUP_DEVICE=y ++CONFIG_CPUSETS=y ++CONFIG_PROC_PID_CPUSET=y ++CONFIG_CGROUP_CPUACCT=y ++CONFIG_RESOURCE_COUNTERS=y ++CONFIG_MEMCG=y ++CONFIG_MEMCG_SWAP=y ++CONFIG_MEMCG_SWAP_ENABLED=y ++CONFIG_MEMCG_KMEM=y ++# CONFIG_CGROUP_PERF is not set ++CONFIG_CGROUP_SCHED=y ++CONFIG_RT_GROUP_SCHED=y ++CONFIG_BLK_CGROUP=y ++# CONFIG_DEBUG_BLK_CGROUP is not set ++CONFIG_CHECKPOINT_RESTORE=y ++CONFIG_NAMESPACES=y ++CONFIG_UTS_NS=y ++CONFIG_IPC_NS=y ++CONFIG_USER_NS=y ++CONFIG_PID_NS=y ++CONFIG_NET_NS=y ++CONFIG_SCHED_AUTOGROUP=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 is not set ++# CONFIG_SOC_IMX6SX is not set ++# CONFIG_SWP_EMULATE is not set ++CONFIG_PCI=y ++CONFIG_PCIE_DW=y ++CONFIG_PCI_IMX6=y ++CONFIG_SMP=y ++CONFIG_VMSPLIT_3G=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_ONDEMAND=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_DEBUG is not set ++# CONFIG_PM_TEST_SUSPEND is not set ++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_SPI_SPIDEV=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 is not set ++# CONFIG_MXC_CAMERA_OV5642 is not set ++CONFIG_MXC_CAMERA_OV5640_MIPI=m ++CONFIG_MXC_CAMERA_OV5647_MIPI=m ++CONFIG_MXC_HDMI_CSI2_TC358743=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_VIVANTE_GALCORE=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 is not set ++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_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=y ++CONFIG_CRYPTO_DEV_FSL_CAAM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_JR=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 ++# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y ++# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE=7 ++# CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST is not set ++# CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO is not set ++# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set ++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_XZ_DEC=y ++# CONFIG_XZ_DEC_X86 is not set ++# CONFIG_XZ_DEC_POWERPC is not set ++# CONFIG_XZ_DEC_IA64 is not set ++CONFIG_XZ_DEC_ARM=y ++CONFIG_XZ_DEC_ARMTHUMB=y ++# CONFIG_XZ_DEC_SPARC is not set ++CONFIG_XZ_DEC_BCJ=y ++# CONFIG_XZ_DEC_TEST is not set ++CONFIG_DECOMPRESS_GZIP=y ++ ++# ++# 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_NEEDED=y ++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=y ++CONFIG_F2FS_FS_XATTR=y ++CONFIG_F2FS_FS_POSIX_ACL=y ++CONFIG_F2FS_FS_SECURITY=y ++# CONFIG_F2FS_CHECK_FS is not set ++ ++ ++# ++# Network File Systems ++# ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_V2=y ++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_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_CRYPTODEV=y ++CONFIG_CRYPTO_MANAGER=y ++CONFIG_CRYPTO_MANAGER2=y ++CONFIG_CRYPTO_USER=y ++# 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_RD_GZIP=y ++CONFIG_RD_XZ=y ++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_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_RUNTIME=y ++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 is not set ++# 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_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 is not set ++# 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 ++ ++CONFIG_TEST_KSTRTOX=y ++ ++# 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.72.orig/arch/arm/configs/imx_v7_defconfig linux-3.14.72/arch/arm/configs/imx_v7_defconfig +--- linux-3.14.72.orig/arch/arm/configs/imx_v7_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/configs/imx_v7_defconfig 2016-06-19 22:11:55.037157623 +0200 +@@ -0,0 +1,414 @@ ++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_KALLSYMS_ALL=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_MACH_IMX51_DT=y ++CONFIG_MACH_EUKREA_CPUIMX51SD=y ++CONFIG_SOC_IMX50=y ++CONFIG_SOC_IMX53=y ++CONFIG_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++CONFIG_SOC_IMX6SX=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_HIGHMEM=y ++CONFIG_CMA=y ++CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_KEXEC=y ++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_IMX6Q_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_LLC2=y ++CONFIG_CAN=y ++CONFIG_CAN_FLEXCAN=y ++CONFIG_CAN_M_CAN=y ++CONFIG_BT=y ++CONFIG_BT_RFCOMM=y ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_BNEP=y ++CONFIG_BT_BNEP_MC_FILTER=y ++CONFIG_BT_BNEP_PROTO_FILTER=y ++CONFIG_BT_HIDP=y ++CONFIG_BT_HCIBTUSB=y ++CONFIG_BT_HCIBTSDIO=y ++CONFIG_BT_HCIUART=y ++CONFIG_BT_HCIUART_H4=y ++CONFIG_BT_HCIUART_BCSP=y ++CONFIG_BT_HCIUART_ATH3K=y ++CONFIG_BT_HCIBCM203X=y ++CONFIG_BT_ATH3K=y ++CONFIG_CFG80211=y ++CONFIG_MAC80211=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_DMA_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_SPI_NOR=y ++CONFIG_SPI_FSL_QUADSPI=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_USB_PEGASUS=m ++CONFIG_USB_RTL8150=m ++CONFIG_USB_RTL8152=m ++CONFIG_USB_USBNET=m ++CONFIG_USB_NET_CDC_EEM=m ++CONFIG_ATH_CARDS=y ++CONFIG_ATH6KL=m ++CONFIG_ATH6KL_SDIO=m ++CONFIG_BRCMFMAC=m ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=m ++CONFIG_KEYBOARD_GPIO=y ++CONFIG_KEYBOARD_SNVS_PWRKEY=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_TOUCHSCREEN_TSC2007=y ++CONFIG_TOUCHSCREEN_STMPE=y ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_MMA8450=y ++CONFIG_INPUT_ISL29023=y ++CONFIG_SERIO_SERPORT=m ++# 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_MFD_STMPE=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_REGULATOR_ANATOP=y ++CONFIG_REGULATOR_DA9052=y ++CONFIG_REGULATOR_MAX17135=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_MEDIA_RC_SUPPORT=y ++CONFIG_RC_DEVICES=y ++CONFIG_IR_GPIO_CIR=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_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_VIDEO_MXC_CSI_CAMERA=m ++CONFIG_MXC_VADC=m ++CONFIG_SOC_CAMERA=y ++CONFIG_VIDEO_MX3=y ++CONFIG_V4L_MEM2MEM_DRIVERS=y ++CONFIG_VIDEO_CODA=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_FB_MXC_DCIC=m ++CONFIG_HANNSTAR_CABC=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=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_MQS=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_EHCI_MXC=y ++CONFIG_USB_ACM=m ++CONFIG_USB_STORAGE=y ++CONFIG_USB_CHIPIDEA=y ++CONFIG_USB_CHIPIDEA_UDC=y ++CONFIG_USB_CHIPIDEA_HOST=y ++CONFIG_USB_SERIAL=m ++CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_FTDI_SIO=m ++CONFIG_USB_SERIAL_OPTION=m ++CONFIG_USB_EHSET_TEST_FIXTURE=m ++CONFIG_NOP_USB_XCEIV=y ++CONFIG_USB_MXS_PHY=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_CONFIGFS=m ++CONFIG_USB_CONFIGFS_SERIAL=y ++CONFIG_USB_CONFIGFS_ACM=y ++CONFIG_USB_CONFIGFS_OBEX=y ++CONFIG_USB_CONFIGFS_NCM=y ++CONFIG_USB_CONFIGFS_ECM=y ++CONFIG_USB_CONFIGFS_ECM_SUBSET=y ++CONFIG_USB_CONFIGFS_RNDIS=y ++CONFIG_USB_CONFIGFS_EEM=y ++CONFIG_USB_CONFIGFS_MASS_STORAGE=y ++CONFIG_USB_CONFIGFS_F_LB_SS=y ++CONFIG_USB_CONFIGFS_F_FS=y ++CONFIG_USB_ZERO=m ++CONFIG_USB_ETH=m ++CONFIG_USB_G_NCM=m ++CONFIG_USB_GADGETFS=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_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_TIMER=y ++CONFIG_LEDS_TRIGGER_ONESHOT=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_BACKLIGHT=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_STAGING_MEDIA=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_IIO=y ++CONFIG_VF610_ADC=y ++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_DEBUG_FS=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_GCM=y ++CONFIG_CRYPTO_CBC=y ++CONFIG_CRYPTO_CTS=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_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 ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y +diff -Nur linux-3.14.72.orig/arch/arm/configs/imx_v7_mfg_defconfig linux-3.14.72/arch/arm/configs/imx_v7_mfg_defconfig +--- linux-3.14.72.orig/arch/arm/configs/imx_v7_mfg_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/configs/imx_v7_mfg_defconfig 2016-06-19 22:11:55.037157623 +0200 +@@ -0,0 +1,332 @@ ++# 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_KALLSYMS_ALL=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_ARCH_MULTI_V6=y ++CONFIG_GPIO_PCA953X=y ++CONFIG_ARCH_MXC=y ++# CONFIG_MACH_MX31ADS is not set ++# CONFIG_MACH_BUG is not set ++CONFIG_MACH_IMX51_DT=y ++CONFIG_MACH_EUKREA_CPUIMX51SD=y ++CONFIG_SOC_IMX50=y ++CONFIG_SOC_IMX53=y ++CONFIG_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++CONFIG_SOC_IMX6SX=y ++CONFIG_SOC_VF610=y ++CONFIG_SMP=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT=y ++CONFIG_AEABI=y ++CONFIG_HIGHMEM=y ++CONFIG_CMA=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_IMX6Q_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_CFG80211=y ++CONFIG_MAC80211=y ++CONFIG_RFKILL=y ++CONFIG_RFKILL_INPUT=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_DMA_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_SPI_NOR=y ++CONFIG_SPI_FSL_QUADSPI=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_AT803X_PHY=y ++CONFIG_BRCMFMAC=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_MC13783=y ++CONFIG_TOUCHSCREEN_TSC2007=y ++CONFIG_TOUCHSCREEN_STMPE=y ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_MMA8450=y ++CONFIG_SERIO_SERPORT=m ++# CONFIG_LEGACY_PTYS is not set ++# CONFIG_DEVKMEM is not set ++CONFIG_SERIAL_IMX=y ++CONFIG_SERIAL_IMX_CONSOLE=y ++CONFIG_SERIAL_FSL_LPUART=y ++CONFIG_SERIAL_FSL_LPUART_CONSOLE=y ++CONFIG_HW_RANDOM=y ++CONFIG_IMX_SEMA4=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_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 ++CONFIG_MFD_MC13XXX_SPI=y ++CONFIG_MFD_MC13XXX_I2C=y ++CONFIG_MFD_STMPE=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_REGULATOR_ANATOP=y ++CONFIG_REGULATOR_DA9052=y ++CONFIG_REGULATOR_MC13783=y ++CONFIG_REGULATOR_MC13892=y ++CONFIG_REGULATOR_PFUZE100=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++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_VIDEO_MXC_PXP_V4L2=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_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_MXC_EINK_AUTO_UPDATE_MODE=y ++CONFIG_FB_MXS_SII902X=y ++CONFIG_HANNSTAR_CABC=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y ++CONFIG_LOGO=y ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_SOC=y ++CONFIG_SND_IMX_SOC=y ++CONFIG_SND_SOC_EUKREA_TLV320=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_USB=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_MXC=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_CHIPIDEA=y ++CONFIG_USB_CHIPIDEA_UDC=y ++CONFIG_USB_CHIPIDEA_HOST=y ++CONFIG_NOP_USB_XCEIV=y ++CONFIG_USB_MXS_PHY=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_ETH=m ++CONFIG_USB_PHY=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_MIPI_CSI2=y ++CONFIG_MXC_MLB150=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_ONESHOT=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_BACKLIGHT=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_STAGING_MEDIA=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_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC7=m ++CONFIG_LIBCRC32C=m ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y +diff -Nur linux-3.14.72.orig/arch/arm/configs/mxs_defconfig linux-3.14.72/arch/arm/configs/mxs_defconfig +--- linux-3.14.72.orig/arch/arm/configs/mxs_defconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/configs/mxs_defconfig 2016-06-19 22:11:55.037157623 +0200 +@@ -55,6 +55,7 @@ + CONFIG_MTD_SST25L=y + CONFIG_MTD_NAND=y + CONFIG_MTD_NAND_GPMI_NAND=y ++CONFIG_MTD_SPI_NOR=y + CONFIG_MTD_UBI=y + # CONFIG_BLK_DEV is not set + CONFIG_EEPROM_AT24=y +diff -Nur linux-3.14.72.orig/arch/arm/include/asm/atomic.h linux-3.14.72/arch/arm/include/asm/atomic.h +--- linux-3.14.72.orig/arch/arm/include/asm/atomic.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/atomic.h 2016-06-19 22:11:55.037157623 +0200 +@@ -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.72.orig/arch/arm/include/asm/cmpxchg.h linux-3.14.72/arch/arm/include/asm/cmpxchg.h +--- linux-3.14.72.orig/arch/arm/include/asm/cmpxchg.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/cmpxchg.h 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/include/asm/futex.h linux-3.14.72/arch/arm/include/asm/futex.h +--- linux-3.14.72.orig/arch/arm/include/asm/futex.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/futex.h 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/include/asm/glue-proc.h linux-3.14.72/arch/arm/include/asm/glue-proc.h +--- linux-3.14.72.orig/arch/arm/include/asm/glue-proc.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/glue-proc.h 2016-06-19 22:11:55.041157465 +0200 +@@ -221,15 +221,6 @@ + # endif + #endif + +-#ifdef CONFIG_CPU_V7 +-# ifdef CPU_NAME +-# undef MULTI_CPU +-# define MULTI_CPU +-# else +-# define CPU_NAME cpu_v7 +-# endif +-#endif +- + #ifdef CONFIG_CPU_V7M + # ifdef CPU_NAME + # undef MULTI_CPU +@@ -248,6 +239,15 @@ + # endif + #endif + ++#ifdef CONFIG_CPU_V7 ++/* ++ * Cortex-A9 needs a different suspend/resume function, so we need ++ * multiple CPU support for ARMv7 anyway. ++ */ ++# undef MULTI_CPU ++# define MULTI_CPU ++#endif ++ + #ifndef MULTI_CPU + #define cpu_proc_init __glue(CPU_NAME,_proc_init) + #define cpu_proc_fin __glue(CPU_NAME,_proc_fin) +diff -Nur linux-3.14.72.orig/arch/arm/include/asm/hardware/cache-l2x0.h linux-3.14.72/arch/arm/include/asm/hardware/cache-l2x0.h +--- linux-3.14.72.orig/arch/arm/include/asm/hardware/cache-l2x0.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/hardware/cache-l2x0.h 2016-06-19 22:11:55.041157465 +0200 +@@ -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,85 @@ + #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_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 L2X0_ADDR_FILTER_EN 1 ++#define L310_ADDR_FILTER_EN 1 + + #define L2X0_CTRL_EN 1 + +diff -Nur linux-3.14.72.orig/arch/arm/include/asm/Kbuild linux-3.14.72/arch/arm/include/asm/Kbuild +--- linux-3.14.72.orig/arch/arm/include/asm/Kbuild 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/Kbuild 2016-06-19 22:11:55.041157465 +0200 +@@ -18,6 +18,7 @@ + generic-y += parport.h + generic-y += poll.h + generic-y += resource.h ++generic-y += rwsem.h + generic-y += sections.h + generic-y += segment.h + generic-y += sembuf.h +diff -Nur linux-3.14.72.orig/arch/arm/include/asm/outercache.h linux-3.14.72/arch/arm/include/asm/outercache.h +--- linux-3.14.72.orig/arch/arm/include/asm/outercache.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/outercache.h 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/include/asm/smp_plat.h linux-3.14.72/arch/arm/include/asm/smp_plat.h +--- linux-3.14.72.orig/arch/arm/include/asm/smp_plat.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/asm/smp_plat.h 2016-06-19 22:11:55.041157465 +0200 +@@ -89,6 +89,7 @@ + return 1 << mpidr_hash.bits; + } + ++extern int platform_can_secondary_boot(void); + extern int platform_can_cpu_hotplug(void); + + #endif +diff -Nur linux-3.14.72.orig/arch/arm/include/debug/imx.S linux-3.14.72/arch/arm/include/debug/imx.S +--- linux-3.14.72.orig/arch/arm/include/debug/imx.S 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/debug/imx.S 2016-06-19 22:11:55.041157465 +0200 +@@ -19,12 +19,11 @@ + * globally for multi-platform build to use a fixed virtual address + * for low-level debug uart port across platforms. + */ +-#define IMX_IO_P2V(x) ( \ +- (((x) & 0x80000000) >> 7) | \ +- (0xf4000000 + \ +- (((x) & 0x50000000) >> 6) + \ +- (((x) & 0x0b000000) >> 4) + \ +- (((x) & 0x000fffff)))) ++#define IMX_IO_P2V(x) ( \ ++ (0xf4000000 + \ ++ (((x) & 0x50000000) >> 4) + \ ++ (((x) & 0x0a000000) >> 4) + \ ++ (((x) & 0x00ffffff)))) + + #define UART_VADDR IMX_IO_P2V(UART_PADDR) + +diff -Nur linux-3.14.72.orig/arch/arm/include/debug/imx-uart.h linux-3.14.72/arch/arm/include/debug/imx-uart.h +--- linux-3.14.72.orig/arch/arm/include/debug/imx-uart.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/include/debug/imx-uart.h 2016-06-19 22:11:55.041157465 +0200 +@@ -81,6 +81,15 @@ + #define IMX6SL_UART_BASE_ADDR(n) IMX6SL_UART##n##_BASE_ADDR + #define IMX6SL_UART_BASE(n) IMX6SL_UART_BASE_ADDR(n) + ++#define IMX6SX_UART1_BASE_ADDR 0x02020000 ++#define IMX6SX_UART2_BASE_ADDR 0x021e8000 ++#define IMX6SX_UART3_BASE_ADDR 0x021ec000 ++#define IMX6SX_UART4_BASE_ADDR 0x021f0000 ++#define IMX6SX_UART5_BASE_ADDR 0x021f4000 ++#define IMX6SX_UART6_BASE_ADDR 0x022a0000 ++#define IMX6SX_UART_BASE_ADDR(n) IMX6SX_UART##n##_BASE_ADDR ++#define IMX6SX_UART_BASE(n) IMX6SX_UART_BASE_ADDR(n) ++ + #define IMX_DEBUG_UART_BASE(soc) soc##_UART_BASE(CONFIG_DEBUG_IMX_UART_PORT) + + #ifdef CONFIG_DEBUG_IMX1_UART +@@ -103,6 +112,8 @@ + #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6Q) + #elif defined(CONFIG_DEBUG_IMX6SL_UART) + #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SL) ++#elif defined(CONFIG_DEBUG_IMX6SX_UART) ++#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SX) + #endif + + #endif /* __DEBUG_IMX_UART_H */ +diff -Nur linux-3.14.72.orig/arch/arm/Kconfig linux-3.14.72/arch/arm/Kconfig +--- linux-3.14.72.orig/arch/arm/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/Kconfig 2016-06-19 22:11:55.041157465 +0200 +@@ -168,12 +168,9 @@ + bool + default y + +-config RWSEM_GENERIC_SPINLOCK +- bool +- default y +- + config RWSEM_XCHGADD_ALGORITHM + bool ++ default y + + config ARCH_HAS_ILOG2_U32 + bool +@@ -1216,19 +1213,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 +1235,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 +1260,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 +1308,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 +@@ -1835,6 +1781,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.72.orig/arch/arm/Kconfig.debug linux-3.14.72/arch/arm/Kconfig.debug +--- linux-3.14.72.orig/arch/arm/Kconfig.debug 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/Kconfig.debug 2016-06-19 22:11:55.041157465 +0200 +@@ -321,6 +321,13 @@ + Say Y here if you want kernel low-level debugging support + on i.MX6SL. + ++ config DEBUG_IMX6SX_UART ++ bool "i.MX6SX Debug UART" ++ depends on SOC_IMX6SX ++ help ++ Say Y here if you want kernel low-level debugging support ++ on i.MX6SX. ++ + config DEBUG_KEYSTONE_UART0 + bool "Kernel low-level debugging on KEYSTONE2 using UART0" + depends on ARCH_KEYSTONE +@@ -939,7 +946,8 @@ + DEBUG_IMX51_UART || \ + DEBUG_IMX53_UART || \ + DEBUG_IMX6Q_UART || \ +- DEBUG_IMX6SL_UART ++ DEBUG_IMX6SL_UART || \ ++ DEBUG_IMX6SX_UART + default 1 + depends on ARCH_MXC + help +@@ -974,7 +982,8 @@ + DEBUG_IMX51_UART || \ + DEBUG_IMX53_UART ||\ + DEBUG_IMX6Q_UART || \ +- DEBUG_IMX6SL_UART ++ DEBUG_IMX6SL_UART || \ ++ DEBUG_IMX6SX_UART + default "debug/msm.S" if DEBUG_MSM_UART + default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART + default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1 +diff -Nur linux-3.14.72.orig/arch/arm/kernel/machine_kexec.c linux-3.14.72/arch/arm/kernel/machine_kexec.c +--- linux-3.14.72.orig/arch/arm/kernel/machine_kexec.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/kernel/machine_kexec.c 2016-06-19 22:11:55.041157465 +0200 +@@ -45,7 +45,8 @@ + * and implements CPU hotplug for the current HW. If not, we won't be + * able to kexec reliably, so fail the prepare operation. + */ +- if (num_possible_cpus() > 1 && !platform_can_cpu_hotplug()) ++ if (num_possible_cpus() > 1 && platform_can_secondary_boot() && ++ !platform_can_cpu_hotplug()) + return -EINVAL; + + /* +diff -Nur linux-3.14.72.orig/arch/arm/kernel/process.c linux-3.14.72/arch/arm/kernel/process.c +--- linux-3.14.72.orig/arch/arm/kernel/process.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/kernel/process.c 2016-06-19 22:11:55.041157465 +0200 +@@ -149,6 +149,7 @@ + + void arch_cpu_idle_enter(void) + { ++ idle_notifier_call_chain(IDLE_START); + ledtrig_cpu(CPU_LED_IDLE_START); + #ifdef CONFIG_PL310_ERRATA_769419 + wmb(); +@@ -158,6 +159,7 @@ + void arch_cpu_idle_exit(void) + { + ledtrig_cpu(CPU_LED_IDLE_END); ++ idle_notifier_call_chain(IDLE_END); + } + + #ifdef CONFIG_HOTPLUG_CPU +diff -Nur linux-3.14.72.orig/arch/arm/kernel/setup.c linux-3.14.72/arch/arm/kernel/setup.c +--- linux-3.14.72.orig/arch/arm/kernel/setup.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/kernel/setup.c 2016-06-19 22:11:55.041157465 +0200 +@@ -1089,3 +1089,12 @@ + .stop = c_stop, + .show = c_show + }; ++ ++/* export the cache management functions */ ++#ifndef MULTI_CACHE ++ ++EXPORT_SYMBOL(__glue(_CACHE,_dma_map_area)); ++EXPORT_SYMBOL(__glue(_CACHE,_dma_unmap_area)); ++EXPORT_SYMBOL(__glue(_CACHE,_dma_flush_range)); ++ ++#endif +diff -Nur linux-3.14.72.orig/arch/arm/kernel/smp.c linux-3.14.72/arch/arm/kernel/smp.c +--- linux-3.14.72.orig/arch/arm/kernel/smp.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/kernel/smp.c 2016-06-19 22:11:55.041157465 +0200 +@@ -146,6 +146,11 @@ + return -ENOSYS; + } + ++int platform_can_secondary_boot(void) ++{ ++ return !!smp_ops.smp_boot_secondary; ++} ++ + int platform_can_cpu_hotplug(void) + { + #ifdef CONFIG_HOTPLUG_CPU +diff -Nur linux-3.14.72.orig/arch/arm/kernel/smp_scu.c linux-3.14.72/arch/arm/kernel/smp_scu.c +--- linux-3.14.72.orig/arch/arm/kernel/smp_scu.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/kernel/smp_scu.c 2016-06-19 22:11:55.041157465 +0200 +@@ -17,6 +17,8 @@ + #include + + #define SCU_CTRL 0x00 ++#define SCU_ENABLE (1 << 0) ++#define SCU_STANDBY_ENABLE (1 << 5) + #define SCU_CONFIG 0x04 + #define SCU_CPU_STATUS 0x08 + #define SCU_INVALIDATE 0x0c +@@ -50,10 +52,16 @@ + + scu_ctrl = readl_relaxed(scu_base + SCU_CTRL); + /* already enabled? */ +- if (scu_ctrl & 1) ++ if (scu_ctrl & SCU_ENABLE) + return; + +- scu_ctrl |= 1; ++ scu_ctrl |= SCU_ENABLE; ++ ++ /* Cortex-A9 earlier than r2p0 has no standby bit in SCU */ ++ if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090 && ++ (read_cpuid_id() & 0x00f0000f) >= 0x00200000) ++ scu_ctrl |= SCU_STANDBY_ENABLE; ++ + writel_relaxed(scu_ctrl, scu_base + SCU_CTRL); + + /* +diff -Nur linux-3.14.72.orig/arch/arm/lib/bitops.h linux-3.14.72/arch/arm/lib/bitops.h +--- linux-3.14.72.orig/arch/arm/lib/bitops.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/lib/bitops.h 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/mach-berlin/berlin.c linux-3.14.72/arch/arm/mach-berlin/berlin.c +--- linux-3.14.72.orig/arch/arm/mach-berlin/berlin.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-berlin/berlin.c 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/mach-cns3xxx/core.c linux-3.14.72/arch/arm/mach-cns3xxx/core.c +--- linux-3.14.72.orig/arch/arm/mach-cns3xxx/core.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-cns3xxx/core.c 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/mach-exynos/common.c linux-3.14.72/arch/arm/mach-exynos/common.c +--- linux-3.14.72.orig/arch/arm/mach-exynos/common.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-exynos/common.c 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/mach-highbank/highbank.c linux-3.14.72/arch/arm/mach-highbank/highbank.c +--- linux-3.14.72.orig/arch/arm/mach-highbank/highbank.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-highbank/highbank.c 2016-06-19 22:11:55.041157465 +0200 +@@ -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.72.orig/arch/arm/mach-imx/anatop.c linux-3.14.72/arch/arm/mach-imx/anatop.c +--- linux-3.14.72.orig/arch/arm/mach-imx/anatop.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/anatop.c 2016-06-19 22:11:55.041157465 +0200 +@@ -30,8 +30,11 @@ + #define ANADIG_DIGPROG_IMX6SL 0x280 + + #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 ++#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8 + #define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 + #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 ++/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */ ++#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000 + #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000 + #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000 + +@@ -56,16 +59,43 @@ + BM_ANADIG_REG_CORE_FET_ODRIVE); + } + ++static inline void imx_anatop_enable_2p5_pulldown(bool enable) ++{ ++ regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR), ++ BM_ANADIG_REG_2P5_ENABLE_PULLDOWN); ++} ++ ++static inline void imx_anatop_disconnect_high_snvs(bool enable) ++{ ++ regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR), ++ BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); ++} ++ + void imx_anatop_pre_suspend(void) + { +- imx_anatop_enable_weak2p5(true); ++ if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) ++ imx_anatop_enable_2p5_pulldown(true); ++ else ++ imx_anatop_enable_weak2p5(true); ++ + imx_anatop_enable_fet_odrive(true); ++ ++ if (cpu_is_imx6sl()) ++ imx_anatop_disconnect_high_snvs(true); + } + + void imx_anatop_post_resume(void) + { ++ if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) ++ imx_anatop_enable_2p5_pulldown(false); ++ else ++ imx_anatop_enable_weak2p5(false); ++ + imx_anatop_enable_fet_odrive(false); +- imx_anatop_enable_weak2p5(false); ++ ++ if (cpu_is_imx6sl()) ++ imx_anatop_disconnect_high_snvs(false); ++ + } + + static void imx_anatop_usb_chrg_detect_disable(void) +@@ -104,6 +134,19 @@ + 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: ++ /* ++ * i.MX6DQ TO1.5 is defined as Rev 1.3 in Data Sheet, marked ++ * as 'D' in Part Number last character. ++ */ ++ revision = IMX_CHIP_REVISION_1_5; ++ break; + default: + revision = IMX_CHIP_REVISION_UNKNOWN; + } +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/busfreq_ddr3.c linux-3.14.72/arch/arm/mach-imx/busfreq_ddr3.c +--- linux-3.14.72.orig/arch/arm/mach-imx/busfreq_ddr3.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/busfreq_ddr3.c 2016-06-19 22:11:55.045157162 +0200 +@@ -0,0 +1,656 @@ ++/* ++ * Copyright (C) 2011-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 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 ++ ++#include "hardware.h" ++ ++ ++/* ++ * This structure is for passing necessary data for low level ocram ++ * busfreq code(arch/arm/mach-imx/ddr3_freq_imx6.S), if this struct ++ * definition is changed, the offset definition in ++ * arch/arm/mach-imx/ddr3_freq_imx6.S must be also changed accordingly, ++ * otherwise, the busfreq change function will be broken! ++ * ++ * This structure will be placed in front of the asm code on ocram. ++ */ ++struct imx6_busfreq_info { ++ u32 freq; ++ void *ddr_settings; ++ u32 dll_off; ++ void *iomux_offsets; ++ u32 mu_delay_val; ++} __aligned(8); ++ ++static struct imx6_busfreq_info *imx6sx_busfreq_info; ++ ++/* 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 *gic_dist_base; ++ ++static int ddr_settings_size; ++static int iomux_settings_size; ++static int curr_ddr_rate; ++ ++void (*imx6sx_change_ddr_freq)(struct imx6_busfreq_info *busfreq_info); ++extern void imx6sx_ddr3_freq_change(struct imx6_busfreq_info *busfreq_info); ++ ++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); ++ ++extern unsigned long save_ttbr1(void); ++extern void restore_ttbr1(unsigned long ttbr1); ++extern unsigned long ddr_freq_change_iram_base; ++ ++extern unsigned long ddr_freq_change_total_size; ++extern unsigned long iram_tlb_phys_addr; ++ ++extern unsigned long mx6_ddr3_freq_change_start asm("mx6_ddr3_freq_change_start"); ++extern unsigned long mx6_ddr3_freq_change_end asm("mx6_ddr3_freq_change_end"); ++extern unsigned long imx6sx_ddr3_freq_change_start asm("imx6sx_ddr3_freq_change_start"); ++extern unsigned long imx6sx_ddr3_freq_change_end asm("imx6sx_ddr3_freq_change_end"); ++#ifdef CONFIG_SMP ++#ifdef CONFIG_SOC_IMX6Q ++static unsigned long wfe_freq_change_iram_base; ++#endif ++u32 *wait_for_ddr_freq_update; ++static unsigned int online_cpus; ++static u32 *irqs_used; ++ ++void (*wfe_change_ddr_freq)(u32 cpuid, u32 *ddr_freq_change_done); ++extern void wfe_ddr3_freq_change(u32 cpuid, u32 *ddr_freq_change_done); ++extern unsigned long wfe_ddr3_freq_change_start asm("wfe_ddr3_freq_change_start"); ++extern unsigned long wfe_ddr3_freq_change_end asm("wfe_ddr3_freq_change_end"); ++extern void __iomem *imx_scu_base; ++#endif ++ ++#define MIN_DLL_ON_FREQ 333000000 ++#define MAX_DLL_OFF_FREQ 125000000 ++#define MMDC0_MPMUR0 0x8b8 ++#define MMDC0_MPMUR0_OFFSET 16 ++#define MMDC0_MPMUR0_MASK 0x3ff ++ ++unsigned long ddr3_dll_mx6sx[][2] = { ++ {0x0c, 0x0}, ++ {0x10, 0x0}, ++ {0x1C, 0x04008032}, ++ {0x1C, 0x00048031}, ++ {0x1C, 0x05208030}, ++ {0x1C, 0x04008040}, ++ {0x818, 0x0}, ++}; ++ ++unsigned long ddr3_calibration_mx6sx[][2] = { ++ {0x83c, 0x0}, ++ {0x840, 0x0}, ++ {0x848, 0x0}, ++ {0x850, 0x0}, ++}; ++ ++unsigned long iomux_offsets_mx6sx[][2] = { ++ {0x330, 0x0}, ++ {0x334, 0x0}, ++ {0x338, 0x0}, ++ {0x33c, 0x0}, ++}; ++ ++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; ++} ++ ++#ifdef CONFIG_SMP ++/* ++ * 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; ++ ++ me = smp_processor_id(); ++#ifdef CONFIG_LOCAL_TIMERS ++ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, ++ &me); ++#endif ++ wfe_change_ddr_freq(0xff << (me * 8), (u32 *)&iram_iomux_settings[0][1]); ++ ++#ifdef CONFIG_LOCAL_TIMERS ++ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, ++ &me); ++#endif ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++int update_ddr_freq_imx6sx(int ddr_rate) ++{ ++ int i; ++ bool dll_off = false; ++ unsigned long ttbr1; ++ ++ 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; ++ ++ imx6sx_busfreq_info->dll_off = dll_off; ++ iram_ddr_settings[0][0] = ddr_settings_size; ++ iram_iomux_settings[0][0] = iomux_settings_size; ++ 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]; ++ } ++ ++ local_irq_disable(); ++ ++ ttbr1 = save_ttbr1(); ++ imx6sx_busfreq_info->freq = ddr_rate; ++ imx6sx_busfreq_info->ddr_settings = iram_ddr_settings; ++ imx6sx_busfreq_info->iomux_offsets = iram_iomux_settings; ++ imx6sx_busfreq_info->mu_delay_val = ((readl_relaxed(mmdc_base + MMDC0_MPMUR0) ++ >> MMDC0_MPMUR0_OFFSET) & MMDC0_MPMUR0_MASK); ++ ++ imx6sx_change_ddr_freq(imx6sx_busfreq_info); ++ restore_ttbr1(ttbr1); ++ curr_ddr_rate = ddr_rate; ++ ++ local_irq_enable(); ++ ++ pr_debug("Bus freq set to %d done!\n", ddr_rate); ++ ++ return 0; ++} ++ ++/* change the DDR frequency. */ ++int update_ddr_freq_imx6q(int ddr_rate) ++{ ++ int i, j; ++ bool dll_off = false; ++ int me = 0; ++ unsigned long ttbr1; ++#ifdef CONFIG_SMP ++ unsigned int reg; ++ int cpu = 0; ++#endif ++ ++ 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(); ++ ++#ifdef CONFIG_SMP ++ me = smp_processor_id(); ++ ++ /* Make sure all the online cores are active */ ++ while (1) { ++ bool not_exited_busfreq = false; ++ for_each_online_cpu(cpu) { ++ u32 reg = __raw_readl(imx_scu_base + 0x08); ++ if (reg & (0x02 << (cpu * 8))) ++ not_exited_busfreq = true; ++ } ++ if (!not_exited_busfreq) ++ break; ++ } ++ ++ wmb(); ++ *wait_for_ddr_freq_update = 1; ++ dsb(); ++ ++ online_cpus = readl_relaxed(imx_scu_base + 0x08); ++ for_each_online_cpu(cpu) { ++ *((char *)(&online_cpus) + (u8)cpu) = 0x02; ++ 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); ++ } ++ } ++ /* Wait for the other active CPUs to idle */ ++ while (1) { ++ u32 reg = readl_relaxed(imx_scu_base + 0x08); ++ reg |= (0x02 << (me * 8)); ++ if (reg == online_cpus) ++ break; ++ } ++#endif ++ ++ /* Ensure iram_tlb_phys_addr is flushed to DDR. */ ++ __cpuc_flush_dcache_area(&iram_tlb_phys_addr, sizeof(iram_tlb_phys_addr)); ++ outer_clean_range(virt_to_phys(&iram_tlb_phys_addr), virt_to_phys(&iram_tlb_phys_addr + 1)); ++ ++ ttbr1 = save_ttbr1(); ++ /* Now we can change the DDR frequency. */ ++ mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, ++ dll_off, iram_iomux_settings); ++ restore_ttbr1(ttbr1); ++ curr_ddr_rate = ddr_rate; ++ ++#ifdef CONFIG_SMP ++ wmb(); ++ /* DDR frequency change is done . */ ++ *wait_for_ddr_freq_update = 0; ++ dsb(); ++ ++ /* wake up all the cores. */ ++ sev(); ++#endif ++ ++ local_irq_enable(); ++ ++ pr_debug("Bus freq set to %d done! cpu=%d\n", ddr_rate, me); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SOC_IMX6SX ++int init_mmdc_ddr3_settings_imx6sx(struct platform_device *busfreq_pdev) ++{ ++ int i; ++ struct device_node *node; ++ unsigned long ddr_code_size; ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc"); ++ if (!node) { ++ printk(KERN_ERR "failed to find mmdc device tree data!\n"); ++ return -EINVAL; ++ } ++ mmdc_base = of_iomap(node, 0); ++ WARN(!mmdc_base, "unable to map mmdc registers\n"); ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-iomuxc"); ++ if (!node) { ++ printk(KERN_ERR "failed to find iomuxc device tree data!\n"); ++ return -EINVAL; ++ } ++ iomux_base = of_iomap(node, 0); ++ WARN(!iomux_base, "unable to map iomux registers\n"); ++ ++ ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6sx) + ++ ARRAY_SIZE(ddr3_calibration_mx6sx); ++ ++ normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL); ++ memcpy(normal_mmdc_settings, ddr3_dll_mx6sx, ++ sizeof(ddr3_dll_mx6sx)); ++ memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6sx)), ++ ddr3_calibration_mx6sx, sizeof(ddr3_calibration_mx6sx)); ++ ++ /* 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]); ++ } ++ ++ iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6sx); ++ ++ ddr_code_size = (&imx6sx_ddr3_freq_change_end -&imx6sx_ddr3_freq_change_start) *4 + ++ sizeof(*imx6sx_busfreq_info); ++ ++ imx6sx_busfreq_info = (struct imx6_busfreq_info *)ddr_freq_change_iram_base; ++ ++ imx6sx_change_ddr_freq = (void *)fncpy((void *)ddr_freq_change_iram_base + sizeof(*imx6sx_busfreq_info), ++ &imx6sx_ddr3_freq_change, ddr_code_size - sizeof(*imx6sx_busfreq_info)); ++ ++ /* ++ * Store the size of the array in iRAM also, ++ * increase the size by 8 bytes. ++ */ ++ iram_iomux_settings = (void *)(ddr_freq_change_iram_base + ddr_code_size); ++ iram_ddr_settings = iram_iomux_settings + (iomux_settings_size * 8) + 8; ++ ++ if ((ddr_code_size + (iomux_settings_size + ddr_settings_size) * 8 + 16) ++ > ddr_freq_change_total_size) { ++ printk(KERN_ERR "Not enough memory allocated for DDR Frequency change code.\n"); ++ return EINVAL; ++ } ++ ++ for (i = 0; i < iomux_settings_size; i++) { ++ iomux_offsets_mx6sx[i][1] = ++ readl_relaxed(iomux_base + ++ iomux_offsets_mx6sx[i][0]); ++ iram_iomux_settings[i + 1][0] = ++ iomux_offsets_mx6sx[i][0]; ++ iram_iomux_settings[i + 1][1] = ++ iomux_offsets_mx6sx[i][1]; ++ } ++ ++ curr_ddr_rate = ddr_normal_rate; ++ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_SOC_IMX6Q ++int init_mmdc_ddr3_settings_imx6q(struct platform_device *busfreq_pdev) ++{ ++ int i; ++ struct device_node *node; ++ unsigned long ddr_code_size; ++ unsigned long wfe_code_size = 0; ++#ifdef CONFIG_SMP ++ u32 cpu; ++ struct device *dev = &busfreq_pdev->dev; ++ int err; ++#endif ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc-combine"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-mmdc device tree data!\n"); ++ return -EINVAL; ++ } ++ mmdc_base = of_iomap(node, 0); ++ WARN(!mmdc_base, "unable to map mmdc registers\n"); ++ ++ node = NULL; ++ if (cpu_is_imx6q()) ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-iomuxc"); ++ if (cpu_is_imx6dl()) ++ node = of_find_compatible_node(NULL, NULL, ++ "fsl,imx6dl-iomuxc"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-iomux device tree data!\n"); ++ return -EINVAL; ++ } ++ iomux_base = of_iomap(node, 0); ++ WARN(!iomux_base, "unable to map iomux registers\n"); ++ ++ node = NULL; ++ node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-a9-gic device tree data!\n"); ++ return -EINVAL; ++ } ++ gic_dist_base = of_iomap(node, 0); ++ WARN(!gic_dist_base, "unable to map gic dist registers\n"); ++ ++ if (cpu_is_imx6q()) ++ ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6q) + ++ ARRAY_SIZE(ddr3_calibration); ++ if (cpu_is_imx6dl()) ++ ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6dl) + ++ ARRAY_SIZE(ddr3_calibration); ++ ++ normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL); ++ if (cpu_is_imx6q()) { ++ memcpy(normal_mmdc_settings, ddr3_dll_mx6q, ++ sizeof(ddr3_dll_mx6q)); ++ memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6q)), ++ ddr3_calibration, sizeof(ddr3_calibration)); ++ } ++ if (cpu_is_imx6dl()) { ++ memcpy(normal_mmdc_settings, ddr3_dll_mx6dl, ++ sizeof(ddr3_dll_mx6dl)); ++ memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6dl)), ++ ddr3_calibration, sizeof(ddr3_calibration)); ++ } ++ /* store the original DDR settings at boot. */ ++ for (i = 0; i < ddr_settings_size; i++) { ++ /* ++ * writes via command mode register cannot be read back. ++ * hence hardcode them in the initial static array. ++ * this may require modification on a per customer basis. ++ */ ++ if (normal_mmdc_settings[i][0] != 0x1C) ++ normal_mmdc_settings[i][1] = ++ readl_relaxed(mmdc_base ++ + normal_mmdc_settings[i][0]); ++ } ++ ++#ifdef CONFIG_SMP ++ 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; ++ } ++#endif ++ iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q); ++ ++ ddr_code_size = (&mx6_ddr3_freq_change_end -&mx6_ddr3_freq_change_start) *4; ++ ++ mx6_change_ddr_freq = (void *)fncpy((void *)ddr_freq_change_iram_base, ++ &mx6_ddr3_freq_change, ddr_code_size); ++ ++ /* ++ * Store the size of the array in iRAM also, ++ * increase the size by 8 bytes. ++ */ ++ iram_iomux_settings = (void *)(ddr_freq_change_iram_base + ddr_code_size); ++ iram_ddr_settings = iram_iomux_settings + (iomux_settings_size * 8) + 8; ++ ++#ifdef CONFIG_SMP ++ wfe_freq_change_iram_base = (unsigned long)((u32 *)iram_ddr_settings + (ddr_settings_size * 8) + 8); ++ ++ if (wfe_freq_change_iram_base & (FNCPY_ALIGN - 1)) ++ wfe_freq_change_iram_base += FNCPY_ALIGN - ((uintptr_t)wfe_freq_change_iram_base % (FNCPY_ALIGN)); ++ ++ wfe_code_size = (&wfe_ddr3_freq_change_end -&wfe_ddr3_freq_change_start) *4; ++ ++ wfe_change_ddr_freq = (void *)fncpy((void *)wfe_freq_change_iram_base, ++ &wfe_ddr3_freq_change, wfe_code_size); ++ ++ /* Store the variable used to communicate between cores in a non-cacheable IRAM area */ ++ wait_for_ddr_freq_update = (u32 *)&iram_iomux_settings[0][1]; ++#endif ++ ++ if ((ddr_code_size + wfe_code_size + (iomux_settings_size + ddr_settings_size) * 8 + 16) ++ > ddr_freq_change_total_size) { ++ printk(KERN_ERR "Not enough memory allocated for DDR Frequency change code.\n"); ++ return EINVAL; ++ } ++ ++ 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]; ++ } ++ } ++ ++ curr_ddr_rate = ddr_normal_rate; ++ ++ return 0; ++} ++#endif +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/busfreq-imx6.c linux-3.14.72/arch/arm/mach-imx/busfreq-imx6.c +--- linux-3.14.72.orig/arch/arm/mach-imx/busfreq-imx6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/busfreq-imx6.c 2016-06-19 22:11:55.045157162 +0200 +@@ -0,0 +1,1268 @@ ++/* ++ * Copyright (C) 2011-2015 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 ++#include ++#include "clk.h" ++#include "hardware.h" ++#include "common.h" ++ ++#define LPAPM_CLK 24000000 ++#define DDR3_AUDIO_CLK 50000000 ++#define LPDDR2_AUDIO_CLK 100000000 ++ ++#define MMDC_MDMISC_DDR_TYPE_DDR3 0 ++#define MMDC_MDMISC_DDR_TYPE_LPDDR2 1 ++ ++#ifdef CONFIG_SOC_IMX6SX ++static int ddr_type; ++#endif ++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; ++unsigned long ddr_freq_change_total_size; ++unsigned long ddr_freq_change_iram_base; ++unsigned long ddr_freq_change_iram_phys; ++ ++static int bus_freq_scaling_initialized; ++static struct device *busfreq_dev; ++static int busfreq_suspended; ++#ifdef CONFIG_SOC_IMX6SL ++static u32 org_arm_rate; ++#endif ++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 unsigned long iram_tlb_phys_addr; ++extern int unsigned long iram_tlb_base_addr; ++ ++extern int init_mmdc_lpddr2_settings(struct platform_device *dev); ++extern int init_mmdc_ddr3_settings_imx6q(struct platform_device *dev); ++extern int init_mmdc_ddr3_settings_imx6sx(struct platform_device *dev); ++extern int update_ddr_freq_imx6q(int ddr_rate); ++extern int update_ddr_freq_imx6sx(int ddr_rate); ++extern int update_lpddr2_freq(int ddr_rate); ++ ++DEFINE_MUTEX(bus_freq_mutex); ++ ++static struct clk *mmdc_clk; ++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_bus; ++static struct clk *pll2_bypass_src; ++static struct clk *pll2_bypass; ++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_alt_sel_clk; ++static struct clk *axi_sel_clk; ++static struct clk *pll3_pfd1_540m; ++static struct clk *m4_clk; ++static struct clk *pll1; ++static struct clk *pll1_bypass; ++static struct clk *pll1_bypass_src; ++ ++#ifdef CONFIG_SOC_IMX6SL ++static u32 pll2_org_rate; ++#endif ++static struct delayed_work low_bus_freq_handler; ++static struct delayed_work bus_freq_daemon; ++ ++static RAW_NOTIFIER_HEAD(busfreq_notifier_chain); ++ ++static int busfreq_notify(enum busfreq_event event) ++{ ++ int ret; ++ ++ ret = raw_notifier_call_chain(&busfreq_notifier_chain, event, NULL); ++ ++ return notifier_to_errno(ret); ++} ++ ++int register_busfreq_notifier(struct notifier_block *nb) ++{ ++ return raw_notifier_chain_register(&busfreq_notifier_chain, nb); ++} ++EXPORT_SYMBOL(register_busfreq_notifier); ++ ++int unregister_busfreq_notifier(struct notifier_block *nb) ++{ ++ return raw_notifier_chain_unregister(&busfreq_notifier_chain, nb); ++} ++EXPORT_SYMBOL(unregister_busfreq_notifier); ++ ++#ifdef CONFIG_SOC_IMX6SX ++static bool check_m4_sleep(void) ++{ ++ unsigned long timeout = jiffies + msecs_to_jiffies(500); ++ ++ while (imx_gpc_is_m4_sleeping() == 0) ++ if (time_after(jiffies, timeout)) ++ return false; ++ return true; ++} ++ ++static void enter_lpm_imx6sx(void) ++{ ++ if (imx_src_is_m4_enabled()) ++ if (!check_m4_sleep()) ++ pr_err("M4 is NOT in sleep!!!\n"); ++ ++ /* set periph_clk2 to source from OSC for periph */ ++ imx_clk_set_parent(periph_clk2_sel, osc_clk); ++ imx_clk_set_parent(periph_clk, periph_clk2); ++ /* set ahb/ocram to 24MHz */ ++ imx_clk_set_rate(ahb_clk, LPAPM_CLK); ++ imx_clk_set_rate(ocram_clk, LPAPM_CLK); ++ ++ if (audio_bus_count) { ++ /* Need to ensure that PLL2_PFD_400M is kept ON. */ ++ clk_prepare_enable(pll2_400); ++ if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) ++ update_ddr_freq_imx6sx(DDR3_AUDIO_CLK); ++ else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) ++ update_lpddr2_freq(LPDDR2_AUDIO_CLK); ++ imx_clk_set_parent(periph2_clk2_sel, pll3); ++ imx_clk_set_parent(periph2_pre_clk, pll2_400); ++ imx_clk_set_parent(periph2_clk, periph2_pre_clk); ++ /* ++ * As periph2_clk's parent is not changed from ++ * high mode to audio mode, so clk framework ++ * will not update its children's freq, but we ++ * change the mmdc's podf in asm code, so here ++ * need to update mmdc rate to make sure clk ++ * tree is right, although it will not do any ++ * change to hardware. ++ */ ++ if (high_bus_freq_mode) { ++ if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) ++ imx_clk_set_rate(mmdc_clk, DDR3_AUDIO_CLK); ++ else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) ++ imx_clk_set_rate(mmdc_clk, LPDDR2_AUDIO_CLK); ++ } ++ audio_bus_freq_mode = 1; ++ low_bus_freq_mode = 0; ++ } else { ++ if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) ++ update_ddr_freq_imx6sx(LPAPM_CLK); ++ else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) ++ update_lpddr2_freq(LPAPM_CLK); ++ imx_clk_set_parent(periph2_clk2_sel, osc_clk); ++ imx_clk_set_parent(periph2_clk, periph2_clk2); ++ ++ if (audio_bus_freq_mode) ++ clk_disable_unprepare(pll2_400); ++ low_bus_freq_mode = 1; ++ audio_bus_freq_mode = 0; ++ } ++} ++ ++static void exit_lpm_imx6sx(void) ++{ ++ clk_prepare_enable(pll2_400); ++ ++ /* ++ * lower ahb/ocram's freq first to avoid too high ++ * freq during parent switch from OSC to pll3. ++ */ ++ imx_clk_set_rate(ahb_clk, LPAPM_CLK / 3); ++ imx_clk_set_rate(ocram_clk, LPAPM_CLK / 2); ++ /* set periph_clk2 to pll3 */ ++ imx_clk_set_parent(periph_clk2_sel, pll3); ++ /* set periph clk to from pll2_400 */ ++ imx_clk_set_parent(periph_pre_clk, pll2_400); ++ imx_clk_set_parent(periph_clk, periph_pre_clk); ++ ++ if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) ++ update_ddr_freq_imx6sx(ddr_normal_rate); ++ else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) ++ update_lpddr2_freq(ddr_normal_rate); ++ /* correct parent info after ddr freq change in asm code */ ++ imx_clk_set_parent(periph2_pre_clk, pll2_400); ++ imx_clk_set_parent(periph2_clk, periph2_pre_clk); ++ imx_clk_set_parent(periph2_clk2_sel, pll3); ++ ++ /* ++ * As periph2_clk's parent is not changed from ++ * audio mode to high mode, so clk framework ++ * will not update its children's freq, but we ++ * change the mmdc's podf in asm code, so here ++ * need to update mmdc rate to make sure clk ++ * tree is right, although it will not do any ++ * change to hardware. ++ */ ++ if (audio_bus_freq_mode) ++ imx_clk_set_rate(mmdc_clk, ddr_normal_rate); ++ ++ clk_disable_unprepare(pll2_400); ++ ++ if (audio_bus_freq_mode) ++ clk_disable_unprepare(pll2_400); ++} ++#endif ++ ++#ifdef CONFIG_SOC_IMX6SL ++static void enter_lpm_imx6sl(void) ++{ ++ if (high_bus_freq_mode) { ++ pll2_org_rate = clk_get_rate(pll2_bus); ++ /* Set periph_clk to be sourced from OSC_CLK */ ++ imx_clk_set_parent(periph_clk2_sel, osc_clk); ++ imx_clk_set_parent(periph_clk, periph_clk2); ++ /* Ensure AHB/AXI clks are at 24MHz. */ ++ imx_clk_set_rate(ahb_clk, LPAPM_CLK); ++ imx_clk_set_rate(ocram_clk, LPAPM_CLK); ++ } ++ if (audio_bus_count) { ++ /* Set AHB to 8MHz to lower pwer.*/ ++ imx_clk_set_rate(ahb_clk, LPAPM_CLK / 3); ++ ++ /* Set up DDR to 100MHz. */ ++ update_lpddr2_freq(LPDDR2_AUDIO_CLK); ++ ++ /* Fix the clock tree in kernel */ ++ imx_clk_set_parent(periph2_pre_clk, pll2_200); ++ imx_clk_set_parent(periph2_clk, periph2_pre_clk); ++ ++ if (low_bus_freq_mode || ultra_low_bus_freq_mode) { ++ /* ++ * Fix the clock tree in kernel, make sure ++ * pll2_bypass is updated as it is ++ * sourced from PLL2. ++ */ ++ imx_clk_set_parent(pll2_bypass, pll2); ++ /* ++ * Swtich ARM to run off PLL2_PFD2_400MHz ++ * since DDR is anyway at 100MHz. ++ */ ++ imx_clk_set_parent(step_clk, pll2_400); ++ imx_clk_set_parent(pll1_sw_clk, step_clk); ++ /* ++ * Need to ensure that PLL1 is bypassed and enabled ++ * before ARM-PODF is set. ++ */ ++ clk_set_parent(pll1_bypass, pll1_bypass_src); ++ ++ /* ++ * Ensure that the clock will be ++ * at original speed. ++ */ ++ imx_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) { ++ /* ++ * Anyway, make sure the AHB is running at 24MHz ++ * in low_bus_freq_mode. ++ */ ++ if (audio_bus_freq_mode) ++ imx_clk_set_rate(ahb_clk, LPAPM_CLK); ++ /* ++ * 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. ++ * To work well with CPUFREQ we want to ensure that ++ * the CPU freq does not change, so attempt to ++ * get a freq as close to 396MHz as possible. ++ */ ++ imx_clk_set_rate(pll1, ++ clk_round_rate(pll1, (org_arm_rate * 2))); ++ pll1_rate = clk_get_rate(pll1); ++ arm_div = pll1_rate / org_arm_rate; ++ if (pll1_rate / arm_div > org_arm_rate) ++ arm_div++; ++ /* ++ * Need to ensure that PLL1 is bypassed and enabled ++ * before ARM-PODF is set. ++ */ ++ clk_set_parent(pll1_bypass, pll1); ++ /* ++ * Ensure ARM CLK is lower before ++ * changing the parent. ++ */ ++ imx_clk_set_rate(cpu_clk, org_arm_rate / arm_div); ++ /* Now set the ARM clk parent to PLL1_SYS. */ ++ imx_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. ++ */ ++ imx_clk_set_parent(step_clk, osc_clk); ++ /* Now set DDR to 24MHz. */ ++ update_lpddr2_freq(LPAPM_CLK); ++ ++ /* ++ * Fix the clock tree in kernel. ++ * Make sure PLL2 rate is updated as it gets ++ * bypassed in the DDR freq change code. ++ */ ++ imx_clk_set_parent(pll2_bypass, pll2_bypass_src); ++ imx_clk_set_parent(periph2_clk2_sel, pll2_bus); ++ imx_clk_set_parent(periph2_clk, periph2_clk2); ++ ++ } ++ 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) ++{ ++ /* Change DDR freq in IRAM. */ ++ update_lpddr2_freq(ddr_normal_rate); ++ ++ /* ++ * Fix the clock tree in kernel. ++ * Make sure PLL2 rate is updated as it gets ++ * un-bypassed in the DDR freq change code. ++ */ ++ imx_clk_set_parent(pll2_bypass, pll2); ++ imx_clk_set_parent(periph2_pre_clk, pll2_400); ++ imx_clk_set_parent(periph2_clk, periph2_pre_clk); ++ ++ /* Ensure that periph_clk is sourced from PLL2_400. */ ++ imx_clk_set_parent(periph_pre_clk, pll2_400); ++ /* ++ * Before switching the perhiph_clk, ensure that the ++ * AHB/AXI will not be too fast. ++ */ ++ imx_clk_set_rate(ahb_clk, LPAPM_CLK / 3); ++ imx_clk_set_rate(ocram_clk, LPAPM_CLK / 2); ++ imx_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. */ ++ imx_clk_set_parent(step_clk, pll2_400); ++ imx_clk_set_parent(pll1_sw_clk, step_clk); ++ /* ++ * Need to ensure that PLL1 is bypassed and enabled ++ * before ARM-PODF is set. ++ */ ++ clk_set_parent(pll1_bypass, pll1_bypass_src); ++ imx_clk_set_rate(cpu_clk, org_arm_rate); ++ ultra_low_bus_freq_mode = 0; ++ } ++} ++#endif ++ ++static void reduce_bus_freq(void) ++{ ++ clk_prepare_enable(pll3); ++ if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode)) ++ busfreq_notify(LOW_BUSFREQ_EXIT); ++ else if (!audio_bus_count) ++ busfreq_notify(LOW_BUSFREQ_ENTER); ++ switch(__mxc_cpu_type) { ++ case MXC_CPU_IMX6SL: ++#ifdef CONFIG_SOC_IMX6SL ++ enter_lpm_imx6sl(); ++#endif ++ break; ++ case MXC_CPU_IMX6SX: ++#ifdef CONFIG_SOC_IMX6SX ++ enter_lpm_imx6sx(); ++#endif ++ break; ++ default: ++#ifdef CONFIG_SOC_IMX6Q ++ if (cpu_is_imx6dl()) ++ /* Set axi to periph_clk */ ++ imx_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_imx6q(DDR3_AUDIO_CLK); ++ /* Make sure periph clk's parent also got updated */ ++ imx_clk_set_parent(periph_clk2_sel, pll3); ++ imx_clk_set_parent(periph_pre_clk, pll2_200); ++ imx_clk_set_parent(periph_clk, periph_pre_clk); ++ audio_bus_freq_mode = 1; ++ low_bus_freq_mode = 0; ++ } else { ++ update_ddr_freq_imx6q(LPAPM_CLK); ++ /* Make sure periph clk's parent also got updated */ ++ imx_clk_set_parent(periph_clk2_sel, osc_clk); ++ /* Set periph_clk parent to OSC via periph_clk2_sel */ ++ imx_clk_set_parent(periph_clk, periph_clk2); ++ if (audio_bus_freq_mode) ++ clk_disable_unprepare(pll2_400); ++ low_bus_freq_mode = 1; ++ audio_bus_freq_mode = 0; ++ } ++#endif ++ break; ++ } ++ 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); ++} ++ ++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. ++ */ ++static int set_high_bus_freq(int high_bus_freq) ++{ ++ 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_bus; ++ 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; ++ ++ if (low_bus_freq_mode || ultra_low_bus_freq_mode) ++ busfreq_notify(LOW_BUSFREQ_EXIT); ++ ++ clk_prepare_enable(pll3); ++ ++ switch(__mxc_cpu_type) { ++ case MXC_CPU_IMX6SL: ++#ifdef CONFIG_SOC_IMX6SL ++ exit_lpm_imx6sl(); ++#endif ++ break; ++ case MXC_CPU_IMX6SX: ++#ifdef CONFIG_SOC_IMX6SX ++ exit_lpm_imx6sx(); ++#endif ++ break; ++ default: ++#ifdef CONFIG_SOC_IMX6Q ++ if (high_bus_freq) { ++ clk_prepare_enable(pll2_400); ++ update_ddr_freq_imx6q(ddr_normal_rate); ++ /* Make sure periph clk's parent also got updated */ ++ imx_clk_set_parent(periph_clk2_sel, pll3); ++ imx_clk_set_parent(periph_pre_clk, periph_clk_parent); ++ imx_clk_set_parent(periph_clk, periph_pre_clk); ++ if (cpu_is_imx6dl()) { ++ /* Set axi to pll3_pfd1_540m */ ++ imx_clk_set_parent(axi_alt_sel_clk, pll3_pfd1_540m); ++ imx_clk_set_parent(axi_sel_clk, axi_alt_sel_clk); ++ } ++ clk_disable_unprepare(pll2_400); ++ } else { ++ update_ddr_freq_imx6q(ddr_med_rate); ++ /* Make sure periph clk's parent also got updated */ ++ imx_clk_set_parent(periph_clk2_sel, pll3); ++ imx_clk_set_parent(periph_pre_clk, pll2_400); ++ imx_clk_set_parent(periph_clk, periph_pre_clk); ++ } ++ if (audio_bus_freq_mode) ++ clk_disable_unprepare(pll2_400); ++#endif ++ break; ++ } ++ ++ high_bus_freq_mode = 1; ++ med_bus_freq_mode = 0; ++ low_bus_freq_mode = 0; ++ audio_bus_freq_mode = 0; ++ ++ clk_disable_unprepare(pll3); ++ if (high_bus_freq_mode) ++ dev_dbg(busfreq_dev, "Bus freq set to high mode. Count:\ ++ high %d, med %d, audio %d\n", ++ high_bus_count, med_bus_count, audio_bus_count); ++ if (med_bus_freq_mode) ++ dev_dbg(busfreq_dev, "Bus freq set to med mode. Count:\ ++ high %d, med %d, audio %d\n", ++ high_bus_count, med_bus_count, audio_bus_count); ++ ++ return 0; ++} ++ ++void request_bus_freq(enum bus_freq_mode mode) ++{ ++ mutex_lock(&bus_freq_mutex); ++ ++ if (mode == BUS_FREQ_HIGH) ++ high_bus_count++; ++ else if (mode == BUS_FREQ_MED) ++ med_bus_count++; ++ else if (mode == BUS_FREQ_AUDIO) ++ audio_bus_count++; ++ else if (mode == BUS_FREQ_LOW) ++ low_bus_count++; ++ ++ if (busfreq_suspended || !bus_freq_scaling_initialized || ++ !bus_freq_scaling_is_active) { ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ cancel_delayed_work_sync(&low_bus_freq_handler); ++ ++ if (cpu_is_imx6dl() || cpu_is_imx6sx()) { ++ /* No support for medium setpoint on i.MX6DL and i.MX6SX. */ ++ if (mode == BUS_FREQ_MED) { ++ high_bus_count++; ++ mode = BUS_FREQ_HIGH; ++ } ++ } ++ ++ if ((mode == BUS_FREQ_HIGH) && (!high_bus_freq_mode)) { ++ set_high_bus_freq(1); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ ++ if ((mode == BUS_FREQ_MED) && (!high_bus_freq_mode) && ++ (!med_bus_freq_mode)) { ++ set_high_bus_freq(0); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) && ++ (!med_bus_freq_mode) && (!audio_bus_freq_mode)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ mutex_unlock(&bus_freq_mutex); ++ return; ++} ++EXPORT_SYMBOL(request_bus_freq); ++ ++void release_bus_freq(enum bus_freq_mode mode) ++{ ++ mutex_lock(&bus_freq_mutex); ++ ++ if (mode == BUS_FREQ_HIGH) { ++ if (high_bus_count == 0) { ++ dev_err(busfreq_dev, "high bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ high_bus_count--; ++ } else if (mode == BUS_FREQ_MED) { ++ if (med_bus_count == 0) { ++ dev_err(busfreq_dev, "med bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ med_bus_count--; ++ } else if (mode == BUS_FREQ_AUDIO) { ++ if (audio_bus_count == 0) { ++ dev_err(busfreq_dev, "audio bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ audio_bus_count--; ++ } else if (mode == BUS_FREQ_LOW) { ++ if (low_bus_count == 0) { ++ dev_err(busfreq_dev, "low bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ low_bus_count--; ++ } ++ ++ if (busfreq_suspended || !bus_freq_scaling_initialized || ++ !bus_freq_scaling_is_active) { ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ ++ if (cpu_is_imx6dl() || cpu_is_imx6sx()) { ++ /* No support for medium setpoint on i.MX6DL and i.MX6SX. */ ++ if (mode == BUS_FREQ_MED) { ++ high_bus_count--; ++ mode = BUS_FREQ_HIGH; ++ } ++ } ++ ++ if ((!audio_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count != 0)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ if ((!low_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count == 0) && ++ (low_bus_count != 0)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ if ((!ultra_low_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count == 0) && ++ (low_bus_count == 0)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ ++ mutex_unlock(&bus_freq_mutex); ++ return; ++} ++EXPORT_SYMBOL(release_bus_freq); ++ ++static struct map_desc ddr_iram_io_desc __initdata = { ++ /* .virtual and .pfn are run-time assigned */ ++ .length = SZ_1M, ++ .type = MT_MEMORY_RWX_NONCACHED, ++}; ++ ++const static char *ddr_freq_iram_match[] __initconst = { ++ "fsl,ddr-lpm-sram", ++ NULL ++}; ++ ++static int __init imx6_dt_find_ddr_sram(unsigned long node, ++ const char *uname, int depth, void *data) ++{ ++ unsigned long ddr_iram_addr; ++ __be32 *prop; ++ ++ if (of_flat_dt_match(node, ddr_freq_iram_match)) { ++ unsigned long len; ++ prop = of_get_flat_dt_prop(node, "reg", &len); ++ if (prop == NULL || len != (sizeof(unsigned long) * 2)) ++ return EINVAL; ++ ddr_iram_addr = be32_to_cpu(prop[0]); ++ ddr_freq_change_total_size = be32_to_cpu(prop[1]); ++ ddr_freq_change_iram_phys = ddr_iram_addr; ++ ++ /* Make sure ddr_freq_change_iram_phys is 8 byte aligned. */ ++ if ((uintptr_t)(ddr_freq_change_iram_phys) & (FNCPY_ALIGN - 1)) ++ ddr_freq_change_iram_phys += FNCPY_ALIGN - ((uintptr_t)ddr_freq_change_iram_phys % (FNCPY_ALIGN)); ++ } ++ return 0; ++} ++ ++void __init imx6_busfreq_map_io(void) ++{ ++ /* ++ * Get the address of IRAM to be used by the ddr frequency ++ * change code from the device tree. ++ */ ++ WARN_ON(of_scan_flat_dt(imx6_dt_find_ddr_sram, NULL)); ++ ++ if (ddr_freq_change_iram_phys) { ++ ddr_freq_change_iram_base = IMX_IO_P2V(ddr_freq_change_iram_phys); ++ if ((iram_tlb_phys_addr & 0xFFF00000) != (ddr_freq_change_iram_phys & 0xFFF00000)) { ++ /* We need to create a 1M page table entry. */ ++ ddr_iram_io_desc.virtual = IMX_IO_P2V(ddr_freq_change_iram_phys & 0xFFF00000); ++ ddr_iram_io_desc.pfn = __phys_to_pfn(ddr_freq_change_iram_phys & 0xFFF00000); ++ iotable_init(&ddr_iram_io_desc, 1); ++ } ++ memset((void *)ddr_freq_change_iram_base, 0, ddr_freq_change_total_size); ++ } ++} ++ ++static void bus_freq_daemon_handler(struct work_struct *work) ++{ ++ mutex_lock(&bus_freq_mutex); ++ if ((!low_bus_freq_mode) && (!ultra_low_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count == 0)) ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++} ++ ++static ssize_t bus_freq_scaling_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ if (bus_freq_scaling_is_active) ++ return sprintf(buf, "Bus frequency scaling is enabled\n"); ++ else ++ return sprintf(buf, "Bus frequency scaling is disabled\n"); ++} ++ ++static ssize_t bus_freq_scaling_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ if (strncmp(buf, "1", 1) == 0) { ++ bus_freq_scaling_is_active = 1; ++ set_high_bus_freq(1); ++ /* ++ * We set bus freq to highest at the beginning, ++ * so we use this daemon thread to make sure system ++ * can enter low bus mode if ++ * there is no high bus request pending ++ */ ++ schedule_delayed_work(&bus_freq_daemon, ++ usecs_to_jiffies(5000000)); ++ } else if (strncmp(buf, "0", 1) == 0) { ++ if (bus_freq_scaling_is_active) ++ set_high_bus_freq(1); ++ bus_freq_scaling_is_active = 0; ++ } ++ return size; ++} ++ ++static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event, ++ void *dummy) ++{ ++ mutex_lock(&bus_freq_mutex); ++ ++ if (event == PM_SUSPEND_PREPARE) { ++ high_bus_count++; ++ set_high_bus_freq(1); ++ busfreq_suspended = 1; ++ } else if (event == PM_POST_SUSPEND) { ++ busfreq_suspended = 0; ++ high_bus_count--; ++ schedule_delayed_work(&bus_freq_daemon, ++ usecs_to_jiffies(5000000)); ++ } ++ ++ mutex_unlock(&bus_freq_mutex); ++ ++ return NOTIFY_OK; ++} ++ ++static int busfreq_reboot_notifier_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ /* System is rebooting. Set the system into high_bus_freq_mode. */ ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ return 0; ++} ++ ++static struct notifier_block imx_bus_freq_pm_notifier = { ++ .notifier_call = bus_freq_pm_notify, ++}; ++ ++static struct notifier_block imx_busfreq_reboot_notifier = { ++ .notifier_call = busfreq_reboot_notifier_event, ++}; ++ ++ ++static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show, ++ bus_freq_scaling_enable_store); ++ ++/*! ++ * This is the probe routine for the bus frequency driver. ++ * ++ * @param pdev The platform device structure ++ * ++ * @return The function returns 0 on success ++ * ++ */ ++ ++static int busfreq_probe(struct platform_device *pdev) ++{ ++ u32 err; ++ ++ busfreq_dev = &pdev->dev; ++ ++ /* Return if no IRAM space is allocated for ddr freq change code. */ ++ if (!ddr_freq_change_iram_base) ++ return ENOMEM; ++ ++ 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_bus = devm_clk_get(&pdev->dev, "pll2_bus"); ++ if (IS_ERR(pll2_bus)) { ++ dev_err(busfreq_dev, "%s: failed to get pll2_bus\n", ++ __func__); ++ return PTR_ERR(pll2_bus); ++ } ++ ++ 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_alt_sel_clk = devm_clk_get(&pdev->dev, "axi_alt_sel"); ++ if (IS_ERR(axi_alt_sel_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get axi_alt_sel_clk\n", ++ __func__); ++ return PTR_ERR(axi_alt_sel_clk); ++ } ++ ++ 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() || cpu_is_imx6sx()) { ++ 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); ++ } ++ ++ 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(step_clk); ++ } ++ } ++ if (cpu_is_imx6sl()) { ++ pll1 = devm_clk_get(&pdev->dev, "pll1"); ++ if (IS_ERR(pll1)) { ++ dev_err(busfreq_dev, "%s: failed to get pll1\n", ++ __func__); ++ return PTR_ERR(pll1); ++ } ++ ++ pll1_bypass = devm_clk_get(&pdev->dev, "pll1_bypass"); ++ if (IS_ERR(pll1_bypass)) { ++ dev_err(busfreq_dev, "%s: failed to get pll1_bypass\n", ++ __func__); ++ return PTR_ERR(pll1_bypass); ++ } ++ ++ pll1_bypass_src = devm_clk_get(&pdev->dev, "pll1_bypass_src"); ++ if (IS_ERR(pll1_bypass_src)) { ++ dev_err(busfreq_dev, "%s: failed to get pll1_bypass_src\n", ++ __func__); ++ return PTR_ERR(pll1_bypass_src); ++ } ++ ++ 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); ++ } ++ ++ 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); ++ } ++ ++ pll2_bypass_src = devm_clk_get(&pdev->dev, "pll2_bypass_src"); ++ if (IS_ERR(pll2_bypass_src)) { ++ dev_err(busfreq_dev, "%s: failed to get pll2_bypass_src\n", ++ __func__); ++ return PTR_ERR(pll2_bypass_src); ++ } ++ ++ pll2 = devm_clk_get(&pdev->dev, "pll2"); ++ if (IS_ERR(pll2)) { ++ dev_err(busfreq_dev, "%s: failed to get pll2\n", ++ __func__); ++ return PTR_ERR(pll2); ++ } ++ ++ pll2_bypass = devm_clk_get(&pdev->dev, "pll2_bypass"); ++ if (IS_ERR(pll2_bypass)) { ++ dev_err(busfreq_dev, "%s: failed to get pll2_bypass\n", ++ __func__); ++ return PTR_ERR(pll2_bypass); ++ } ++ } ++ if (cpu_is_imx6sx()) { ++ mmdc_clk = devm_clk_get(&pdev->dev, "mmdc"); ++ if (IS_ERR(mmdc_clk)) { ++ dev_err(busfreq_dev, ++ "%s: failed to get mmdc_clk\n", ++ __func__); ++ return PTR_ERR(mmdc_clk); ++ } ++ m4_clk = devm_clk_get(&pdev->dev, "m4"); ++ if (IS_ERR(m4_clk)) { ++ dev_err(busfreq_dev, ++ "%s: failed to get m4_clk\n", ++ __func__); ++ return PTR_ERR(m4_clk); ++ } ++ } ++ ++ err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr); ++ if (err) { ++ dev_err(busfreq_dev, ++ "Unable to register sysdev entry for BUSFREQ"); ++ return err; ++ } ++ ++ if (of_property_read_u32(pdev->dev.of_node, "fsl,max_ddr_freq", ++ &ddr_normal_rate)) { ++ dev_err(busfreq_dev, "max_ddr_freq entry missing\n"); ++ return -EINVAL; ++ } ++ ++ high_bus_freq_mode = 1; ++ med_bus_freq_mode = 0; ++ low_bus_freq_mode = 0; ++ audio_bus_freq_mode = 0; ++ ultra_low_bus_freq_mode = 0; ++ ++ bus_freq_scaling_is_active = 0; ++ 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); ++ ++ /* ++ * Need to make sure to an entry for the ddr freq change code address in the IRAM page table. ++ * This is only required if the DDR freq code and suspend/idle code are in different OCRAM spaces. ++ */ ++ if ((iram_tlb_phys_addr & 0xFFF00000) != (ddr_freq_change_iram_phys & 0xFFF00000)) { ++ unsigned long i; ++ ++ /* ++ * Make sure the ddr_iram virtual address has a mapping ++ * in the IRAM page table. ++ */ ++ i = ((IMX_IO_P2V(ddr_freq_change_iram_phys) >> 20) << 2) / 4; ++ *((unsigned long *)iram_tlb_base_addr + i) = ++ (ddr_freq_change_iram_phys & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; ++ } ++ ++#if defined(CONFIG_SOC_IMX6SX) || defined(CONFIG_SOC_IMX6SL) ++ if (cpu_is_imx6sl()) { ++ err = init_mmdc_lpddr2_settings(pdev); ++#ifdef CONFIG_SOC_IMX6SX ++ } else if (cpu_is_imx6sx()) { ++ ddr_type = imx_mmdc_get_ddr_type(); ++ /* check whether it is a DDR3 or LPDDR2 board */ ++ if (ddr_type == MMDC_MDMISC_DDR_TYPE_DDR3) ++ err = init_mmdc_ddr3_settings_imx6sx(pdev); ++ else if (ddr_type == MMDC_MDMISC_DDR_TYPE_LPDDR2) ++ err = init_mmdc_lpddr2_settings(pdev); ++ /* if M4 is enabled and rate > 24MHz, add high bus count */ ++ if (imx_src_is_m4_enabled() && ++ (clk_get_rate(m4_clk) > LPAPM_CLK)) ++ high_bus_count++; ++#endif ++ } ++#endif ++#ifdef CONFIG_SOC_IMX6Q ++ else ++ err = init_mmdc_ddr3_settings_imx6q(pdev); ++#endif ++ ++ if (err) { ++ dev_err(busfreq_dev, "Busfreq init of MMDC failed\n"); ++ return err; ++ } ++ return 0; ++} ++ ++static const struct of_device_id imx6_busfreq_ids[] = { ++ { .compatible = "fsl,imx6_busfreq", }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver busfreq_driver = { ++ .driver = { ++ .name = "imx6_busfreq", ++ .owner = THIS_MODULE, ++ .of_match_table = imx6_busfreq_ids, ++ }, ++ .probe = busfreq_probe, ++}; ++ ++/*! ++ * Initialise the busfreq_driver. ++ * ++ * @return The function always returns 0. ++ */ ++ ++static int __init busfreq_init(void) ++{ ++#ifndef CONFIG_MX6_VPU_352M ++ if (platform_driver_register(&busfreq_driver) != 0) ++ return -ENODEV; ++ ++ printk(KERN_INFO "Bus freq driver module loaded\n"); ++#endif ++ return 0; ++} ++ ++static void __exit busfreq_cleanup(void) ++{ ++ sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr); ++ ++ /* Unregister the device structure */ ++ platform_driver_unregister(&busfreq_driver); ++ bus_freq_scaling_initialized = 0; ++} ++ ++module_init(busfreq_init); ++module_exit(busfreq_cleanup); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("BusFreq driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/busfreq_lpddr2.c linux-3.14.72/arch/arm/mach-imx/busfreq_lpddr2.c +--- linux-3.14.72.orig/arch/arm/mach-imx/busfreq_lpddr2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/busfreq_lpddr2.c 2016-06-19 22:11:55.045157162 +0200 +@@ -0,0 +1,116 @@ ++/* ++ * Copyright (C) 2011-2015 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" ++ ++ ++static struct device *busfreq_dev; ++static int curr_ddr_rate; ++static DEFINE_SPINLOCK(freq_lock); ++ ++void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode) = 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); ++#ifdef CONFIG_SOC_IMX6SX ++extern void imx6sx_lpddr2_freq_change(u32 freq, int bus_freq_mode); ++#endif ++extern unsigned long save_ttbr1(void); ++extern void restore_ttbr1(unsigned long ttbr1); ++extern unsigned long ddr_freq_change_iram_base; ++extern unsigned long imx6_lpddr2_freq_change_start asm("imx6_lpddr2_freq_change_start"); ++extern unsigned long imx6_lpddr2_freq_change_end asm("imx6_lpddr2_freq_change_end"); ++ ++/* change the DDR frequency. */ ++int update_lpddr2_freq(int ddr_rate) ++{ ++ unsigned long ttbr1, flags; ++ ++ if (ddr_rate == curr_ddr_rate) ++ return 0; ++ ++ pr_debug("Bus freq set to %d start...\n", ddr_rate); ++ ++ spin_lock_irqsave(&freq_lock, flags); ++ /* ++ * Flush the TLB, to ensure no TLB maintenance occurs ++ * when DDR is in self-refresh. ++ */ ++ ttbr1 = save_ttbr1(); ++ ++ /* Now change DDR frequency. */ ++ mx6_change_lpddr2_freq(ddr_rate, ++ (low_bus_freq_mode | ultra_low_bus_freq_mode)); ++ restore_ttbr1(ttbr1); ++ ++ curr_ddr_rate = ddr_rate; ++ spin_unlock_irqrestore(&freq_lock, flags); ++ ++ pr_debug("Bus freq set to %d done...\n", ddr_rate); ++ ++ return 0; ++} ++ ++int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev) ++{ ++ unsigned long ddr_code_size; ++ busfreq_dev = &busfreq_pdev->dev; ++ ++ ddr_code_size = (&imx6_lpddr2_freq_change_end -&imx6_lpddr2_freq_change_start) *4; ++ ++ if (cpu_is_imx6sl()) ++ mx6_change_lpddr2_freq = (void *)fncpy( ++ (void *)ddr_freq_change_iram_base, ++ &mx6_lpddr2_freq_change, ddr_code_size); ++#ifdef CONFIG_SOC_IMX6SX ++ else if (cpu_is_imx6sx()) ++ mx6_change_lpddr2_freq = (void *)fncpy( ++ (void *)ddr_freq_change_iram_base, ++ &imx6sx_lpddr2_freq_change, ddr_code_size); ++#endif ++ ++ curr_ddr_rate = ddr_normal_rate; ++ ++ return 0; ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-busy.c linux-3.14.72/arch/arm/mach-imx/clk-busy.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-busy.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-busy.c 2016-06-19 22:11:55.045157162 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012-2015 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -187,3 +187,12 @@ + + return clk; + } ++ ++struct clk *imx_clk_busy_gate(const char *name, const char *parent, ++ void __iomem *reg, u8 shift) ++{ ++ return clk_register_gate2(NULL, name, parent, ++ CLK_SET_RATE_PARENT, ++ reg, shift, 0, &imx_ccm_lock, NULL); ++} ++ +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-gate2.c linux-3.14.72/arch/arm/mach-imx/clk-gate2.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-gate2.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-gate2.c 2016-06-19 22:11:55.045157162 +0200 +@@ -1,6 +1,7 @@ + /* + * Copyright (C) 2010-2011 Canonical Ltd + * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd ++ * Copyright (C) 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 +@@ -10,12 +11,14 @@ + */ + + #include ++#include + #include + #include + #include + #include + #include + #include "clk.h" ++#include "common.h" + + /** + * DOC: basic gatable clock which can gate and ungate it's ouput +@@ -27,57 +30,118 @@ + * parent - fixed parent. No clk_set_parent support + */ + +-#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) ++struct clk_gate2 { ++ struct clk_hw hw; ++ void __iomem *reg; ++ u8 bit_idx; ++ u8 flags; ++ spinlock_t *lock; ++ unsigned int *share_count; ++}; + +-static int clk_gate2_enable(struct clk_hw *hw) ++#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw) ++#define CCM_CCGR_FULL_ENABLE 0x3 ++ ++static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable) + { +- struct clk_gate *gate = to_clk_gate(hw); + u32 reg; +- unsigned long flags = 0; +- +- if (gate->lock) +- spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); +- reg |= 3 << gate->bit_idx; ++ if (enable) ++ reg |= CCM_CCGR_FULL_ENABLE << gate->bit_idx; ++ else ++ reg &= ~(CCM_CCGR_FULL_ENABLE << gate->bit_idx); + writel(reg, gate->reg); ++} + +- if (gate->lock) +- spin_unlock_irqrestore(gate->lock, flags); ++static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable) ++{ ++ struct clk_gate2 *gate = to_clk_gate2(hw); + +- return 0; ++#ifdef CONFIG_SOC_IMX6SX ++ if (imx_src_is_m4_enabled()) { ++ if (!amp_power_mutex || !shared_mem) { ++ if (enable) ++ clk_gate2_do_hardware(gate, enable); ++ return; ++ } ++ ++ imx_sema4_mutex_lock(amp_power_mutex); ++ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER || ++ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) { ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ return; ++ } ++ ++ if (!imx_update_shared_mem(hw, enable)) { ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ return; ++ } ++ ++ clk_gate2_do_hardware(gate, enable); ++ ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ } else ++#endif ++ clk_gate2_do_hardware(gate, enable); + } + +-static void clk_gate2_disable(struct clk_hw *hw) ++static int clk_gate2_enable(struct clk_hw *hw) + { +- struct clk_gate *gate = to_clk_gate(hw); +- u32 reg; ++ struct clk_gate2 *gate = to_clk_gate2(hw); + unsigned long flags = 0; + +- if (gate->lock) +- spin_lock_irqsave(gate->lock, flags); ++ spin_lock_irqsave(gate->lock, flags); + +- reg = readl(gate->reg); +- reg &= ~(3 << gate->bit_idx); +- writel(reg, gate->reg); ++ if (gate->share_count && (*gate->share_count)++ > 0) ++ goto out; ++ ++ clk_gate2_do_shared_clks(hw, true); ++out: ++ spin_unlock_irqrestore(gate->lock, flags); + +- if (gate->lock) +- spin_unlock_irqrestore(gate->lock, flags); ++ return 0; + } + +-static int clk_gate2_is_enabled(struct clk_hw *hw) ++static void clk_gate2_disable(struct clk_hw *hw) + { +- u32 reg; +- struct clk_gate *gate = to_clk_gate(hw); ++ struct clk_gate2 *gate = to_clk_gate2(hw); ++ unsigned long flags = 0; + +- reg = readl(gate->reg); ++ spin_lock_irqsave(gate->lock, flags); ++ ++ if (gate->share_count) { ++ if (WARN_ON(*gate->share_count == 0)) ++ goto out; ++ else if (--(*gate->share_count) > 0) ++ goto out; ++ } ++ ++ clk_gate2_do_shared_clks(hw, false); ++out: ++ spin_unlock_irqrestore(gate->lock, flags); ++} + +- if (((reg >> gate->bit_idx) & 1) == 1) ++static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx) ++{ ++ u32 val = readl(reg); ++ ++ if (((val >> bit_idx) & 1) == 1) + return 1; + + return 0; + } + ++static int clk_gate2_is_enabled(struct clk_hw *hw) ++{ ++ struct clk_gate2 *gate = to_clk_gate2(hw); ++ ++ if (gate->share_count) ++ return !!__clk_get_enable_count(hw->clk); ++ else ++ return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx); ++} ++ + static struct clk_ops clk_gate2_ops = { + .enable = clk_gate2_enable, + .disable = clk_gate2_disable, +@@ -87,21 +151,23 @@ + struct clk *clk_register_gate2(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, +- u8 clk_gate2_flags, spinlock_t *lock) ++ u8 clk_gate2_flags, spinlock_t *lock, ++ unsigned int *share_count) + { +- struct clk_gate *gate; ++ struct clk_gate2 *gate; + struct clk *clk; + struct clk_init_data init; + +- gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); ++ gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + +- /* struct clk_gate assignments */ ++ /* struct clk_gate2 assignments */ + gate->reg = reg; + gate->bit_idx = bit_idx; + gate->flags = clk_gate2_flags; + gate->lock = lock; ++ gate->share_count = share_count; + + init.name = name; + init.ops = &clk_gate2_ops; +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-gate-exclusive.c linux-3.14.72/arch/arm/mach-imx/clk-gate-exclusive.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-gate-exclusive.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/clk-gate-exclusive.c 2016-06-19 22:11:55.045157162 +0200 +@@ -0,0 +1,94 @@ ++/* ++ * Copyright 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++/** ++ * struct clk_gate_exclusive - i.MX specific gate clock which is mutually ++ * exclusive with other gate clocks ++ * ++ * @gate: the parent class ++ * @exclusive_mask: mask of gate bits which are mutually exclusive to this ++ * gate clock ++ * ++ * The imx exclusive gate clock is a subclass of basic clk_gate ++ * with an addtional mask to indicate which other gate bits in the same ++ * register is mutually exclusive to this gate clock. ++ */ ++struct clk_gate_exclusive { ++ struct clk_gate gate; ++ u32 exclusive_mask; ++}; ++ ++static int clk_gate_exclusive_enable(struct clk_hw *hw) ++{ ++ struct clk_gate *gate = container_of(hw, struct clk_gate, hw); ++ struct clk_gate_exclusive *exgate = container_of(gate, ++ struct clk_gate_exclusive, gate); ++ u32 val = readl(gate->reg); ++ ++ if (val & exgate->exclusive_mask) ++ return -EBUSY; ++ ++ return clk_gate_ops.enable(hw); ++} ++ ++static void clk_gate_exclusive_disable(struct clk_hw *hw) ++{ ++ clk_gate_ops.disable(hw); ++} ++ ++static int clk_gate_exclusive_is_enabled(struct clk_hw *hw) ++{ ++ return clk_gate_ops.is_enabled(hw); ++} ++ ++static const struct clk_ops clk_gate_exclusive_ops = { ++ .enable = clk_gate_exclusive_enable, ++ .disable = clk_gate_exclusive_disable, ++ .is_enabled = clk_gate_exclusive_is_enabled, ++}; ++ ++struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, ++ void __iomem *reg, u8 shift, u32 exclusive_mask) ++{ ++ struct clk_gate_exclusive *exgate; ++ struct clk_gate *gate; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ if (exclusive_mask == 0) ++ return ERR_PTR(-EINVAL); ++ ++ exgate = kzalloc(sizeof(*exgate), GFP_KERNEL); ++ if (!exgate) ++ return ERR_PTR(-ENOMEM); ++ gate = &exgate->gate; ++ ++ init.name = name; ++ init.ops = &clk_gate_exclusive_ops; ++ init.flags = CLK_SET_RATE_PARENT; ++ init.parent_names = parent ? &parent : NULL; ++ init.num_parents = parent ? 1 : 0; ++ ++ gate->reg = reg; ++ gate->bit_idx = shift; ++ gate->lock = &imx_ccm_lock; ++ gate->hw.init = &init; ++ exgate->exclusive_mask = exclusive_mask; ++ ++ clk = clk_register(NULL, &gate->hw); ++ if (IS_ERR(clk)) ++ kfree(exgate); ++ ++ return clk; ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk.h linux-3.14.72/arch/arm/mach-imx/clk.h +--- linux-3.14.72.orig/arch/arm/mach-imx/clk.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk.h 2016-06-19 22:11:55.045157162 +0200 +@@ -7,6 +7,8 @@ + extern spinlock_t imx_ccm_lock; + + extern void imx_cscmr1_fixup(u32 *val); ++extern struct imx_sema4_mutex *amp_power_mutex; ++extern struct imx_shared_mem *shared_mem; + + struct clk *imx_clk_pllv1(const char *name, const char *parent, + void __iomem *base); +@@ -22,22 +24,80 @@ + IMX_PLLV3_ENET, + }; + ++#define MAX_SHARED_CLK_NUMBER 100 ++#define SHARED_MEM_MAGIC_NUMBER 0x12345678 ++#define MCC_POWER_SHMEM_NUMBER (6) ++ ++struct imx_shared_clk { ++ struct clk *self; ++ struct clk *parent; ++ void *m4_clk; ++ void *m4_clk_parent; ++ u8 ca9_enabled; ++ u8 cm4_enabled; ++}; ++ ++struct imx_shared_mem { ++ u32 ca9_valid; ++ u32 cm4_valid; ++ struct imx_shared_clk imx_clk[MAX_SHARED_CLK_NUMBER]; ++}; ++ + struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, + const char *parent_name, void __iomem *base, u32 div_mask); + + struct clk *clk_register_gate2(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, +- u8 clk_gate_flags, spinlock_t *lock); ++ u8 clk_gate_flags, spinlock_t *lock, ++ unsigned int *share_count); + + struct clk * imx_obtain_fixed_clock( + const char *name, unsigned long rate); + ++struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, ++ void __iomem *reg, u8 shift, u32 exclusive_mask); ++ + static inline struct clk *imx_clk_gate2(const char *name, const char *parent, + void __iomem *reg, u8 shift) + { + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, +- shift, 0, &imx_ccm_lock); ++ shift, 0, &imx_ccm_lock, NULL); ++} ++ ++static inline struct clk *imx_clk_gate2_shared(const char *name, ++ const char *parent, void __iomem *reg, u8 shift, ++ unsigned int *share_count) ++{ ++ return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, ++ shift, 0, &imx_ccm_lock, share_count); ++} ++ ++static inline void imx_clk_prepare_enable(struct clk *clk) ++{ ++ int ret = clk_prepare_enable(clk); ++ ++ if (ret) ++ pr_err("failed to prepare and enable clk %s: %d\n", ++ __clk_get_name(clk), ret); ++} ++ ++static inline void imx_clk_set_parent(struct clk *clk, struct clk *parent) ++{ ++ int ret = clk_set_parent(clk, parent); ++ ++ if (ret) ++ pr_err("failed to set parent of clk %s to %s: %d\n", ++ __clk_get_name(clk), __clk_get_name(parent), ret); ++} ++ ++static inline void imx_clk_set_rate(struct clk *clk, unsigned long rate) ++{ ++ int ret = clk_set_rate(clk, rate); ++ ++ if (ret) ++ pr_err("failed to set rate of clk %s to %ld: %d\n", ++ __clk_get_name(clk), rate, ret); + } + + struct clk *imx_clk_pfd(const char *name, const char *parent_name, +@@ -51,6 +111,9 @@ + u8 width, void __iomem *busy_reg, u8 busy_shift, + const char **parent_names, int num_parents); + ++struct clk *imx_clk_busy_gate(const char *name, const char *parent, ++ void __iomem *reg, u8 shift); ++ + struct clk *imx_clk_fixup_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, + void (*fixup)(u32 *val)); +@@ -86,12 +149,20 @@ + shift, 0, &imx_ccm_lock); + } + ++static inline struct clk *imx_clk_mux_bus(const char *name, void __iomem *reg, ++ u8 shift, u8 width, const char **parents, int num_parents) ++{ ++ return clk_register_mux(NULL, name, parents, num_parents, ++ CLK_SET_RATE_NO_REPARENT, ++ reg, shift, width, 0, &imx_ccm_lock); ++} ++ + static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, int num_parents) + { + return clk_register_mux(NULL, name, parents, num_parents, +- CLK_SET_RATE_NO_REPARENT, reg, shift, +- width, 0, &imx_ccm_lock); ++ CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE, ++ reg, shift, width, 0, &imx_ccm_lock); + } + + static inline struct clk *imx_clk_mux_flags(const char *name, +@@ -99,10 +170,28 @@ + int num_parents, unsigned long flags) + { + return clk_register_mux(NULL, name, parents, num_parents, +- flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0, ++ flags | CLK_SET_PARENT_GATE, reg, shift, width, 0, + &imx_ccm_lock); + } + ++static inline struct clk *imx_clk_mux_flags_bus(const char *name, ++ void __iomem *reg, u8 shift, u8 width, const char **paretns, ++ int num_parents, unsigned long flags) ++{ ++ return clk_register_mux(NULL, name, paretns, num_parents, ++ flags | CLK_SET_RATE_NO_REPARENT, reg, shift, ++ width, 0, &imx_ccm_lock); ++} ++ ++static inline struct clk *imx_clk_mux_glitchless(const char *name, ++ void __iomem *reg, u8 shift, u8 width, const char **parents, ++ int num_parents) ++{ ++ return clk_register_mux(NULL, name, parents, num_parents, ++ 0, reg, shift, ++ width, 0, &imx_ccm_lock); ++} ++ + static inline struct clk *imx_clk_fixed_factor(const char *name, + const char *parent, unsigned int mult, unsigned int div) + { +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-imx25.c linux-3.14.72/arch/arm/mach-imx/clk-imx25.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-imx25.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-imx25.c 2016-06-19 22:11:55.045157162 +0200 +@@ -312,8 +312,6 @@ + int __init mx25_clocks_init_dt(void) + { + struct device_node *np; +- void __iomem *base; +- int irq; + unsigned long osc_rate = 24000000; + + /* retrieve the freqency of fixed clocks from device tree */ +@@ -333,12 +331,7 @@ + + __mx25_clocks_init(osc_rate); + +- np = of_find_compatible_node(NULL, NULL, "fsl,imx25-gpt"); +- base = of_iomap(np, 0); +- WARN_ON(!base); +- irq = irq_of_parse_and_map(np, 0); +- +- mxc_timer_init(base, irq); ++ mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx25-gpt")); + + return 0; + } +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-imx51-imx53.c linux-3.14.72/arch/arm/mach-imx/clk-imx51-imx53.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-imx51-imx53.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-imx51-imx53.c 2016-06-19 22:11:55.045157162 +0200 +@@ -324,9 +324,8 @@ + + static void __init mx50_clocks_init(struct device_node *np) + { +- void __iomem *base; + unsigned long r; +- int i, irq; ++ int i; + + clk[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE); + clk[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE); +@@ -374,11 +373,7 @@ + r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); + clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); + +- np = of_find_compatible_node(NULL, NULL, "fsl,imx50-gpt"); +- base = of_iomap(np, 0); +- WARN_ON(!base); +- irq = irq_of_parse_and_map(np, 0); +- mxc_timer_init(base, irq); ++ mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx50-gpt")); + } + CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init); + +@@ -494,9 +489,8 @@ + + static void __init mx53_clocks_init(struct device_node *np) + { +- int i, irq; ++ int i; + unsigned long r; +- void __iomem *base; + + clk[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE); + clk[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE); +@@ -594,10 +588,6 @@ + r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); + clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); + +- np = of_find_compatible_node(NULL, NULL, "fsl,imx53-gpt"); +- base = of_iomap(np, 0); +- WARN_ON(!base); +- irq = irq_of_parse_and_map(np, 0); +- mxc_timer_init(base, irq); ++ mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx53-gpt")); + } + CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-imx6q.c linux-3.14.72/arch/arm/mach-imx/clk-imx6q.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-imx6q.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-imx6q.c 2016-06-19 22:11:55.045157162 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011-2013 Freescale Semiconductor, Inc. ++ * Copyright 2011-2015 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include "clk.h" + #include "common.h" +@@ -31,7 +32,8 @@ + static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; + static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; + static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; +-static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", }; ++static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", }; ++static const char *axi_sels[] = { "periph", "axi_alt_sel", }; + static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; + static const char *gpu_axi_sels[] = { "axi", "ahb", }; + static const char *gpu2d_core_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", }; +@@ -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", }; +@@ -63,7 +67,7 @@ + "ipu2", "vdo_axi", "osc", "gpu2d_core", + "gpu3d_core", "usdhc2", "ssi1", "ssi2", + "ssi3", "gpu3d_shader", "vpu_axi", "can_root", +- "ldb_di0", "ldb_di1", "esai", "eim_slow", ++ "ldb_di0", "ldb_di1", "esai_extal", "eim_slow", + "uart_serial", "spdif", "asrc", "hsi_tx", + }; + static const char *cko_sels[] = { "cko1", "cko2", }; +@@ -72,49 +76,23 @@ + "pll4_audio", "pll5_video", "pll8_mlb", "enet_ref", + "pcie_ref", "sata_ref", + }; +- +-enum mx6q_clks { +- dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, +- pll3_pfd0_720m, pll3_pfd1_540m, pll3_pfd2_508m, pll3_pfd3_454m, +- pll2_198m, pll3_120m, pll3_80m, pll3_60m, twd, step, pll1_sw, +- periph_pre, periph2_pre, periph_clk2_sel, periph2_clk2_sel, axi_sel, +- esai_sel, asrc_sel, spdif_sel, gpu2d_axi, gpu3d_axi, gpu2d_core_sel, +- gpu3d_core_sel, gpu3d_shader_sel, ipu1_sel, ipu2_sel, ldb_di0_sel, +- ldb_di1_sel, ipu1_di0_pre_sel, ipu1_di1_pre_sel, ipu2_di0_pre_sel, +- ipu2_di1_pre_sel, ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, +- ipu2_di1_sel, hsi_tx_sel, pcie_axi_sel, ssi1_sel, ssi2_sel, ssi3_sel, +- usdhc1_sel, usdhc2_sel, usdhc3_sel, usdhc4_sel, enfc_sel, emi_sel, +- emi_slow_sel, vdo_axi_sel, vpu_axi_sel, cko1_sel, periph, periph2, +- 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, +- 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, +- hdmi_isfr, i2c1, i2c2, i2c3, iim, enfc, ipu1, ipu1_di0, ipu1_di1, ipu2, +- ipu2_di0, ldb_di0, ldb_di1, ipu2_di1, hsi_tx, mlb, mmdc_ch0_axi, +- mmdc_ch1_axi, ocram, openvg_axi, pcie_axi, pwm1, pwm2, pwm3, pwm4, per1_bch, +- gpmi_bch_apb, gpmi_bch, gpmi_io, gpmi_apb, sata, sdma, spba, ssi1, +- ssi2, ssi3, uart_ipg, uart_serial, usboh3, usdhc1, usdhc2, usdhc3, +- usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg, +- pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg, +- ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5, +- sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate, +- usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow, +- spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div, +- lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max +-}; +- +-static struct clk *clk[clk_max]; ++static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", }; ++static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; ++static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; ++static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; ++static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; ++static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", }; ++static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", }; ++static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; ++ ++static struct clk *clk[IMX6QDL_CLK_END]; + static struct clk_onecell_data clk_data; + +-static enum mx6q_clks const clks_init_on[] __initconst = { +- mmdc_ch0_axi, rom, arm, ++static unsigned int const clks_init_on[] __initconst = { ++ IMX6QDL_CLK_MMDC_CH0_AXI, ++ IMX6QDL_CLK_ROM, ++ IMX6QDL_CLK_ARM, ++ IMX6QDL_CLK_OCRAM, + }; + + static struct clk_div_table clk_enet_ref_table[] = { +@@ -140,17 +118,26 @@ + { /* sentinel */ } + }; + ++static unsigned int share_count_esai; ++static unsigned int share_count_asrc; ++static unsigned int share_count_ssi1; ++static unsigned int share_count_ssi2; ++static unsigned int share_count_ssi3; ++static unsigned int share_count_spdif; ++ + static void __init imx6q_clocks_init(struct device_node *ccm_node) + { + struct device_node *np; + void __iomem *base; +- int i, irq; +- int ret; ++ int i; + +- 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); ++ clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); ++ clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); ++ clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0); ++ clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0); ++ /* Clock source from external clock via CLK1/2 PADs */ ++ clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0); ++ clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); + base = of_iomap(np, 0); +@@ -164,43 +151,76 @@ + video_div_table[3].div = 1; + } + +- /* 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[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clk[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clk[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clk[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clk[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clk[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ ++ /* type name parent_name base div_mask */ ++ clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); ++ clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); ++ clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); ++ clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); ++ clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); ++ clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); ++ clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); ++ ++ clk[IMX6QDL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT); ++ clk[IMX6QDL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT); ++ clk[IMX6QDL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT); ++ clk[IMX6QDL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT); ++ clk[IMX6QDL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT); ++ clk[IMX6QDL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT); ++ clk[IMX6QDL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT); ++ ++ /* Do not bypass PLLs initially */ ++ imx_clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]); ++ imx_clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]); ++ imx_clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]); ++ imx_clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]); ++ imx_clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]); ++ imx_clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]); ++ imx_clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]); ++ ++ clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); ++ clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); ++ clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); ++ clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); ++ clk[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); ++ clk[IMX6QDL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); ++ clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13); ++ + /* + * Bit 20 is the reserved and read-only bit, we do this only for: + * - Do nothing for usbphy clk_enable/disable + * - Keep refcount when do usbphy clk_enable/disable, in that case, + * the clk framework may need to enable/disable usbphy's parent + */ +- clk[usbphy1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); +- clk[usbphy2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); ++ clk[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); ++ clk[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); + + /* + * usbphy*_gate needs to be on after system boots up, and software + * never needs to control it anymore. + */ +- clk[usbphy1_gate] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); +- clk[usbphy2_gate] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); ++ clk[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); ++ clk[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); + +- 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); ++ clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5); ++ clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4); + +- 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); ++ clk[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20); ++ clk[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); + +- clk[enet_ref] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, ++ clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, + base + 0xe0, 0, 2, 0, clk_enet_ref_table, + &imx_ccm_lock); + +- 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[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); ++ clk[IMX6QDL_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 +@@ -208,29 +228,38 @@ + * 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); ++ clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12)); ++ clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13)); ++ ++ clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10)); ++ clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11)); ++ ++ /* name parent_name reg idx */ ++ clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); ++ clk[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); ++ clk[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); ++ clk[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); ++ clk[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); ++ clk[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); ++ clk[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); ++ ++ /* name parent_name mult div */ ++ clk[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); ++ clk[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); ++ clk[IMX6QDL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); ++ clk[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); ++ clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); ++ clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20); ++ clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); ++ if (cpu_is_imx6dl()) { ++ clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi", 1, 1); ++ clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi", 1, 1); ++ } + +- /* 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); +- clk[pll2_pfd2_396m] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); +- clk[pll3_pfd0_720m] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); +- clk[pll3_pfd1_540m] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); +- clk[pll3_pfd2_508m] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); +- clk[pll3_pfd3_454m] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); +- +- /* name parent_name mult div */ +- clk[pll2_198m] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); +- clk[pll3_120m] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); +- 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[pll4_post_div] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); +- clk[pll4_audio_div] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock); +- clk[pll5_post_div] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); +- clk[pll5_video_div] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); ++ clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock); ++ clk[IMX6QDL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); + + np = ccm_node; + base = of_iomap(np, 0); +@@ -238,193 +267,212 @@ + + imx6q_pm_set_ccm_base(base); + +- /* name reg shift width parent_names num_parents */ +- clk[step] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); +- clk[pll1_sw] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); +- clk[periph_pre] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); +- clk[periph2_pre] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); +- clk[periph_clk2_sel] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); +- clk[periph2_clk2_sel] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); +- clk[axi_sel] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels)); +- clk[esai_sel] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); +- clk[asrc_sel] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); +- clk[spdif_sel] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); +- clk[gpu2d_axi] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); +- clk[gpu3d_axi] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); +- clk[gpu2d_core_sel] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); +- clk[gpu3d_core_sel] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels)); +- clk[gpu3d_shader_sel] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); +- clk[ipu1_sel] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); +- 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[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); +- clk[ssi2_sel] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); +- clk[ssi3_sel] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); +- clk[usdhc1_sel] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); +- clk[usdhc2_sel] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); +- clk[usdhc3_sel] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); +- clk[usdhc4_sel] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); +- clk[enfc_sel] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels)); +- clk[emi_sel] = imx_clk_fixup_mux("emi_sel", base + 0x1c, 27, 2, emi_sels, ARRAY_SIZE(emi_sels), imx_cscmr1_fixup); +- clk[emi_slow_sel] = imx_clk_fixup_mux("emi_slow_sel", base + 0x1c, 29, 2, emi_slow_sels, ARRAY_SIZE(emi_slow_sels), imx_cscmr1_fixup); +- clk[vdo_axi_sel] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels)); +- clk[vpu_axi_sel] = imx_clk_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels)); +- clk[cko1_sel] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); +- clk[cko2_sel] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); +- clk[cko] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); +- +- /* name reg shift width busy: reg, shift parent_names num_parents */ +- clk[periph] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); +- clk[periph2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); +- +- /* name parent_name reg shift width */ +- clk[periph_clk2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); +- clk[periph2_clk2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); +- clk[ipg] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); +- clk[ipg_per] = imx_clk_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup); +- clk[esai_pred] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3); +- clk[esai_podf] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3); +- clk[asrc_pred] = imx_clk_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3); +- clk[asrc_podf] = imx_clk_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3); +- clk[spdif_pred] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); +- clk[spdif_podf] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); +- clk[can_root] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6); +- clk[ecspi_root] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6); +- clk[gpu2d_core_podf] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); +- clk[gpu3d_core_podf] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3); +- clk[gpu3d_shader] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); +- 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_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[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); +- clk[ipu2_di1_pre] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", base + 0x38, 12, 3); +- clk[hsi_tx_podf] = imx_clk_divider("hsi_tx_podf", "hsi_tx_sel", base + 0x30, 29, 3); +- clk[ssi1_pred] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3); +- clk[ssi1_podf] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6); +- clk[ssi2_pred] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3); +- clk[ssi2_podf] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6); +- clk[ssi3_pred] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3); +- clk[ssi3_podf] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6); +- clk[uart_serial_podf] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6); +- clk[usdhc1_podf] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); +- clk[usdhc2_podf] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); +- clk[usdhc3_podf] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); +- clk[usdhc4_podf] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); +- clk[enfc_pred] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); +- clk[enfc_podf] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); +- clk[emi_podf] = imx_clk_fixup_divider("emi_podf", "emi_sel", base + 0x1c, 20, 3, imx_cscmr1_fixup); +- clk[emi_slow_podf] = imx_clk_fixup_divider("emi_slow_podf", "emi_slow_sel", base + 0x1c, 23, 3, imx_cscmr1_fixup); +- clk[vpu_axi_podf] = imx_clk_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3); +- clk[cko1_podf] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); +- clk[cko2_podf] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); +- +- /* name parent_name reg shift width busy: reg, shift */ +- clk[axi] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); +- clk[mmdc_ch0_axi_podf] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4); +- clk[mmdc_ch1_axi_podf] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); +- clk[arm] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); +- clk[ahb] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); +- +- /* 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[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); +- clk[can2_serial] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20); +- clk[ecspi1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0); +- clk[ecspi2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); +- clk[ecspi3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); +- 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[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); ++ /* name reg shift width parent_names num_parents */ ++ clk[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); ++ clk[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); ++ clk[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux_bus("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); ++ clk[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); ++ clk[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); ++ clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); ++ clk[IMX6QDL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels)); ++ clk[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux_glitchless("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels)); ++ clk[IMX6QDL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ clk[IMX6QDL_CLK_ASRC_SEL] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ clk[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ if (cpu_is_imx6q()) { ++ clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); ++ clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); ++ } ++ clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); ++ clk[IMX6QDL_CLK_GPU3D_CORE_SEL] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels)); ++ clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); ++ clk[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); ++ clk[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); ++ clk[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_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[IMX6QDL_CLK_HSI_TX_SEL] = imx_clk_mux("hsi_tx_sel", base + 0x30, 28, 1, hsi_tx_sels, ARRAY_SIZE(hsi_tx_sels)); ++ clk[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); ++ clk[IMX6QDL_CLK_SSI1_SEL] = imx_clk_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_SSI2_SEL] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_SSI3_SEL] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels)); ++ clk[IMX6QDL_CLK_EMI_SEL] = imx_clk_fixup_mux("emi_sel", base + 0x1c, 27, 2, emi_sels, ARRAY_SIZE(emi_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_EMI_SLOW_SEL] = imx_clk_fixup_mux("emi_slow_sel", base + 0x1c, 29, 2, emi_slow_sels, ARRAY_SIZE(emi_slow_sels), imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels)); ++ clk[IMX6QDL_CLK_VPU_AXI_SEL] = imx_clk_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels)); ++ clk[IMX6QDL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); ++ clk[IMX6QDL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); ++ clk[IMX6QDL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); ++ ++ /* name reg shift width busy: reg, shift parent_names num_parents */ ++ clk[IMX6QDL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); ++ clk[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); ++ ++ /* name parent_name reg shift width */ ++ clk[IMX6QDL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); ++ clk[IMX6QDL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); ++ clk[IMX6QDL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); ++ clk[IMX6QDL_CLK_IPG_PER] = imx_clk_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3); ++ clk[IMX6QDL_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3); ++ clk[IMX6QDL_CLK_ASRC_PRED] = imx_clk_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3); ++ clk[IMX6QDL_CLK_ASRC_PODF] = imx_clk_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3); ++ clk[IMX6QDL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); ++ clk[IMX6QDL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); ++ clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6); ++ clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6); ++ clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); ++ clk[IMX6QDL_CLK_GPU3D_CORE_PODF] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3); ++ clk[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); ++ clk[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3); ++ clk[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3); ++ clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); ++ clk[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); ++ clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); ++ clk[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7); ++ clk[IMX6QDL_CLK_IPU1_DI0_PRE] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3); ++ clk[IMX6QDL_CLK_IPU1_DI1_PRE] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3); ++ clk[IMX6QDL_CLK_IPU2_DI0_PRE] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3); ++ clk[IMX6QDL_CLK_IPU2_DI1_PRE] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", base + 0x38, 12, 3); ++ clk[IMX6QDL_CLK_HSI_TX_PODF] = imx_clk_divider("hsi_tx_podf", "hsi_tx_sel", base + 0x30, 29, 3); ++ clk[IMX6QDL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3); ++ clk[IMX6QDL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6); ++ clk[IMX6QDL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3); ++ clk[IMX6QDL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6); ++ clk[IMX6QDL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3); ++ clk[IMX6QDL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6); ++ clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6); ++ clk[IMX6QDL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); ++ clk[IMX6QDL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); ++ clk[IMX6QDL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); ++ clk[IMX6QDL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); ++ clk[IMX6QDL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); ++ clk[IMX6QDL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); ++ clk[IMX6QDL_CLK_EMI_PODF] = imx_clk_fixup_divider("emi_podf", "emi_sel", base + 0x1c, 20, 3, imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_EMI_SLOW_PODF] = imx_clk_fixup_divider("emi_slow_podf", "emi_slow_sel", base + 0x1c, 23, 3, imx_cscmr1_fixup); ++ clk[IMX6QDL_CLK_VPU_AXI_PODF] = imx_clk_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3); ++ clk[IMX6QDL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); ++ clk[IMX6QDL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); ++ ++ /* name parent_name reg shift width busy: reg, shift */ ++ clk[IMX6QDL_CLK_AXI] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); ++ clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_busy_divider("mmdc_ch0_axi", "periph", base + 0x14, 19, 3, base + 0x48, 4); ++ clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_busy_divider("mmdc_ch1_axi", "periph2", base + 0x14, 3, 3, base + 0x48, 2); ++ clk[IMX6QDL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); ++ clk[IMX6QDL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); ++ ++ /* name parent_name reg shift */ ++ clk[IMX6QDL_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); ++ clk[IMX6QDL_CLK_ASRC] = imx_clk_gate2_shared("asrc", "asrc_podf", base + 0x68, 6, &share_count_asrc); ++ clk[IMX6QDL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); ++ clk[IMX6QDL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); ++ clk[IMX6QDL_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); ++ clk[IMX6QDL_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); ++ clk[IMX6QDL_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); ++ clk[IMX6QDL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); ++ clk[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16); ++ clk[IMX6QDL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); ++ clk[IMX6QDL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20); ++ clk[IMX6QDL_CLK_DCIC1] = imx_clk_gate2("dcic1", "ipu1_podf", base + 0x68, 24); ++ clk[IMX6QDL_CLK_DCIC2] = imx_clk_gate2("dcic2", "ipu2_podf", base + 0x68, 26); ++ clk[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0); ++ clk[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); ++ clk[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); ++ clk[IMX6QDL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); ++ if (cpu_is_imx6dl()) ++ clk[IMX6DL_CLK_I2C4] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8); ++ else ++ clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); ++ clk[IMX6QDL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); ++ clk[IMX6QDL_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai); ++ clk[IMX6QDL_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai); ++ clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai); ++ clk[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); ++ clk[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); + if (cpu_is_imx6dl()) + /* + * The multiplexer and divider of imx6q clock gpu3d_shader get + * redefined/reused as gpu2d_core_sel and gpu2d_core_podf on imx6dl. + */ +- clk[gpu2d_core] = imx_clk_gate2("gpu2d_core", "gpu3d_shader", base + 0x6c, 24); ++ clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu3d_shader", base + 0x6c, 24); + else +- clk[gpu2d_core] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); +- clk[gpu3d_core] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); +- clk[hdmi_iahb] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); +- clk[hdmi_isfr] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4); +- clk[i2c1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); +- clk[i2c2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); +- 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[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[hsi_tx] = imx_clk_gate2("hsi_tx", "hsi_tx_podf", base + 0x74, 16); ++ clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); ++ clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); ++ clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); ++ clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4); ++ clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); ++ clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); ++ clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); ++ clk[IMX6QDL_CLK_IIM] = imx_clk_gate2("iim", "ipg", base + 0x70, 12); ++ clk[IMX6QDL_CLK_ENFC] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14); ++ clk[IMX6QDL_CLK_VDOA] = imx_clk_gate2("vdoa", "vdo_axi", base + 0x70, 26); ++ clk[IMX6QDL_CLK_IPU1] = imx_clk_gate2("ipu1", "ipu1_podf", base + 0x74, 0); ++ clk[IMX6QDL_CLK_IPU1_DI0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", base + 0x74, 2); ++ clk[IMX6QDL_CLK_IPU1_DI1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", base + 0x74, 4); ++ clk[IMX6QDL_CLK_IPU2] = imx_clk_gate2("ipu2", "ipu2_podf", base + 0x74, 6); ++ clk[IMX6QDL_CLK_IPU2_DI0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", base + 0x74, 8); ++ clk[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12); ++ clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_div_sel", base + 0x74, 14); ++ clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10); ++ clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2("hsi_tx", "hsi_tx_podf", base + 0x74, 16); + if (cpu_is_imx6dl()) + /* + * The multiplexer and divider of the imx6q clock gpu2d get + * redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl. + */ +- clk[mlb] = imx_clk_gate2("mlb", "gpu2d_core_podf", base + 0x74, 18); ++ clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "gpu2d_core_podf", base + 0x74, 18); + else +- clk[mlb] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); +- clk[mmdc_ch0_axi] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20); +- clk[mmdc_ch1_axi] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22); +- clk[ocram] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28); +- clk[openvg_axi] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30); +- clk[pcie_axi] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0); +- clk[per1_bch] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); +- clk[pwm1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16); +- clk[pwm2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18); +- clk[pwm3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20); +- clk[pwm4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22); +- clk[gpmi_bch_apb] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); +- clk[gpmi_bch] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); +- clk[gpmi_io] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); +- clk[gpmi_apb] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); +- clk[rom] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); +- clk[sata] = imx_clk_gate2("sata", "ahb", base + 0x7c, 4); +- clk[sdma] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); +- clk[spba] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); +- clk[spdif] = imx_clk_gate2("spdif", "spdif_podf", base + 0x7c, 14); +- clk[ssi1_ipg] = imx_clk_gate2("ssi1_ipg", "ipg", base + 0x7c, 18); +- clk[ssi2_ipg] = imx_clk_gate2("ssi2_ipg", "ipg", base + 0x7c, 20); +- clk[ssi3_ipg] = imx_clk_gate2("ssi3_ipg", "ipg", base + 0x7c, 22); +- clk[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); +- clk[usdhc1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); +- clk[usdhc2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); +- clk[usdhc3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); +- clk[usdhc4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); +- clk[eim_slow] = imx_clk_gate2("eim_slow", "emi_slow_podf", base + 0x80, 10); +- clk[vdo_axi] = imx_clk_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12); +- clk[vpu_axi] = imx_clk_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14); +- clk[cko1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); +- clk[cko2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); ++ clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); ++ clk[IMX6QDL_CLK_OCRAM] = imx_clk_busy_gate("ocram", "ahb", base + 0x74, 28); ++ clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30); ++ clk[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0); ++ clk[IMX6QDL_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); ++ clk[IMX6QDL_CLK_PWM1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16); ++ clk[IMX6QDL_CLK_PWM2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18); ++ clk[IMX6QDL_CLK_PWM3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20); ++ clk[IMX6QDL_CLK_PWM4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22); ++ clk[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); ++ clk[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); ++ clk[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); ++ clk[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); ++ clk[IMX6QDL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); ++ clk[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ahb", base + 0x7c, 4); ++ clk[IMX6QDL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); ++ clk[IMX6QDL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); ++ clk[IMX6QDL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_spdif); ++ clk[IMX6QDL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_spdif); ++ clk[IMX6QDL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1); ++ clk[IMX6QDL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2); ++ clk[IMX6QDL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3); ++ clk[IMX6QDL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1); ++ clk[IMX6QDL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2); ++ clk[IMX6QDL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3); ++ clk[IMX6QDL_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); ++ clk[IMX6QDL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26); ++ clk[IMX6QDL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); ++ clk[IMX6QDL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); ++ clk[IMX6QDL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); ++ clk[IMX6QDL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); ++ clk[IMX6QDL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); ++ clk[IMX6QDL_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "emi_slow_podf", base + 0x80, 10); ++ clk[IMX6QDL_CLK_VDO_AXI] = imx_clk_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12); ++ clk[IMX6QDL_CLK_VPU_AXI] = imx_clk_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14); ++ clk[IMX6QDL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); ++ clk[IMX6QDL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) +@@ -435,19 +483,30 @@ + 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[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); +- +- 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]); ++ clk_register_clkdev(clk[IMX6QDL_CLK_GPT_IPG], "ipg", "imx-gpt.0"); ++ clk_register_clkdev(clk[IMX6QDL_CLK_GPT_IPG_PER], "per", "imx-gpt.0"); ++ clk_register_clkdev(clk[IMX6QDL_CLK_GPT_3M], "gpt_3m", "imx-gpt.0"); ++ clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL); ++ ++ /* ipu clock initialization */ ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_SEL], clk[IMX6QDL_CLK_IPU1_DI0_PRE]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_SEL], clk[IMX6QDL_CLK_IPU1_DI1_PRE]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_SEL], clk[IMX6QDL_CLK_IPU2_DI0_PRE]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_SEL], clk[IMX6QDL_CLK_IPU2_DI1_PRE]); ++ imx_clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_AXI_ALT_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_AXI_SEL], clk[IMX6QDL_CLK_AXI_ALT_SEL]); ++ /* set epdc/pxp axi clock to 200Mhz */ ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU2_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]); ++ imx_clk_set_rate(clk[IMX6QDL_CLK_IPU2], 200000000); ++ if (cpu_is_imx6q()) { ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_MMDC_CH0_AXI]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_IPU2_SEL], clk[IMX6QDL_CLK_MMDC_CH0_AXI]); + } + + /* +@@ -455,40 +514,84 @@ + * We can not get the 100MHz from the pll2_pfd0_352m. + * So choose pll2_pfd2_396m as enfc_sel's parent. + */ +- clk_set_parent(clk[enfc_sel], clk[pll2_pfd2_396m]); +- +- for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) +- clk_prepare_enable(clk[clks_init_on[i]]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]); + +- if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { +- clk_prepare_enable(clk[usbphy1_gate]); +- clk_prepare_enable(clk[usbphy2_gate]); ++ /* gpu clock initilazation */ ++ /* ++ * On mx6dl, 2d core clock sources(sel, podf) is from 3d ++ * shader core clock, but 3d shader clock multiplexer of ++ * mx6dl is different. For instance the equivalent of ++ * pll2_pfd_594M on mx6q is pll2_pfd_528M on mx6dl. ++ * Make a note here. ++ */ ++ imx_clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL], clk[IMX6QDL_CLK_PLL2_PFD1_594M]); ++ if (cpu_is_imx6dl()) { ++ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_SHADER], 528000000); ++ /* for mx6dl, change gpu3d_core parent to 594_PFD*/ ++ imx_clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], clk[IMX6QDL_CLK_PLL2_PFD1_594M]); ++ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_CORE], 528000000); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]); ++ } else if (cpu_is_imx6q()) { ++ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_SHADER], 594000000); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], clk[IMX6QDL_CLK_MMDC_CH0_AXI]); ++ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_CORE], 528000000); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], clk[IMX6QDL_CLK_PLL3_USB_OTG]); ++ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU2D_CORE], 480000000); + } + + /* + * Let's initially set up CLKO with OSC24M, since this configuration + * is widely used by imx6q board designs to clock audio codec. + */ +- ret = clk_set_parent(clk[cko2_sel], clk[osc]); +- if (!ret) +- ret = clk_set_parent(clk[cko], clk[cko2]); +- if (ret) +- pr_warn("failed to set up CLKO: %d\n", ret); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]); + + /* Audio-related clocks configuration */ +- clk_set_parent(clk[spdif_sel], clk[pll3_pfd3_454m]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_SPDIF_SEL], clk[IMX6QDL_CLK_PLL3_PFD3_454M]); + + /* All existing boards with PCIe use LVDS1 */ + if (IS_ENABLED(CONFIG_PCI_IMX6)) +- clk_set_parent(clk[lvds1_sel], clk[sata_ref]); ++ imx_clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF]); ++ ++ /* ++ * Enable clocks only after both parent and rate are all initialized ++ * as needed ++ */ ++ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) ++ imx_clk_prepare_enable(clk[clks_init_on[i]]); ++ ++ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { ++ imx_clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]); ++ imx_clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]); ++ } ++ ++ /*Set enet_ref clock to 125M to supply for RGMII tx_clk */ ++ clk_set_rate(clk[IMX6QDL_CLK_ENET_REF], 125000000); ++ ++ imx_clk_set_parent(clk[IMX6QDL_CLK_VPU_AXI_SEL], clk[IMX6QDL_CLK_PLL2_PFD0_352M]); ++ ++ if (cpu_is_imx6dl()) ++ imx_clk_set_rate(clk[IMX6QDL_CLK_PLL2_PFD0_352M], 306000000); ++ else ++ imx_clk_set_rate(clk[IMX6QDL_CLK_PLL2_PFD0_352M], 327000000); ++ ++#ifdef CONFIG_MX6_VPU_352M ++ /* ++ * If VPU 352M is enabled, then PLL2_PDF2 need to be ++ * set to 352M, cpufreq will be disabled as VDDSOC/PU ++ * need to be at highest voltage, scaling cpu freq is ++ * not saving any power, and busfreq will be also disabled ++ * as the PLL2_PFD2 is not at default freq, in a word, ++ * all modules that sourceing clk from PLL2_PFD2 will ++ * be impacted. ++ */ ++ imx_clk_set_rate(clk[IMX6QDL_CLK_PLL2_PFD0_352M], 352000000); ++ pr_info("VPU 352M is enabled!\n"); ++#endif + + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + +- np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); +- base = of_iomap(np, 0); +- WARN_ON(!base); +- irq = irq_of_parse_and_map(np, 0); +- mxc_timer_init(base, irq); ++ mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt")); + } + CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-imx6sl.c linux-3.14.72/arch/arm/mach-imx/clk-imx6sl.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-imx6sl.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-imx6sl.c 2016-06-19 22:11:55.045157162 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2013 Freescale Semiconductor, Inc. ++ * Copyright 2013-2015 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 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -18,28 +19,64 @@ + #include "clk.h" + #include "common.h" + +-static const char const *step_sels[] = { "osc", "pll2_pfd2", }; +-static const char const *pll1_sw_sels[] = { "pll1_sys", "step", }; +-static const char const *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", }; +-static const char const *ocram_sels[] = { "periph", "ocram_alt_sels", }; +-static const char const *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", }; +-static const char const *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", }; +-static const char const *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; +-static const char const *periph_sels[] = { "pre_periph_sel", "periph_clk2_podf", }; +-static const char const *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", }; +-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", }; +-static const char const *perclk_sels[] = { "ipg", "osc", }; +-static const char const *epdc_pxp_sels[] = { "mmdc", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd1", }; +-static const char const *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", }; +-static const char const *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", }; +-static const char const *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", }; +-static const char const *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", }; +-static const char const *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", }; +-static const char const *ecspi_sels[] = { "pll3_60m", "osc", }; +-static const char const *uart_sels[] = { "pll3_80m", "osc", }; +- ++#define CCSR 0xc ++#define CCDR 0x04 ++#define CCDR_CH0_HS_BYP 17 ++#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2) ++#define BM_CCSR_STEP_CLK_SEL (1 << 8) ++#define CACRR 0x10 ++#define CDHIPR 0x48 ++#define BM_CDHIPR_ARM_PODF_BUSY (1 << 16) ++#define ARM_WAIT_DIV_396M 2 ++#define ARM_WAIT_DIV_792M 4 ++#define ARM_WAIT_DIV_996M 6 ++ ++#define PLL_ARM 0x0 ++#define BM_PLL_ARM_DIV_SELECT (0x7f << 0) ++#define BM_PLL_ARM_POWERDOWN (1 << 12) ++#define BM_PLL_ARM_ENABLE (1 << 13) ++#define BM_PLL_ARM_LOCK (1 << 31) ++#define PLL_ARM_DIV_792M 66 ++ ++static bool uart_from_osc; ++static const char *step_sels[] = { "osc", "pll2_pfd2", }; ++static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; ++static const char *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", }; ++static const char *ocram_sels[] = { "periph", "ocram_alt_sel", }; ++static const char *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", }; ++static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", }; ++static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; ++static const char *periph_sels[] = { "pre_periph_sel", "periph_clk2_podf", }; ++static const char *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", }; ++static const char *csi_core_sels[] = { "osc", "pll2_pfd2", "pll3_120m", "pll3_pfd1", }; ++static const char *lcdif_axi_sels[] = { "pll2_bus", "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", }; ++static const char *usdhc_sels[] = { "pll2_pfd2", "pll2_pfd0", }; ++static const char *ssi_sels[] = { "pll3_pfd2", "pll3_pfd3", "pll4_audio_div", "dummy", }; ++static const char *perclk_sels[] = { "ipg", "osc", }; ++static const char *pxp_axi_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd3", }; ++static const char *epdc_axi_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd2", }; ++static const char *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", }; ++static const char *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", }; ++static const char *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", }; ++static const char *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", }; ++static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", }; ++static const char *ecspi_sels[] = { "pll3_60m", "osc", }; ++static const char *uart_sels[] = { "pll3_80m", "uart_osc_4m", }; ++static const char *lvds_sels[] = { ++ "pll1_sys", "pll2_bus", "pll2_pfd0", "pll2_pfd1", "pll2_pfd2", "dummy", "pll4_audio", "pll5_video", ++ "dummy", "enet_ref", "dummy", "dummy", "pll3_usb_otg", "pll7_usb_host", "pll3_pfd0", "pll3_pfd1", ++ "pll3_pfd2", "pll3_pfd3", "osc", "dummy", "dummy", "dummy", "dummy", "dummy", ++ "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", ++}; ++static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", }; ++static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; ++static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; ++static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; ++static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; ++static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", }; ++static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", }; ++static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; ++ + static struct clk_div_table clk_enet_ref_table[] = { + { .val = 0, .div = 20, }, + { .val = 1, .div = 10, }, +@@ -63,33 +100,160 @@ + { } + }; + ++static unsigned int share_count_ssi1; ++static unsigned int share_count_ssi2; ++static unsigned int share_count_ssi3; ++static unsigned int share_count_spdif; ++ + static struct clk *clks[IMX6SL_CLK_END]; + static struct clk_onecell_data clk_data; ++static void __iomem *ccm_base; ++static void __iomem *anatop_base; ++ ++static const u32 clks_init_on[] __initconst = { ++ IMX6SL_CLK_IPG, IMX6SL_CLK_ARM, IMX6SL_CLK_MMDC_ROOT, ++}; ++ ++extern int low_bus_freq_mode; ++/* ++ * ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken ++ * during WAIT mode entry process could cause cache memory ++ * corruption. ++ * ++ * Software workaround: ++ * To prevent this issue from occurring, software should ensure that the ++ * ARM to IPG clock ratio is less than 12:5 (that is < 2.4x), before ++ * entering WAIT mode. ++ * ++ * This function will set the ARM clk to max value within the 12:5 limit. ++ * As IPG clock is fixed at 66MHz(so ARM freq must not exceed 158.4MHz), ++ * ARM freq are one of below setpoints: 396MHz, 792MHz and 996MHz, since ++ * the clk APIs can NOT be called in idle thread(may cause kernel schedule ++ * as there is sleep function in PLL wait function), so here we just slow ++ * down ARM to below freq according to previous freq: ++ * ++ * run mode wait mode ++ * 396MHz -> 132MHz; ++ * 792MHz -> 158.4MHz; ++ * 996MHz -> 142.3MHz; ++ */ ++static int imx6sl_get_arm_divider_for_wait(void) ++{ ++ if (readl_relaxed(ccm_base + CCSR) & BM_CCSR_PLL1_SW_CLK_SEL) { ++ return ARM_WAIT_DIV_396M; ++ } else { ++ if ((readl_relaxed(anatop_base + PLL_ARM) & ++ BM_PLL_ARM_DIV_SELECT) == PLL_ARM_DIV_792M) ++ return ARM_WAIT_DIV_792M; ++ else ++ return ARM_WAIT_DIV_996M; ++ } ++} ++ ++void imx6sl_set_wait_clk(bool enter) ++{ ++ static unsigned long saved_arm_div; ++ u32 val; ++ int arm_div_for_wait = imx6sl_get_arm_divider_for_wait(); ++ ++ if (enter) { ++ /* ++ * If in this mode, the IPG clock is at 12MHz, we can ++ * only run ARM at a max 28.8MHz, so we need to run ++ * from the 24MHz OSC, as there is no way to get ++ * 28.8MHz, when ARM is sourced from PLl1. ++ */ ++ if (low_bus_freq_mode) { ++ val = readl_relaxed(ccm_base + CCSR); ++ val |= BM_CCSR_PLL1_SW_CLK_SEL; ++ writel_relaxed(val, ccm_base + CCSR); ++ } else { ++ saved_arm_div = readl_relaxed(ccm_base + CACRR); ++ writel_relaxed(arm_div_for_wait, ccm_base + CACRR); ++ } ++ } else { ++ if (low_bus_freq_mode) { ++ val = readl_relaxed(ccm_base + CCSR); ++ val &= ~BM_CCSR_PLL1_SW_CLK_SEL; ++ writel_relaxed(val, ccm_base + CCSR); ++ } else { ++ writel_relaxed(saved_arm_div, ccm_base + CACRR); ++ } ++ } ++ while (__raw_readl(ccm_base + CDHIPR) & BM_CDHIPR_ARM_PODF_BUSY) ++ ; ++} ++ ++static int __init setup_uart_clk(char *uart_rate) ++{ ++ uart_from_osc = true; ++ return 1; ++} ++__setup("uart_at_4M", setup_uart_clk); + + static void __init imx6sl_clocks_init(struct device_node *ccm_node) + { + struct device_node *np; + void __iomem *base; +- int irq; +- int i; ++ int i, reg; + + clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); + clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); + clks[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0); ++ /* Clock source from external clock via CLK1 PAD */ ++ clks[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); + base = of_iomap(np, 0); + WARN_ON(!base); ++ anatop_base = 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_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ ++ /* type name parent_name base div_mask */ ++ clks[IMX6SL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); ++ clks[IMX6SL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); ++ clks[IMX6SL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); ++ clks[IMX6SL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); ++ clks[IMX6SL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); ++ clks[IMX6SL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); ++ clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); ++ ++ clks[IMX6SL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags_bus("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT); ++ ++ /* Do not bypass PLLs initially */ ++ imx_clk_set_parent(clks[IMX6SL_PLL1_BYPASS], clks[IMX6SL_CLK_PLL1]); ++ imx_clk_set_parent(clks[IMX6SL_PLL2_BYPASS], clks[IMX6SL_CLK_PLL2]); ++ imx_clk_set_parent(clks[IMX6SL_PLL3_BYPASS], clks[IMX6SL_CLK_PLL3]); ++ imx_clk_set_parent(clks[IMX6SL_PLL4_BYPASS], clks[IMX6SL_CLK_PLL4]); ++ imx_clk_set_parent(clks[IMX6SL_PLL5_BYPASS], clks[IMX6SL_CLK_PLL5]); ++ imx_clk_set_parent(clks[IMX6SL_PLL6_BYPASS], clks[IMX6SL_CLK_PLL6]); ++ imx_clk_set_parent(clks[IMX6SL_PLL7_BYPASS], clks[IMX6SL_CLK_PLL7]); ++ ++ clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); ++ clks[IMX6SL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); ++ clks[IMX6SL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); ++ clks[IMX6SL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); ++ clks[IMX6SL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); ++ clks[IMX6SL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); ++ clks[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13); ++ ++ clks[IMX6SL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); ++ clks[IMX6SL_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12)); ++ clks[IMX6SL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10)); ++ + /* + * usbphy1 and usbphy2 are implemented as dummy gates using reserve + * bit 20. They are used by phy driver to keep the refcount of +@@ -103,10 +267,10 @@ + clks[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); + + /* dev name parent_name flags reg shift width div: flags, div_table lock */ +- clks[IMX6SL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); +- clks[IMX6SL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock); +- clks[IMX6SL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); +- clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); ++ clks[IMX6SL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clks[IMX6SL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock); ++ clks[IMX6SL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); + clks[IMX6SL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock); + + /* name parent_name reg idx */ +@@ -123,25 +287,27 @@ + 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); + + np = ccm_node; + base = of_iomap(np, 0); + WARN_ON(!base); ++ ccm_base = base; + + /* Reuse imx6q pm code */ + imx6q_pm_set_ccm_base(base); + + /* name reg shift width parent_names num_parents */ + clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); +- clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); ++ clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); + clks[IMX6SL_CLK_OCRAM_ALT_SEL] = imx_clk_mux("ocram_alt_sel", base + 0x14, 7, 1, ocram_alt_sels, ARRAY_SIZE(ocram_alt_sels)); +- clks[IMX6SL_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels)); +- clks[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_mux("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels)); +- clks[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels)); +- clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); +- clks[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); +- clks[IMX6SL_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_lcdif_sels, ARRAY_SIZE(csi_lcdif_sels)); +- clks[IMX6SL_CLK_LCDIF_AXI_SEL] = imx_clk_mux("lcdif_axi_sel", base + 0x3c, 14, 2, csi_lcdif_sels, ARRAY_SIZE(csi_lcdif_sels)); ++ clks[IMX6SL_CLK_OCRAM_SEL] = imx_clk_mux_glitchless("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels)); ++ clks[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_mux_bus("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels)); ++ clks[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_mux_bus("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels)); ++ clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux_bus("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); ++ clks[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); ++ clks[IMX6SL_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_core_sels, ARRAY_SIZE(csi_core_sels)); ++ clks[IMX6SL_CLK_LCDIF_AXI_SEL] = imx_clk_mux("lcdif_axi_sel", base + 0x3c, 14, 2, lcdif_axi_sels, ARRAY_SIZE(lcdif_axi_sels)); + clks[IMX6SL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_USDHC2_SEL] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_USDHC3_SEL] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); +@@ -150,12 +316,12 @@ + clks[IMX6SL_CLK_SSI2_SEL] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_SSI3_SEL] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_PERCLK_SEL] = imx_clk_fixup_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup); +- clks[IMX6SL_CLK_PXP_AXI_SEL] = imx_clk_mux("pxp_axi_sel", base + 0x34, 6, 3, epdc_pxp_sels, ARRAY_SIZE(epdc_pxp_sels)); +- clks[IMX6SL_CLK_EPDC_AXI_SEL] = imx_clk_mux("epdc_axi_sel", base + 0x34, 15, 3, epdc_pxp_sels, ARRAY_SIZE(epdc_pxp_sels)); ++ clks[IMX6SL_CLK_PXP_AXI_SEL] = imx_clk_mux("pxp_axi_sel", base + 0x34, 6, 3, pxp_axi_sels, ARRAY_SIZE(pxp_axi_sels)); ++ clks[IMX6SL_CLK_EPDC_AXI_SEL] = imx_clk_mux("epdc_axi_sel", base + 0x34, 15, 3, epdc_axi_sels, ARRAY_SIZE(epdc_axi_sels)); + clks[IMX6SL_CLK_GPU2D_OVG_SEL] = imx_clk_mux("gpu2d_ovg_sel", base + 0x18, 4, 2, gpu2d_ovg_sels, ARRAY_SIZE(gpu2d_ovg_sels)); + clks[IMX6SL_CLK_GPU2D_SEL] = imx_clk_mux("gpu2d_sel", base + 0x18, 8, 2, gpu2d_sels, ARRAY_SIZE(gpu2d_sels)); +- clks[IMX6SL_CLK_LCDIF_PIX_SEL] = imx_clk_mux("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels)); +- 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_LCDIF_PIX_SEL] = imx_clk_mux_flags("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux_flags("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels), CLK_SET_RATE_PARENT); + clks[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clks[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); +@@ -167,7 +333,7 @@ + clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); + + /* name parent_name reg shift width */ +- clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3); ++ clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0); + 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_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); +@@ -227,17 +393,21 @@ + clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6); + clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8); + clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10); +- clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28); ++ clks[IMX6SL_CLK_OCRAM] = imx_clk_busy_gate("ocram", "ocram_podf", base + 0x74, 28); + clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); + clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); + clks[IMX6SL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); + clks[IMX6SL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); + clks[IMX6SL_CLK_SDMA] = imx_clk_gate2("sdma", "ipg", base + 0x7c, 6); + clks[IMX6SL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); +- clks[IMX6SL_CLK_SPDIF] = imx_clk_gate2("spdif", "spdif0_podf", base + 0x7c, 14); +- clks[IMX6SL_CLK_SSI1] = imx_clk_gate2("ssi1", "ssi1_podf", base + 0x7c, 18); +- clks[IMX6SL_CLK_SSI2] = imx_clk_gate2("ssi2", "ssi2_podf", base + 0x7c, 20); +- clks[IMX6SL_CLK_SSI3] = imx_clk_gate2("ssi3", "ssi3_podf", base + 0x7c, 22); ++ clks[IMX6SL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif0_podf", base + 0x7c, 14, &share_count_spdif); ++ clks[IMX6SL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_spdif); ++ clks[IMX6SL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1); ++ clks[IMX6SL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2); ++ clks[IMX6SL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3); ++ clks[IMX6SL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1); ++ clks[IMX6SL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2); ++ clks[IMX6SL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3); + clks[IMX6SL_CLK_UART] = imx_clk_gate2("uart", "ipg", base + 0x7c, 24); + clks[IMX6SL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_root", base + 0x7c, 26); + clks[IMX6SL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); +@@ -255,24 +425,75 @@ + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + ++ /* Ensure that CH0 handshake is bypassed */ ++ reg = readl_relaxed(base + CCDR); ++ reg |= 1 << CCDR_CH0_HS_BYP; ++ writel_relaxed(reg, base + CCDR); ++ + clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); + clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); + +- if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { +- clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]); +- clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); +- } ++ /* Ensure the AHB clk is at 132MHz. */ ++ imx_clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000); ++ ++ /* set perclk to source from OSC 24MHz */ ++ imx_clk_set_parent(clks[IMX6SL_CLK_PERCLK_SEL], clks[IMX6SL_CLK_OSC]); + + /* Audio-related clocks configuration */ +- clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]); ++ imx_clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]); ++ ++ /* Configure pxp clocks */ ++ imx_clk_set_parent(clks[IMX6SL_CLK_PXP_AXI_SEL], clks[IMX6SL_CLK_PLL2_PFD2]); ++ imx_clk_set_rate(clks[IMX6SL_CLK_PXP_AXI], 200000000); ++ ++ /* Initialize Video PLLs to valid frequency (650MHz). */ ++ imx_clk_set_rate(clks[IMX6SL_CLK_PLL5_VIDEO_DIV], 650000000); ++ /* set PLL5 video as lcdif pix parent clock */ ++ imx_clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL], ++ clks[IMX6SL_CLK_PLL5_VIDEO_DIV]); ++ ++ /* Set the UART parent if needed */ ++ if (uart_from_osc) ++ imx_clk_set_parent(clks[IMX6SL_CLK_UART_SEL], clks[IMX6SL_CLK_UART_OSC_4M]); ++ /* ++ * Enable clocks only after both parent and rate are all initialized ++ * as needed ++ */ ++ ++ /* ++ * Make sure those always on clocks are enabled to maintain the correct ++ * usecount and enabling/disabling of parent PLLs. ++ */ ++ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) ++ imx_clk_prepare_enable(clks[clks_init_on[i]]); ++ ++ /* ++ * Make sure the OCRAM clk is enabled to maintain the correct usecount ++ * and enabling/disabling of parent PLLs. ++ */ ++ imx_clk_prepare_enable(clks[IMX6SL_CLK_OCRAM]); ++ ++ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { ++ imx_clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]); ++ imx_clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); ++ } + + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt"); +- base = of_iomap(np, 0); +- WARN_ON(!base); +- irq = irq_of_parse_and_map(np, 0); +- mxc_timer_init(base, irq); ++ mxc_timer_init_dt(np); ++ ++ /* Configure EPDC clocks */ ++ clk_set_parent(clks[IMX6SL_CLK_EPDC_PIX_SEL], ++ clks[IMX6SL_CLK_PLL5_VIDEO_DIV]); ++ clk_set_parent(clks[IMX6SL_CLK_EPDC_AXI_SEL], ++ clks[IMX6SL_CLK_PLL2_PFD2]); ++ clk_set_rate(clks[IMX6SL_CLK_EPDC_AXI], 200000000); ++ ++ /* Configure LCDIF clocks */ ++ clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL], ++ clks[IMX6SL_CLK_PLL2_PFD2]); ++ clk_set_rate(clks[IMX6SL_CLK_LCDIF_AXI], 200000000); + } + CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-imx6sx.c linux-3.14.72/arch/arm/mach-imx/clk-imx6sx.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-imx6sx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/clk-imx6sx.c 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,739 @@ ++/* ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk.h" ++#include "common.h" ++ ++#define CCM_CCGR_OFFSET(index) (index * 2) ++#define CCDR 0x4 ++#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16) ++ ++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", }; ++static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", }; ++static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", }; ++static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", }; ++static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; ++static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; ++static const char *ocram_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", }; ++static const char *ocram_sels[] = { "periph", "ocram_alt_sel", }; ++static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", }; ++static const char *gpu_axi_sels[] = { "pll2_pfd2_396m", "pll3_pfd0_720m", "pll3_pfd1_540m", "pll2_bus", }; ++static const char *gpu_core_sels[] = { "pll3_pfd1_540m", "pll3_pfd0_720m", "pll2_bus", "pll2_pfd2_396m", }; ++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 *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", }; ++static const char *ldb_di1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; ++static const char *pcie_axi_sels[] = { "axi", "ahb", }; ++static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll5_video_div", "pll4_audio_div", }; ++static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; ++static const char *perclk_sels[] = { "ipg", "osc", }; ++static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; ++static const char *vid_sels[] = { "pll3_pfd1_540m", "pll3_usb_otg", "pll3_pfd3_454m", "pll4_audio_div", "pll5_video_div", }; ++static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", "dummy", }; ++static const char *uart_sels[] = { "pll3_80m", "osc", }; ++static const char *qspi2_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; ++static const char *enet_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; ++static const char *enet_sels[] = { "enet_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; ++static const char *m4_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "osc", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd3_454m", }; ++static const char *m4_sels[] = { "m4_pre_sel", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; ++static const char *eim_slow_sels[] = { "ocram", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", }; ++static const char *ecspi_sels[] = { "pll3_60m", "osc", }; ++static const char *lcdif1_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", }; ++static const char *lcdif1_sels[] = { "lcdif1_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; ++static const char *lcdif2_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd3_594m", "pll3_pfd1_540m", }; ++static const char *lcdif2_sels[] = { "lcdif2_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; ++static const char *display_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll3_usb_otg", "pll3_pfd1_540m", }; ++static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; ++static const char *cko1_sels[] = { ++ "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", ++ "dummy", "ocram", "dummy", "pxp_axi", "epdc_axi", "lcdif_pix", ++ "epdc_pix", "ahb", "ipg", "perclk", "ckil", "pll4_audio_div", ++}; ++static const char *cko2_sels[] = { ++ "dummy", "mmdc_p0_fast", "usdhc4", "usdhc1", "dummy", "wrck", ++ "ecspi_root", "dummy", "usdhc3", "pcie", "arm", "csi_core", ++ "lcdif_axi", "dummy", "osc", "dummy", "gpu2d_ovg_core", ++ "usdhc2", "ssi1", "ssi2", "ssi3", "gpu2d_core", "dummy", ++ "dummy", "dummy", "dummy", "esai_extal", "eim_slow", "uart_serial", ++ "spdif", "asrc", "dummy", ++}; ++static const char *cko_sels[] = { "cko1", "cko2", }; ++static const char *lvds_sels[] = { ++ "arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div", ++ "dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2", ++}; ++static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", }; ++static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; ++static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; ++static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; ++static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; ++static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", }; ++static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", }; ++static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; ++ ++static struct clk *clks[IMX6SX_CLK_CLK_END]; ++static struct clk_onecell_data clk_data; ++struct imx_sema4_mutex *amp_power_mutex; ++ ++static int clks_shared[MAX_SHARED_CLK_NUMBER]; ++ ++struct imx_shared_mem *shared_mem; ++static unsigned int shared_mem_paddr, shared_mem_size; ++ ++static int const clks_init_on[] __initconst = { ++ IMX6SX_CLK_AIPS_TZ1, IMX6SX_CLK_AIPS_TZ2, IMX6SX_CLK_AIPS_TZ3, ++ IMX6SX_CLK_IPMUX1, IMX6SX_CLK_IPMUX2, IMX6SX_CLK_IPMUX3, ++ IMX6SX_CLK_WAKEUP, IMX6SX_CLK_MMDC_P0_FAST, IMX6SX_CLK_MMDC_P0_IPG, ++ IMX6SX_CLK_ROM, IMX6SX_CLK_ARM, IMX6SX_CLK_IPG, IMX6SX_CLK_OCRAM, ++ IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, ++}; ++ ++static struct clk_div_table clk_enet_ref_table[] = { ++ { .val = 0, .div = 20, }, ++ { .val = 1, .div = 10, }, ++ { .val = 2, .div = 5, }, ++ { .val = 3, .div = 4, }, ++ { } ++}; ++ ++static struct clk_div_table post_div_table[] = { ++ { .val = 2, .div = 1, }, ++ { .val = 1, .div = 2, }, ++ { .val = 0, .div = 4, }, ++ { } ++}; ++ ++static struct clk_div_table video_div_table[] = { ++ { .val = 0, .div = 1, }, ++ { .val = 1, .div = 2, }, ++ { .val = 2, .div = 1, }, ++ { .val = 3, .div = 4, }, ++ { } ++}; ++ ++static u32 share_count_asrc; ++static u32 share_count_audio; ++static u32 share_count_esai; ++static u32 share_count_ssi1; ++static u32 share_count_ssi2; ++static u32 share_count_ssi3; ++static u32 share_count_sai1; ++static u32 share_count_sai2; ++static bool uart_from_osc; ++ ++/* ++ * As IMX6SX_CLK_M4_PRE_SEL is NOT a glitchless MUX, so when ++ * M4 is trying to change its clk parent, need to ask A9 to ++ * help do it, and M4 must be hold in wfi. To avoid glitch ++ * occur, need to gate M4 clk first before switching its parent. ++ */ ++void imx6sx_set_m4_highfreq(bool high_freq) ++{ ++ static struct clk *m4_high_freq_sel; ++ ++ imx_gpc_hold_m4_in_sleep(); ++ ++ clk_disable_unprepare(clks[IMX6SX_CLK_M4]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_M4_SEL], ++ clks[IMX6SX_CLK_LDB_DI0]); ++ ++ if (high_freq) { ++ imx_clk_set_parent(clks[IMX6SX_CLK_M4_PRE_SEL], ++ m4_high_freq_sel); ++ } else { ++ m4_high_freq_sel = clk_get_parent(clks[IMX6SX_CLK_M4_PRE_SEL]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_M4_PRE_SEL], ++ clks[IMX6SX_CLK_OSC]); ++ } ++ ++ imx_clk_set_parent(clks[IMX6SX_CLK_M4_SEL], ++ clks[IMX6SX_CLK_M4_PRE_SEL]); ++ clk_prepare_enable(clks[IMX6SX_CLK_M4]); ++ ++ imx_gpc_release_m4_in_sleep(); ++} ++ ++static int __init setup_uart_clk(char *uart_rate) ++{ ++ uart_from_osc = true; ++ return 1; ++} ++__setup("uart_from_osc", setup_uart_clk); ++ ++static void __init imx6sx_clocks_init(struct device_node *ccm_node) ++{ ++ struct device_node *np; ++ void __iomem *base; ++ int i; ++ ++ clks[IMX6SX_CLK_DUMMY] = imx_clk_fixed("dummy", 0); ++ ++ clks[IMX6SX_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil"); ++ clks[IMX6SX_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc"); ++ ++ /* ipp_di clock is external input */ ++ clks[IMX6SX_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0"); ++ clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1"); ++ ++ /* Clock source from external clock via CLK1 PAD */ ++ clks[IMX6SX_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0); ++ clks[IMX6SX_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0); ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop"); ++ base = of_iomap(np, 0); ++ WARN_ON(!base); ++ ++ clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); ++ ++ /* type name parent_name base div_mask */ ++ clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); ++ clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); ++ clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); ++ clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); ++ clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); ++ clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); ++ clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); ++ ++ clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT); ++ ++ /* Do not bypass PLLs initially */ ++ imx_clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]); ++ imx_clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]); ++ imx_clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]); ++ imx_clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]); ++ imx_clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]); ++ imx_clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]); ++ imx_clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]); ++ ++ clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); ++ clks[IMX6SX_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); ++ clks[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); ++ clks[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); ++ clks[IMX6SX_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); ++ clks[IMX6SX_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); ++ clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13); ++ ++ /* ++ * Bit 20 is the reserved and read-only bit, we do this only for: ++ * - Do nothing for usbphy clk_enable/disable ++ * - Keep refcount when do usbphy clk_enable/disable, in that case, ++ * the clk framework may need to enable/disable usbphy's parent ++ */ ++ clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); ++ clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); ++ ++ /* ++ * usbphy*_gate needs to be on after system boots up, and software ++ * never needs to control it anymore. ++ */ ++ clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); ++ clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); ++ ++ /* FIXME 100Mhz is used for pcie ref for all imx6 pcie, excepted imx6q */ ++ clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5); ++ clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); ++ ++ clks[IMX6SX_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12)); ++ clks[IMX6SX_CLK_LVDS2_OUT] = imx_clk_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13)); ++ clks[IMX6SX_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10)); ++ clks[IMX6SX_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11)); ++ ++ clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, ++ base + 0xe0, 0, 2, 0, clk_enet_ref_table, ++ &imx_ccm_lock); ++ clks[IMX6SX_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0, ++ base + 0xe0, 2, 2, 0, clk_enet_ref_table, ++ &imx_ccm_lock); ++ clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20); ++ ++ clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20); ++ clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21); ++ ++ /* name parent_name reg idx */ ++ clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); ++ clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); ++ clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); ++ clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3); ++ clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); ++ clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); ++ clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); ++ clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); ++ ++ /* name parent_name mult div */ ++ clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); ++ clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); ++ clks[IMX6SX_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); ++ clks[IMX6SX_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); ++ clks[IMX6SX_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); ++ clks[IMX6SX_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); ++ ++ clks[IMX6SX_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock); ++ clks[IMX6SX_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); ++ ++ /* name reg shift width parent_names num_parents */ ++ clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); ++ clks[IMX6SX_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); ++ ++ np = ccm_node; ++ base = of_iomap(np, 0); ++ WARN_ON(!base); ++ ++ imx6q_pm_set_ccm_base(base); ++ ++ /* name reg shift width parent_names num_parents */ ++ clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); ++ clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); ++ clks[IMX6SX_CLK_OCRAM_ALT_SEL] = imx_clk_mux("ocram_alt_sel", base + 0x14, 7, 1, ocram_alt_sels, ARRAY_SIZE(ocram_alt_sels)); ++ clks[IMX6SX_CLK_OCRAM_SEL] = imx_clk_mux_glitchless("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels)); ++ clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux_bus("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); ++ clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux_bus("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)); ++ clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); ++ clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux_bus("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); ++ clks[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); ++ clks[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); ++ clks[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels)); ++ clks[IMX6SX_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels)); ++ clks[IMX6SX_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); ++ clks[IMX6SX_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); ++ clks[IMX6SX_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); ++ clks[IMX6SX_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); ++ clks[IMX6SX_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); ++ clks[IMX6SX_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); ++ clks[IMX6SX_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); ++ clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels)); ++ clks[IMX6SX_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); ++ clks[IMX6SX_CLK_VID_SEL] = imx_clk_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels)); ++ clks[IMX6SX_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ clks[IMX6SX_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels)); ++ clks[IMX6SX_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); ++ clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels)); ++ clks[IMX6SX_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ clks[IMX6SX_CLK_AUDIO_SEL] = imx_clk_mux("audio_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ clks[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels)); ++ clks[IMX6SX_CLK_ENET_SEL] = imx_clk_mux("enet_sel", base + 0x34, 9, 3, enet_sels, ARRAY_SIZE(enet_sels)); ++ clks[IMX6SX_CLK_M4_PRE_SEL] = imx_clk_mux("m4_pre_sel", base + 0x34, 6, 3, m4_pre_sels, ARRAY_SIZE(m4_pre_sels)); ++ clks[IMX6SX_CLK_M4_SEL] = imx_clk_mux("m4_sel", base + 0x34, 0, 3, m4_sels, ARRAY_SIZE(m4_sels)); ++ clks[IMX6SX_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); ++ clks[IMX6SX_CLK_LCDIF2_PRE_SEL] = imx_clk_mux("lcdif2_pre_sel", base + 0x38, 6, 3, lcdif2_pre_sels, ARRAY_SIZE(lcdif2_pre_sels)); ++ clks[IMX6SX_CLK_LCDIF2_SEL] = imx_clk_mux("lcdif2_sel", base + 0x38, 0, 3, lcdif2_sels, ARRAY_SIZE(lcdif2_sels)); ++ clks[IMX6SX_CLK_DISPLAY_SEL] = imx_clk_mux("display_sel", base + 0x3c, 14, 2, display_sels, ARRAY_SIZE(display_sels)); ++ clks[IMX6SX_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels)); ++ clks[IMX6SX_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); ++ clks[IMX6SX_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); ++ clks[IMX6SX_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); ++ ++ clks[IMX6SX_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); ++ clks[IMX6SX_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); ++ clks[IMX6SX_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_CLK_LCDIF1_PRE_SEL] = imx_clk_mux_flags("lcdif1_pre_sel", base + 0x38, 15, 3, lcdif1_pre_sels, ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SX_CLK_LCDIF1_SEL] = imx_clk_mux_flags("lcdif1_sel", base + 0x38, 9, 3, lcdif1_sels, ARRAY_SIZE(lcdif1_sels), CLK_SET_RATE_PARENT); ++ ++ /* name parent_name reg shift width */ ++ clks[IMX6SX_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); ++ clks[IMX6SX_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); ++ clks[IMX6SX_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); ++ clks[IMX6SX_CLK_GPU_CORE_PODF] = imx_clk_divider("gpu_core_podf", "gpu_core_sel", base + 0x18, 29, 3); ++ clks[IMX6SX_CLK_GPU_AXI_PODF] = imx_clk_divider("gpu_axi_podf", "gpu_axi_sel", base + 0x18, 26, 3); ++ clks[IMX6SX_CLK_LCDIF1_PODF] = imx_clk_divider("lcdif1_podf", "lcdif1_pred", base + 0x18, 23, 3); ++ clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3); ++ clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); ++ clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3); ++ clks[IMX6SX_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); ++ clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2); ++ clks[IMX6SX_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6); ++ clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); ++ clks[IMX6SX_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); ++ clks[IMX6SX_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); ++ clks[IMX6SX_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); ++ clks[IMX6SX_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6); ++ clks[IMX6SX_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3); ++ clks[IMX6SX_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3); ++ clks[IMX6SX_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3); ++ clks[IMX6SX_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6); ++ clks[IMX6SX_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3); ++ clks[IMX6SX_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6); ++ clks[IMX6SX_CLK_QSPI2_PRED] = imx_clk_divider("qspi2_pred", "qspi2_sel", base + 0x2c, 18, 3); ++ clks[IMX6SX_CLK_QSPI2_PODF] = imx_clk_divider("qspi2_podf", "qspi2_pred", base + 0x2c, 21, 6); ++ clks[IMX6SX_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3); ++ clks[IMX6SX_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6); ++ clks[IMX6SX_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); ++ clks[IMX6SX_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); ++ clks[IMX6SX_CLK_AUDIO_PRED] = imx_clk_divider("audio_pred", "audio_sel", base + 0x30, 12, 3); ++ clks[IMX6SX_CLK_AUDIO_PODF] = imx_clk_divider("audio_podf", "audio_pred", base + 0x30, 9, 3); ++ clks[IMX6SX_CLK_ENET_PODF] = imx_clk_divider("enet_podf", "enet_pre_sel", base + 0x34, 12, 3); ++ clks[IMX6SX_CLK_M4_PODF] = imx_clk_divider("m4_podf", "m4_sel", base + 0x34, 3, 3); ++ clks[IMX6SX_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); ++ clks[IMX6SX_CLK_LCDIF1_PRED] = imx_clk_divider("lcdif1_pred", "lcdif1_pre_sel", base + 0x38, 12, 3); ++ clks[IMX6SX_CLK_LCDIF2_PRED] = imx_clk_divider("lcdif2_pred", "lcdif2_pre_sel", base + 0x38, 3, 3); ++ clks[IMX6SX_CLK_DISPLAY_PODF] = imx_clk_divider("display_podf", "display_sel", base + 0x3c, 16, 3); ++ clks[IMX6SX_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); ++ clks[IMX6SX_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); ++ clks[IMX6SX_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); ++ ++ clks[IMX6SX_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); ++ clks[IMX6SX_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); ++ clks[IMX6SX_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); ++ clks[IMX6SX_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7); ++ ++ /* name reg shift width busy: reg, shift parent_names num_parents */ ++ clks[IMX6SX_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); ++ clks[IMX6SX_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); ++ /* name parent_name reg shift width busy: reg, shift */ ++ clks[IMX6SX_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0); ++ clks[IMX6SX_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); ++ clks[IMX6SX_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); ++ clks[IMX6SX_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); ++ ++ /* name parent_name reg shift */ ++ /* CCGR0 */ ++ clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); ++ clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); ++ clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); ++ clks[IMX6SX_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); ++ clks[IMX6SX_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); ++ clks[IMX6SX_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); ++ clks[IMX6SX_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); ++ clks[IMX6SX_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); ++ clks[IMX6SX_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); ++ clks[IMX6SX_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16); ++ clks[IMX6SX_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); ++ clks[IMX6SX_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20); ++ clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24); ++ clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26); ++ clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); ++ ++ /* CCGR1 */ ++ clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); ++ clks[IMX6SX_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2); ++ clks[IMX6SX_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4); ++ clks[IMX6SX_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6); ++ clks[IMX6SX_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_podf", base + 0x6c, 8); ++ clks[IMX6SX_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); ++ clks[IMX6SX_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); ++ clks[IMX6SX_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai); ++ clks[IMX6SX_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai); ++ clks[IMX6SX_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai); ++ clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2("wakeup", "ipg", base + 0x6c, 18); ++ clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20); ++ clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22); ++ clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26); ++ clks[IMX6SX_CLK_CANFD] = imx_clk_gate2("canfd", "can_podf", base + 0x6c, 30); ++ ++ /* CCGR2 */ ++ clks[IMX6SX_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2); ++ clks[IMX6SX_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); ++ clks[IMX6SX_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); ++ clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); ++ clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); ++ clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14); ++ clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2("ipmux1", "ahb", base + 0x70, 16); ++ clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2("ipmux2", "ahb", base + 0x70, 18); ++ clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2("ipmux3", "ahb", base + 0x70, 20); ++ clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2("tzasc1", "mmdc_podf", base + 0x70, 22); ++ clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28); ++ clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30); ++ ++ /* CCGR3 */ ++ clks[IMX6SX_CLK_M4] = imx_clk_gate2("m4", "m4_podf", base + 0x74, 2); ++ clks[IMX6SX_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); ++ clks[IMX6SX_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "enet_sel", base + 0x74, 4); ++ clks[IMX6SX_CLK_DISPLAY_AXI] = imx_clk_gate2("display_axi", "display_podf", base + 0x74, 6); ++ clks[IMX6SX_CLK_LCDIF2_PIX] = imx_clk_gate2("lcdif2_pix", "lcdif2_sel", base + 0x74, 8); ++ clks[IMX6SX_CLK_LCDIF1_PIX] = imx_clk_gate2("lcdif1_pix", "lcdif1_sel", base + 0x74, 10); ++ clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12); ++ clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); ++ clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18); ++ clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_busy_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); ++ clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); ++ clks[IMX6SX_CLK_OCRAM] = imx_clk_busy_gate("ocram", "ocram_podf", base + 0x74, 28); ++ ++ /* CCGR4 */ ++ clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0); ++ clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10); ++ clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); ++ clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2("per2_main", "ahb", base + 0x78, 14); ++ clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); ++ clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); ++ clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); ++ clks[IMX6SX_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); ++ clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); ++ clks[IMX6SX_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); ++ clks[IMX6SX_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "qspi2_podf", base + 0x78, 28); ++ clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); ++ ++ /* CCGR5 */ ++ clks[IMX6SX_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); ++ clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); ++ clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); ++ clks[IMX6SX_CLK_AUDIO] = imx_clk_gate2_shared("audio", "audio_podf", base + 0x7c, 14, &share_count_audio); ++ clks[IMX6SX_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio); ++ clks[IMX6SX_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio); ++ clks[IMX6SX_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1); ++ clks[IMX6SX_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2); ++ clks[IMX6SX_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3); ++ clks[IMX6SX_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1); ++ clks[IMX6SX_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2); ++ clks[IMX6SX_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3); ++ clks[IMX6SX_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); ++ clks[IMX6SX_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_podf", base + 0x7c, 26); ++ clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1); ++ clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2); ++ clks[IMX6SX_CLK_SAI1] = imx_clk_gate2_shared("sai1", "ssi1_podf", base + 0x7c, 28, &share_count_sai1); ++ clks[IMX6SX_CLK_SAI2] = imx_clk_gate2_shared("sai2", "ssi2_podf", base + 0x7c, 30, &share_count_sai2); ++ ++ /* CCGR6 */ ++ clks[IMX6SX_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); ++ clks[IMX6SX_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); ++ clks[IMX6SX_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); ++ clks[IMX6SX_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); ++ clks[IMX6SX_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); ++ clks[IMX6SX_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10); ++ clks[IMX6SX_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16); ++ clks[IMX6SX_CLK_VADC] = imx_clk_gate2("vadc", "vid_podf", base + 0x80, 20); ++ clks[IMX6SX_CLK_GIS] = imx_clk_gate2("gis", "display_podf", base + 0x80, 22); ++ clks[IMX6SX_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24); ++ clks[IMX6SX_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26); ++ clks[IMX6SX_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28); ++ clks[IMX6SX_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30); ++ ++ clks[IMX6SX_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); ++ clks[IMX6SX_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); ++ ++ /* get those shared clk nodes if M4 is active */ ++ if (imx_src_is_m4_enabled()) { ++ u32 num; ++ of_property_read_u32(np, "fsl,shared-clks-number", &num); ++ if (num > MAX_SHARED_CLK_NUMBER) ++ pr_err("clk: shared clk nodes exceed the max number!\n"); ++ of_property_read_u32_array(np, "fsl,shared-clks-index", ++ clks_shared, num); ++ if (of_property_read_u32(np, "fsl,shared-mem-addr", ++ &shared_mem_paddr)) ++ pr_err("clk: fsl,shared-mem-addr NOT found!\n"); ++ if (of_property_read_u32(np, "fsl,shared-mem-size", ++ &shared_mem_size)) ++ pr_err("clk: fsl,shared-mem-size NOT found!\n"); ++ } ++ ++ /* mask handshake of mmdc */ ++ writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR); ++ ++ for (i = 0; i < ARRAY_SIZE(clks); i++) ++ if (IS_ERR(clks[i])) ++ pr_err("i.MX6sx clk %d: register failed with %ld\n", i, PTR_ERR(clks[i])); ++ ++ /* ++ * QSPI2/GPMI_IO share the same clock source but with the ++ * different gate, need explicitely gate the QSPI2 & GPMI_IO ++ * during the clock init phase according to the SOC design. ++ */ ++ if (!imx_src_is_m4_enabled()) { ++ writel_relaxed(readl_relaxed(base + 0x78) & ~(3 << CCM_CCGR_OFFSET(5)), base + 0x78); ++ writel_relaxed(readl_relaxed(base + 0x78) & ~(3 << CCM_CCGR_OFFSET(14)), base + 0x78); ++ } ++ clk_data.clks = clks; ++ clk_data.clk_num = ARRAY_SIZE(clks); ++ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); ++ ++ /* ++ * As some of the modules need to access ocotp in MSL, ++ * need to make sure ocotp clk(CCM_CCGR2_CG6) is enabled ++ * during MSL, as on i.MX6SX, accessing OCOTP registers ++ * needs its clk on, it will be disabled by clk late ++ * init and managed by ocotp driver. ++ */ ++ writel_relaxed(readl_relaxed(base + 0x70) | 1 << 12, base + 0x70); ++ ++ clk_register_clkdev(clks[IMX6SX_CLK_GPT_BUS], "ipg", "imx-gpt.0"); ++ clk_register_clkdev(clks[IMX6SX_CLK_GPT_SERIAL], "per", "imx-gpt.0"); ++ clk_register_clkdev(clks[IMX6SX_CLK_GPT_3M], "gpt_3m", "imx-gpt.0"); ++ ++ /* maintain M4 usecount */ ++ if (imx_src_is_m4_enabled()) ++ imx_clk_prepare_enable(clks[IMX6SX_CLK_M4]); ++ ++ /* set perclk to from OSC */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_PERCLK_SEL], clks[IMX6SX_CLK_OSC]); ++ ++ /* Set the default 132MHz for EIM module */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]); ++ imx_clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000); ++ ++ /* set parent clock for LCDIF1 pixel clock */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]); ++ ++ /* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_LVDS1_SEL], clks[IMX6SX_CLK_PCIE_REF_125M]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_PCIE_AXI_SEL], clks[IMX6SX_CLK_AXI]); ++ ++ /* ++ * Init enet system AHB clock, set to 200Mhz ++ * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB ++ */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]); ++ imx_clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000); ++ imx_clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000); ++ imx_clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000); ++ ++ /* Audio clocks */ ++ imx_clk_set_rate(clks[IMX6SX_CLK_PLL4_AUDIO_DIV], 393216000); ++ ++ imx_clk_set_parent(clks[IMX6SX_CLK_SPDIF_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]); ++ imx_clk_set_rate(clks[IMX6SX_CLK_SPDIF_PODF], 98304000); ++ ++ imx_clk_set_parent(clks[IMX6SX_CLK_AUDIO_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]); ++ imx_clk_set_rate(clks[IMX6SX_CLK_AUDIO_PODF], 24000000); ++ ++ imx_clk_set_parent(clks[IMX6SX_CLK_SSI1_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_SSI2_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_SSI3_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]); ++ imx_clk_set_rate(clks[IMX6SX_CLK_SSI1_PODF], 24576000); ++ imx_clk_set_rate(clks[IMX6SX_CLK_SSI2_PODF], 24576000); ++ imx_clk_set_rate(clks[IMX6SX_CLK_SSI3_PODF], 24576000); ++ ++ imx_clk_set_parent(clks[IMX6SX_CLK_ESAI_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]); ++ imx_clk_set_rate(clks[IMX6SX_CLK_ESAI_PODF], 24576000); ++ ++ /* Set parent clock for vadc */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]); ++ ++ /* Update gpu clock from default 528M to 720M */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]); ++ ++ /* Set the UART parent if needed. */ ++ if (uart_from_osc) ++ imx_clk_set_parent(clks[IMX6SX_CLK_UART_SEL], clks[IMX6SX_CLK_OSC]); ++ else ++ imx_clk_set_parent(clks[IMX6SX_CLK_UART_SEL], clks[IMX6SX_CLK_PLL3_80M]); ++ ++ /* pll2_bus is the best parent of QSPI clock */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]); ++ imx_clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]); ++ ++ if (!imx_src_is_m4_enabled()) ++ /* default parent of can_sel clock is invalid, manually set it here */ ++ imx_clk_set_parent(clks[IMX6SX_CLK_CAN_SEL], clks[IMX6SX_CLK_PLL3_60M]); ++ /* ++ * Enable clocks only after both parent and rate are all initialized ++ * as needed ++ */ ++ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) ++ imx_clk_prepare_enable(clks[clks_init_on[i]]); ++ ++ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { ++ imx_clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]); ++ imx_clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]); ++ } ++ ++ /* Set initial power mode */ ++ imx6q_set_lpm(WAIT_CLOCKED); ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-gpt"); ++ mxc_timer_init_dt(np); ++} ++CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init); ++ ++int imx_update_shared_mem(struct clk_hw *hw, bool enable) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) { ++ if (shared_mem->imx_clk[i].self == hw->clk) ++ break; ++ } ++ ++ if (i >= ARRAY_SIZE(clks_shared)) ++ return 1; ++ ++ /* update ca9 clk status in shared memory */ ++ if (enable) ++ shared_mem->imx_clk[i].ca9_enabled = 1; ++ else ++ shared_mem->imx_clk[i].ca9_enabled = 0; ++ ++ if (shared_mem->imx_clk[i].cm4_enabled == 0) ++ return 1; ++ ++ return 0; ++} ++ ++static int __init imx_amp_power_init(void) ++{ ++ int i; ++ void __iomem *shared_mem_base; ++ ++ if (!imx_src_is_m4_enabled()) ++ return 0; ++ ++ amp_power_mutex = imx_sema4_mutex_create(0, MCC_POWER_SHMEM_NUMBER); ++ ++ shared_mem_base = ioremap_nocache(shared_mem_paddr, shared_mem_size); ++ ++ if (!amp_power_mutex) { ++ pr_err("Failed to create sema4 mutex!\n"); ++ return 0; ++ } ++ ++ shared_mem = (struct imx_shared_mem *)shared_mem_base; ++ ++ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) { ++ shared_mem->imx_clk[i].self = clks[clks_shared[i]]; ++ shared_mem->imx_clk[i].ca9_enabled = 1; ++ pr_debug("%d: name %s, addr 0x%x\n", i, ++ __clk_get_name(shared_mem->imx_clk[i].self), ++ (u32)&(shared_mem->imx_clk[i])); ++ } ++ /* enable amp power management */ ++ shared_mem->ca9_valid = SHARED_MEM_MAGIC_NUMBER; ++ ++ pr_info("A9-M4 sema4 num %d, A9-M4 magic number 0x%x - 0x%x.\n", ++ amp_power_mutex->gate_num, shared_mem->ca9_valid, ++ shared_mem->cm4_valid); ++ ++ return 0; ++} ++late_initcall(imx_amp_power_init); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-pfd.c linux-3.14.72/arch/arm/mach-imx/clk-pfd.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-pfd.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-pfd.c 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012-2014 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -12,10 +12,12 @@ + + #include + #include ++#include + #include + #include + #include + #include "clk.h" ++#include "common.h" + + /** + * struct clk_pfd - IMX PFD clock +@@ -39,20 +41,56 @@ + #define CLR 0x8 + #define OTG 0xc + +-static int clk_pfd_enable(struct clk_hw *hw) ++static void clk_pfd_do_hardware(struct clk_pfd *pfd, bool enable) ++{ ++ if (enable) ++ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); ++ else ++ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); ++} ++ ++static void clk_pfd_do_shared_clks(struct clk_hw *hw, bool enable) + { + struct clk_pfd *pfd = to_clk_pfd(hw); + +- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); ++#ifdef CONFIG_SOC_IMX6SX ++ if (imx_src_is_m4_enabled()) { ++ if (!amp_power_mutex || !shared_mem) { ++ if (enable) ++ clk_pfd_do_hardware(pfd, enable); ++ return; ++ } ++ ++ imx_sema4_mutex_lock(amp_power_mutex); ++ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER || ++ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) { ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ return; ++ } ++ ++ if (!imx_update_shared_mem(hw, enable)) { ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ return; ++ } ++ ++ clk_pfd_do_hardware(pfd, enable); ++ ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ } else ++#endif ++ clk_pfd_do_hardware(pfd, enable); ++} ++ ++static int clk_pfd_enable(struct clk_hw *hw) ++{ ++ clk_pfd_do_shared_clks(hw, true); + + return 0; + } + + static void clk_pfd_disable(struct clk_hw *hw) + { +- struct clk_pfd *pfd = to_clk_pfd(hw); +- +- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); ++ clk_pfd_do_shared_clks(hw, false); + } + + static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw, +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/clk-pllv3.c linux-3.14.72/arch/arm/mach-imx/clk-pllv3.c +--- linux-3.14.72.orig/arch/arm/mach-imx/clk-pllv3.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/clk-pllv3.c 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012-2015 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -13,18 +13,18 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include "clk.h" ++#include "common.h" + + #define PLL_NUM_OFFSET 0x10 + #define PLL_DENOM_OFFSET 0x20 + + #define BM_PLL_POWER (0x1 << 12) +-#define BM_PLL_ENABLE (0x1 << 13) +-#define BM_PLL_BYPASS (0x1 << 16) + #define BM_PLL_LOCK (0x1 << 31) + + /** +@@ -61,70 +61,78 @@ + break; + if (time_after(jiffies, timeout)) + break; +- usleep_range(50, 500); + } 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_do_hardware(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; +- +- val = readl_relaxed(pll->base); +- val &= ~BM_PLL_BYPASS; +- writel_relaxed(val, pll->base); ++ if (enable) { ++ 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; ++ } else { ++ if (pll->powerup_set) ++ val &= ~BM_PLL_POWER; ++ else ++ val |= BM_PLL_POWER; ++ writel_relaxed(val, pll->base); ++ } + + return 0; + } + +-static void clk_pllv3_unprepare(struct clk_hw *hw) ++static void clk_pllv3_do_shared_clks(struct clk_hw *hw, bool enable) + { +- struct clk_pllv3 *pll = to_clk_pllv3(hw); +- u32 val; +- +- 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); ++#ifdef CONFIG_SOC_IMX6SX ++ if (imx_src_is_m4_enabled()) { ++ if (!amp_power_mutex || !shared_mem) { ++ if (enable) ++ clk_pllv3_do_hardware(hw, enable); ++ return; ++ } ++ ++ imx_sema4_mutex_lock(amp_power_mutex); ++ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER || ++ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) { ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ return; ++ } ++ ++ if (!imx_update_shared_mem(hw, enable)) { ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ return; ++ } ++ clk_pllv3_do_hardware(hw, enable); ++ ++ imx_sema4_mutex_unlock(amp_power_mutex); ++ } else ++#endif ++ clk_pllv3_do_hardware(hw, enable); + } + +-static int clk_pllv3_enable(struct clk_hw *hw) ++static int clk_pllv3_prepare(struct clk_hw *hw) + { +- struct clk_pllv3 *pll = to_clk_pllv3(hw); +- u32 val; +- +- val = readl_relaxed(pll->base); +- val |= BM_PLL_ENABLE; +- writel_relaxed(val, pll->base); ++ clk_pllv3_do_shared_clks(hw, true); + + return 0; + } + +-static void clk_pllv3_disable(struct clk_hw *hw) ++static void clk_pllv3_unprepare(struct clk_hw *hw) + { +- struct clk_pllv3 *pll = to_clk_pllv3(hw); +- u32 val; +- +- val = readl_relaxed(pll->base); +- val &= ~BM_PLL_ENABLE; +- writel_relaxed(val, pll->base); ++ clk_pllv3_do_shared_clks(hw, false); + } + + static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw, +@@ -169,8 +177,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, + .round_rate = clk_pllv3_round_rate, + .set_rate = clk_pllv3_set_rate, +@@ -225,8 +231,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, + .round_rate = clk_pllv3_sys_round_rate, + .set_rate = clk_pllv3_sys_set_rate, +@@ -299,8 +303,6 @@ + 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, + .round_rate = clk_pllv3_av_round_rate, + .set_rate = clk_pllv3_av_set_rate, +@@ -315,8 +317,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, + }; + +@@ -355,7 +355,7 @@ + + init.name = name; + init.ops = ops; +- init.flags = 0; ++ init.flags = CLK_SET_RATE_GATE | CLK_GET_RATE_NOCACHE; + init.parent_names = &parent_name; + init.num_parents = 1; + +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/common.h linux-3.14.72/arch/arm/mach-imx/common.h +--- linux-3.14.72.orig/arch/arm/mach-imx/common.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/common.h 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + + /* +@@ -17,6 +17,8 @@ + struct platform_device; + struct pt_regs; + struct clk; ++struct clk_hw; ++struct device_node; + enum mxc_cpu_pwr_mode; + + void mx1_map_io(void); +@@ -56,6 +58,7 @@ + void imx53_init_late(void); + void epit_timer_init(void __iomem *base, int irq); + void mxc_timer_init(void __iomem *, int); ++void mxc_timer_init_dt(struct device_node *); + int mx1_clocks_init(unsigned long fref); + int mx21_clocks_init(unsigned long lref, unsigned long fref); + int mx25_clocks_init(void); +@@ -80,6 +83,18 @@ + unsigned int imx_get_soc_revision(void); + void imx_init_revision_from_anatop(void); + struct device *imx_soc_device_init(void); ++unsigned int imx_gpc_is_mf_mix_off(void); ++void imx6sx_set_m4_highfreq(bool high_freq); ++void imx_mu_enable_m4_irqs_in_gic(bool enable); ++void imx_gpc_add_m4_wake_up_irq(u32 irq, bool enable); ++void imx_gpc_hold_m4_in_sleep(void); ++void imx_gpc_release_m4_in_sleep(void); ++int imx_update_shared_mem(struct clk_hw *hw, bool enable); ++bool imx_src_is_m4_enabled(void); ++void mcc_receive_from_mu_buffer(unsigned int index, unsigned int *data); ++void mcc_send_via_mu_buffer(unsigned int index, unsigned int data); ++unsigned int imx_gpc_is_m4_sleeping(void); ++bool imx_mu_is_m4_in_low_freq(void); + + enum mxc_cpu_pwr_mode { + WAIT_CLOCKED, /* wfi only */ +@@ -116,20 +131,19 @@ + 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); + void imx_smp_prepare(void); +-void imx_scu_standby_enable(void); + #else + static inline void imx_scu_map_io(void) {} + static inline void imx_smp_prepare(void) {} +-static inline void imx_scu_standby_enable(void) {} + #endif ++extern void imx6_pm_map_io(void); ++ + 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); +@@ -139,13 +153,31 @@ + void imx_anatop_pre_suspend(void); + void imx_anatop_post_resume(void); + int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +-void imx6q_set_chicken_bit(void); ++void imx6q_set_int_mem_clk_lpm(bool enable); ++void imx6sl_set_wait_clk(bool enter); ++void imx6_enet_mac_init(const char *compatible); ++int imx_mmdc_get_ddr_type(void); ++void imx6_busfreq_map_io(void); ++void imx6sx_low_power_idle(void); ++void imx6q_enable_rbc(bool enable); + + 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 imx6sx_pm_init(void); + void imx6q_pm_set_ccm_base(void __iomem *base); ++ + #ifdef CONFIG_PM + void imx5_pm_init(void); + #else +@@ -165,5 +197,5 @@ + #endif + + extern struct smp_operations imx_smp_ops; +- ++extern void imx6sl_low_power_wfi(void __iomem *base); + #endif +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/common-imx6.c linux-3.14.72/arch/arm/mach-imx/common-imx6.c +--- linux-3.14.72.orig/arch/arm/mach-imx/common-imx6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/common-imx6.c 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,96 @@ ++/* ++ * Copyright 2011-2015 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 "common.h" ++#define OCOTP_MACn(n) (0x00000620 + (n) * 0x10) ++ ++void __init imx6_enet_mac_init(const char *compatible) ++{ ++ struct device_node *ocotp_np, *enet_np, *from = NULL; ++ void __iomem *base; ++ struct property *newmac; ++ u32 macaddr_low; ++ u32 macaddr_high = 0; ++ u32 macaddr1_high = 0; ++ u8 *macaddr; ++ int i; ++ ++ for (i = 0; i < 2; i++) { ++ enet_np = of_find_compatible_node(from, NULL, compatible); ++ if (!enet_np) ++ return; ++ ++ from = enet_np; ++ ++ if (of_get_mac_address(enet_np)) ++ goto put_enet_node; ++ ++ ocotp_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp"); ++ if (!ocotp_np) { ++ pr_warn("failed to find ocotp node\n"); ++ goto put_enet_node; ++ } ++ ++ base = of_iomap(ocotp_np, 0); ++ if (!base) { ++ pr_warn("failed to map ocotp\n"); ++ goto put_ocotp_node; ++ } ++ ++ macaddr_low = readl_relaxed(base + OCOTP_MACn(1)); ++ if (i) ++ macaddr1_high = readl_relaxed(base + OCOTP_MACn(2)); ++ else ++ macaddr_high = readl_relaxed(base + OCOTP_MACn(0)); ++ ++ newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); ++ if (!newmac) ++ goto put_ocotp_node; ++ ++ newmac->value = newmac + 1; ++ newmac->length = 6; ++ newmac->name = kstrdup("local-mac-address", GFP_KERNEL); ++ if (!newmac->name) { ++ kfree(newmac); ++ goto put_ocotp_node; ++ } ++ ++ macaddr = newmac->value; ++ if (i) { ++ macaddr[5] = (macaddr_low >> 16) & 0xff; ++ macaddr[4] = (macaddr_low >> 24) & 0xff; ++ macaddr[3] = macaddr1_high & 0xff; ++ macaddr[2] = (macaddr1_high >> 8) & 0xff; ++ macaddr[1] = (macaddr1_high >> 16) & 0xff; ++ macaddr[0] = (macaddr1_high >> 24) & 0xff; ++ } else { ++ macaddr[5] = macaddr_high & 0xff; ++ macaddr[4] = (macaddr_high >> 8) & 0xff; ++ macaddr[3] = (macaddr_high >> 16) & 0xff; ++ macaddr[2] = (macaddr_high >> 24) & 0xff; ++ macaddr[1] = macaddr_low & 0xff; ++ macaddr[0] = (macaddr_low >> 8) & 0xff; ++ } ++ ++ of_update_property(enet_np, newmac); ++ ++put_ocotp_node: ++ of_node_put(ocotp_np); ++put_enet_node: ++ of_node_put(enet_np); ++ } ++} ++ +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/cpu.c linux-3.14.72/arch/arm/mach-imx/cpu.c +--- linux-3.14.72.orig/arch/arm/mach-imx/cpu.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/cpu.c 2016-06-19 22:11:55.049156848 +0200 +@@ -111,6 +111,9 @@ + case MXC_CPU_IMX6DL: + soc_id = "i.MX6DL"; + break; ++ case MXC_CPU_IMX6SX: ++ soc_id = "i.MX6SX"; ++ break; + case MXC_CPU_IMX6Q: + soc_id = "i.MX6Q"; + break; +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/cpuidle.h linux-3.14.72/arch/arm/mach-imx/cpuidle.h +--- linux-3.14.72.orig/arch/arm/mach-imx/cpuidle.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/cpuidle.h 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012-2014 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -13,6 +13,8 @@ + #ifdef CONFIG_CPU_IDLE + extern int imx5_cpuidle_init(void); + extern int imx6q_cpuidle_init(void); ++extern int imx6sl_cpuidle_init(void); ++extern int imx6sx_cpuidle_init(void); + #else + static inline int imx5_cpuidle_init(void) + { +@@ -22,4 +24,12 @@ + { + return 0; + } ++static inline int imx6sl_cpuidle_init(void) ++{ ++ return 0; ++} ++static inline int imx6sx_cpuidle_init(void) ++{ ++ return 0; ++} + #endif +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/cpuidle-imx6q.c linux-3.14.72/arch/arm/mach-imx/cpuidle-imx6q.c +--- linux-3.14.72.orig/arch/arm/mach-imx/cpuidle-imx6q.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/cpuidle-imx6q.c 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2012 Freescale Semiconductor, Inc. ++ * Copyright (C) 2012-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 +@@ -65,11 +65,8 @@ + + int __init imx6q_cpuidle_init(void) + { +- /* 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 INT_MEM_CLK_LPM bit to get a reliable WAIT mode support */ ++ imx6q_set_int_mem_clk_lpm(true); + + return cpuidle_register(&imx6q_cpuidle_driver, NULL); + } +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/cpuidle-imx6sl.c linux-3.14.72/arch/arm/mach-imx/cpuidle-imx6sl.c +--- linux-3.14.72.orig/arch/arm/mach-imx/cpuidle-imx6sl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/cpuidle-imx6sl.c 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (C) 2014-2015 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 "common.h" ++#include "cpuidle.h" ++#include "hardware.h" ++ ++#define MAX_MMDC_IO_NUM 19 ++ ++static void __iomem *wfi_iram_base; ++extern unsigned long iram_tlb_base_addr; ++extern int ultra_low_bus_freq_mode; ++extern int audio_bus_freq_mode; ++extern unsigned long mx6sl_lpm_wfi_start asm("mx6sl_lpm_wfi_start"); ++extern unsigned long mx6sl_lpm_wfi_end asm("mx6sl_lpm_wfi_end"); ++ ++struct imx6_cpuidle_pm_info { ++ u32 pm_info_size; /* Size of pm_info */ ++ u32 ttbr; ++ void __iomem *mmdc_base; ++ void __iomem *iomuxc_base; ++ void __iomem *ccm_base; ++ void __iomem *l2_base; ++ void __iomem *anatop_base; ++ u32 mmdc_io_num; /*Number of MMDC IOs which need saved/restored. */ ++ u32 mmdc_io_val[MAX_MMDC_IO_NUM][2]; /* To save offset and value */ ++} __aligned(8); ++ ++static const u32 imx6sl_mmdc_io_offset[] __initconst = { ++ 0x30c, 0x310, 0x314, 0x318, /* DQM0 ~ DQM3 */ ++ 0x5c4, 0x5cc, 0x5d4, 0x5d8, /* GPR_B0DS ~ GPR_B3DS */ ++ 0x300, 0x31c, 0x338, 0x5ac, /*CAS, RAS, SDCLK_0, GPR_ADDS */ ++ 0x33c, 0x340, 0x5b0, 0x5c0, /*SODT0, SODT1, ,MODE_CTL, MODE */ ++ 0x330, 0x334, 0x320, /*SDCKE0, SDCK1, RESET */ ++}; ++ ++static struct regulator *vbus_ldo; ++static struct regulator_dev *ldo2p5_dummy_regulator_rdev; ++static struct regulator_init_data ldo2p5_dummy_initdata = { ++ .constraints = { ++ .valid_ops_mask = REGULATOR_CHANGE_STATUS, ++ }, ++}; ++static int ldo2p5_dummy_enable; ++ ++static void (*imx6sl_wfi_in_iram_fn)(void __iomem *iram_vbase, ++ int audio_mode, bool vbus_ldo); ++ ++static int imx6sl_enter_wait(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ imx6q_set_lpm(WAIT_UNCLOCKED); ++ if (audio_bus_freq_mode || ultra_low_bus_freq_mode) { ++ imx6sl_wfi_in_iram_fn(wfi_iram_base, audio_bus_freq_mode, ++ regulator_is_enabled(vbus_ldo)); ++ } else { ++ /* ++ * Software workaround for ERR005311, see function ++ * description for details. ++ */ ++ 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 imx6_cpuidle_pm_info *pm_info; ++ int i; ++ const u32 *mmdc_offset_array; ++ u32 wfi_code_size; ++ ++ vbus_ldo = regulator_get(NULL, "ldo2p5-dummy"); ++ if (IS_ERR(vbus_ldo)) ++ vbus_ldo = NULL; ++ ++ wfi_iram_base = (void *)(iram_tlb_base_addr + MX6_CPUIDLE_IRAM_ADDR_OFFSET); ++ ++ /* Make sure wif_iram_base is 8 byte aligned. */ ++ if ((uintptr_t)(wfi_iram_base) & (FNCPY_ALIGN - 1)) ++ wfi_iram_base += FNCPY_ALIGN - ((uintptr_t)wfi_iram_base % (FNCPY_ALIGN)); ++ ++ pm_info = wfi_iram_base; ++ pm_info->pm_info_size = sizeof(*pm_info); ++ pm_info->mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset); ++ mmdc_offset_array = imx6sl_mmdc_io_offset; ++ pm_info->mmdc_base = (void __iomem *)IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); ++ pm_info->ccm_base = (void __iomem *)IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); ++ pm_info->anatop_base = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); ++ pm_info->iomuxc_base = (void __iomem *)IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); ++ pm_info->l2_base = (void __iomem *)IMX_IO_P2V(MX6Q_L2_BASE_ADDR); ++ ++ /* Only save mmdc io offset, settings will be saved in asm code */ ++ for (i = 0; i < pm_info->mmdc_io_num; i++) ++ pm_info->mmdc_io_val[i][0] = mmdc_offset_array[i]; ++ ++ /* calculate the wfi code size */ ++ wfi_code_size = (&mx6sl_lpm_wfi_end -&mx6sl_lpm_wfi_start) *4; ++ ++ imx6sl_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + sizeof(*pm_info), ++ &imx6sl_low_power_wfi, wfi_code_size); ++ ++ return cpuidle_register(&imx6sl_cpuidle_driver, NULL); ++} ++ ++static int imx_ldo2p5_dummy_enable(struct regulator_dev *rdev) ++{ ++ ldo2p5_dummy_enable = 1; ++ return 0; ++} ++ ++static int imx_ldo2p5_dummy_disable(struct regulator_dev *rdev) ++{ ++ ldo2p5_dummy_enable = 0; ++ return 0; ++} ++ ++static int imx_ldo2p5_dummy_is_enable(struct regulator_dev *rdev) ++{ ++ return ldo2p5_dummy_enable; ++} ++ ++static struct regulator_ops ldo2p5_dummy_ops = { ++ .enable = imx_ldo2p5_dummy_enable, ++ .disable = imx_ldo2p5_dummy_disable, ++ .is_enabled = imx_ldo2p5_dummy_is_enable, ++}; ++ ++static struct regulator_desc ldo2p5_dummy_desc = { ++ .name = "ldo2p5-dummy", ++ .id = -1, ++ .type = REGULATOR_VOLTAGE, ++ .owner = THIS_MODULE, ++ .ops = &ldo2p5_dummy_ops, ++}; ++ ++static int ldo2p5_dummy_probe(struct platform_device *pdev) ++{ ++ struct regulator_config config = { }; ++ int ret; ++ ++ config.dev = &pdev->dev; ++ config.init_data = &ldo2p5_dummy_initdata; ++ config.of_node = pdev->dev.of_node; ++ ++ ldo2p5_dummy_regulator_rdev = regulator_register(&ldo2p5_dummy_desc, &config); ++ if (IS_ERR(ldo2p5_dummy_regulator_rdev)) { ++ ret = PTR_ERR(ldo2p5_dummy_regulator_rdev); ++ dev_err(&pdev->dev, "Failed to register dummy ldo2p5 regulator: %d\n", ret); ++ return ret; ++ } ++ return 0; ++} ++ ++static const struct of_device_id imx_ldo2p5_dummy_ids[] = { ++ { .compatible = "fsl,imx6-dummy-ldo2p5"}, ++ }; ++MODULE_DEVICE_TABLE(ofm, imx_ldo2p5_dummy_ids); ++ ++static struct platform_driver ldo2p5_dummy_driver = { ++ .probe = ldo2p5_dummy_probe, ++ .driver = { ++ .name = "ldo2p5-dummy", ++ .owner = THIS_MODULE, ++ .of_match_table = imx_ldo2p5_dummy_ids, ++ }, ++}; ++ ++module_platform_driver(ldo2p5_dummy_driver); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/cpuidle-imx6sx.c linux-3.14.72/arch/arm/mach-imx/cpuidle-imx6sx.c +--- linux-3.14.72.orig/arch/arm/mach-imx/cpuidle-imx6sx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/cpuidle-imx6sx.c 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,276 @@ ++/* ++ * Copyright (C) 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "cpuidle.h" ++#include "hardware.h" ++ ++#define MX6_MAX_MMDC_IO_NUM 19 ++ ++#define PMU_LOW_PWR_CTRL 0x270 ++#define XTALOSC24M_OSC_CONFIG0 0x2a0 ++#define XTALOSC24M_OSC_CONFIG1 0x2b0 ++#define XTALOSC24M_OSC_CONFIG2 0x2c0 ++#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT 24 ++#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK 0xf ++#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT 16 ++#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK 0xf ++#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT 12 ++#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT 4 ++#define XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT 1 ++#define XTALOSC24M_OSC_CONFIG0_START_SHIFT 0 ++#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT 20 ++#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT 0 ++#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK 0xfff ++#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT 0 ++ ++static void __iomem *wfi_iram_base; ++static void __iomem *wfi_iram_base_phys; ++extern unsigned long iram_tlb_phys_addr; ++extern unsigned long mx6sx_lpm_wfi_start asm("mx6sx_lpm_wfi_start"); ++extern unsigned long mx6sx_lpm_wfi_end asm("mx6sx_lpm_wfi_end"); ++extern u32 low_bus_freq_mode; ++ ++struct imx6_pm_base { ++ phys_addr_t pbase; ++ void __iomem *vbase; ++}; ++ ++static const u32 imx6sx_mmdc_io_offset[] __initconst = { ++ 0x2ec, 0x2f0, 0x2f4, 0x2f8, /* DQM0 ~ DQM3 */ ++ 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */ ++ 0x60c, 0x610, 0x61c, 0x620, /* B0DS ~ B3DS */ ++ 0x5f8, 0x608, 0x310, 0x314, /* CTL, MODE, SODT0, SODT1 */ ++ 0x300, 0x2fc, 0x32c, /* CAS, RAS, SDCLK_0 */ ++}; ++ ++struct imx6_cpuidle_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 pm_info_size; /* Size of pm_info. */ ++ u32 ttbr; ++ struct imx6_pm_base mmdc_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; ++ struct imx6_pm_base anatop_base; ++ struct imx6_pm_base src_base; ++ struct imx6_pm_base sema4_base; ++ u32 saved_diagnostic; /* To save disagnostic register */ ++ 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); ++ ++static void (*imx6sx_wfi_in_iram_fn)(void __iomem *iram_vbase); ++ ++static int imx6_idle_finish(unsigned long val) ++{ ++ imx6sx_wfi_in_iram_fn(wfi_iram_base); ++ ++ return 0; ++} ++ ++static int imx6sx_enter_wait(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ imx6q_set_lpm(WAIT_UNCLOCKED); ++ if ((index == 1) || (!low_bus_freq_mode && index == 2)) { ++ cpu_do_idle(); ++ } else { ++ /* Need to notify there is a cpu pm operation. */ ++ cpu_pm_enter(); ++ cpu_cluster_pm_enter(); ++ ++ cpu_suspend(0, imx6_idle_finish); ++ ++ cpu_cluster_pm_exit(); ++ cpu_pm_exit(); ++ imx6q_enable_rbc(false); ++ } ++ ++ imx6q_set_lpm(WAIT_CLOCKED); ++ ++ return index; ++} ++ ++static struct cpuidle_driver imx6sx_cpuidle_driver = { ++ .name = "imx6sx_cpuidle", ++ .owner = THIS_MODULE, ++ .states = { ++ /* WFI */ ++ ARM_CPUIDLE_WFI_STATE, ++ /* WAIT MODE */ ++ { ++ .exit_latency = 50, ++ .target_residency = 75, ++ .flags = CPUIDLE_FLAG_TIME_VALID, ++ .enter = imx6sx_enter_wait, ++ .name = "WAIT", ++ .desc = "Clock off", ++ }, ++ /* LOW POWER IDLE */ ++ { ++ /* ++ * RBC 31us + ARM gating 93us + RBC clear 65us ++ * + PLL2 relock 450us and some margin, here set ++ * it to 650us. ++ */ ++ .exit_latency = 650, ++ .target_residency = 1000, ++ .flags = CPUIDLE_FLAG_TIME_VALID, ++ .enter = imx6sx_enter_wait, ++ .name = "LOW-POWER-IDLE", ++ .desc = "ARM power off", ++ }, ++ ++ }, ++ .state_count = 3, ++ .safe_state_index = 0, ++}; ++ ++int __init imx6sx_cpuidle_init(void) ++{ ++ struct imx6_cpuidle_pm_info *cpuidle_pm_info; ++ int i; ++ const u32 *mmdc_offset_array; ++ u32 wfi_code_size, val; ++ ++ wfi_iram_base_phys = (void *)(iram_tlb_phys_addr + MX6_CPUIDLE_IRAM_ADDR_OFFSET); ++ ++ /* Make sure wfi_iram_base is 8 byte aligned. */ ++ if ((uintptr_t)(wfi_iram_base_phys) & (FNCPY_ALIGN - 1)) ++ wfi_iram_base_phys += FNCPY_ALIGN - ((uintptr_t)wfi_iram_base_phys % (FNCPY_ALIGN)); ++ ++ wfi_iram_base = (void *)IMX_IO_P2V((unsigned long) wfi_iram_base_phys); ++ ++ cpuidle_pm_info = wfi_iram_base; ++ cpuidle_pm_info->pbase = (phys_addr_t) wfi_iram_base_phys; ++ cpuidle_pm_info->pm_info_size = sizeof(*cpuidle_pm_info); ++ cpuidle_pm_info->resume_addr = virt_to_phys(v7_cpu_resume); ++ cpuidle_pm_info->mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset); ++ mmdc_offset_array = imx6sx_mmdc_io_offset; ++ ++ cpuidle_pm_info->mmdc_base.pbase = MX6Q_MMDC_P0_BASE_ADDR; ++ cpuidle_pm_info->mmdc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); ++ ++ cpuidle_pm_info->ccm_base.pbase = MX6Q_CCM_BASE_ADDR; ++ cpuidle_pm_info->ccm_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); ++ ++ cpuidle_pm_info->anatop_base.pbase = MX6Q_ANATOP_BASE_ADDR; ++ cpuidle_pm_info->anatop_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); ++ ++ cpuidle_pm_info->gpc_base.pbase = MX6Q_GPC_BASE_ADDR; ++ cpuidle_pm_info->gpc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_GPC_BASE_ADDR); ++ ++ cpuidle_pm_info->iomuxc_base.pbase = MX6Q_IOMUXC_BASE_ADDR; ++ cpuidle_pm_info->iomuxc_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); ++ ++ cpuidle_pm_info->l2_base.pbase = MX6Q_L2_BASE_ADDR; ++ cpuidle_pm_info->l2_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_L2_BASE_ADDR); ++ ++ cpuidle_pm_info->src_base.pbase = MX6Q_SRC_BASE_ADDR; ++ cpuidle_pm_info->src_base.vbase = (void __iomem *)IMX_IO_P2V(MX6Q_SRC_BASE_ADDR); ++ ++ cpuidle_pm_info->sema4_base.pbase = MX6Q_SEMA4_BASE_ADDR; ++ cpuidle_pm_info->sema4_base.vbase = ++ (void __iomem *)IMX_IO_P2V(MX6Q_SEMA4_BASE_ADDR); ++ ++ /* only save mmdc io offset, settings will be saved in asm code */ ++ for (i = 0; i < cpuidle_pm_info->mmdc_io_num; i++) ++ cpuidle_pm_info->mmdc_io_val[i][0] = mmdc_offset_array[i]; ++ ++ /* code size should include cpuidle_pm_info size */ ++ wfi_code_size = (&mx6sx_lpm_wfi_end -&mx6sx_lpm_wfi_start) *4 + sizeof(*cpuidle_pm_info); ++ imx6sx_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base + sizeof(*cpuidle_pm_info), ++ &imx6sx_low_power_idle, wfi_code_size); ++ ++ imx6q_set_int_mem_clk_lpm(true); ++ ++ if (imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2) { ++ /* ++ * enable RC-OSC here, as it needs at least 4ms for RC-OSC to ++ * be stable, low power idle flow can NOT endure this big ++ * latency, so we make RC-OSC self-tuning enabled here. ++ */ ++ val = readl_relaxed(cpuidle_pm_info->anatop_base.vbase + ++ PMU_LOW_PWR_CTRL); ++ val |= 0x1; ++ writel_relaxed(val, cpuidle_pm_info->anatop_base.vbase + ++ PMU_LOW_PWR_CTRL); ++ /* ++ * config RC-OSC freq ++ * tune_enable = 1;tune_start = 1;hyst_plus = 0;hyst_minus = 0; ++ * osc_prog = 0xa7; ++ */ ++ writel_relaxed( ++ 0x4 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT | ++ 0xa7 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT | ++ 0x1 << XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT | ++ 0x1 << XTALOSC24M_OSC_CONFIG0_START_SHIFT, ++ cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG0); ++ /* set count_trg = 0x2dc */ ++ writel_relaxed( ++ 0x40 << XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT | ++ 0x2dc << XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT, ++ cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG1); ++ /* wait 4ms according to hardware design */ ++ msleep(4); ++ /* ++ * now add some hysteresis, hyst_plus=3, hyst_minus=3 ++ * (the minimum hysteresis that looks good is 2) ++ */ ++ val = readl_relaxed(cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG0); ++ val &= ~((XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK << ++ XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | ++ (XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK << ++ XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT)); ++ val |= (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) | ++ (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT); ++ writel_relaxed(val, cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG0); ++ /* set the count_1m_trg = 0x2d7 */ ++ val = readl_relaxed(cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG2); ++ val &= ~(XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK << ++ XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT); ++ val |= 0x2d7 << XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT; ++ writel_relaxed(val, cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG2); ++ /* ++ * hardware design require to write XTALOSC24M_OSC_CONFIG0 or ++ * XTALOSC24M_OSC_CONFIG1 to ++ * make XTALOSC24M_OSC_CONFIG2 write work ++ */ ++ val = readl_relaxed(cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG1); ++ writel_relaxed(val, cpuidle_pm_info->anatop_base.vbase + ++ XTALOSC24M_OSC_CONFIG1); ++ } ++ ++ return cpuidle_register(&imx6sx_cpuidle_driver, NULL); ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/ddr3_freq_imx6.S linux-3.14.72/arch/arm/mach-imx/ddr3_freq_imx6.S +--- linux-3.14.72.orig/arch/arm/mach-imx/ddr3_freq_imx6.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/ddr3_freq_imx6.S 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,1116 @@ ++/* ++ * Copyright (C) 2011-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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include "hardware.h" ++ ++#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 ++ ++.extern iram_tlb_phys_addr ++#ifdef CONFIG_SMP ++.extern imx_scu_base ++#endif ++ ++.globl mx6_ddr3_freq_change_start ++.globl mx6_ddr3_freq_change_end ++.globl wfe_ddr3_freq_change_start ++.globl wfe_ddr3_freq_change_end ++ ++ .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 ++ ++ .macro disable_l1_dcache ++ ++ /* ++ * Flush all data from the L1 data cache before disabling ++ * SCTLR.C bit. ++ */ ++ push {r0 - r11, lr} ++ ++ ldr r7, =v7_flush_kern_cache_all ++ mov lr, pc ++ mov pc, r7 ++ pop {r0 - r11, lr} ++ ++ /* disable d-cache */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ dsb ++ isb ++ ++ push {r0 - r11, lr} ++ ++ ldr r7, =v7_flush_kern_cache_all ++ mov lr, pc ++ mov pc, r7 ++ pop {r0 - r11, lr} ++ ++ .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) ++ ++mx6_ddr3_freq_change_start: ++ 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 ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ ldr r6, =iram_tlb_phys_addr ++ ldr r7, [r6] ++ ++ /* ++ * Need to flush and disable L1 before disabling L2, we need data to ++ * coherent. Flushing L1 pushes everyhting to L2. We sync L2 later, but ++ * it can still have dirty lines. While exiting, we need to enable L2 first ++ * and then L1. ++ . */ ++ disable_l1_dcache ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* ++ * Make sure the L2 buffers are drained. ++ * Sync operation on L2 drains the buffers. ++ */ ++ ldr r12, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ ++ /* Wait for background operations to complete. */ ++wait_for_l2_to_idle: ++ ldr r1, [r12, #L2_CACHE_SYNC] ++ cmp r1, #0x0 ++ bne wait_for_l2_to_idle ++ ++ mov r1, #0x0 ++ str r1, [r12, #L2_CACHE_SYNC] ++ ++ /* Disable L2. */ ++ str r1, [r12, #0x100] ++ ++ dsb ++ isb ++#endif ++ ++ /* ++ * To ensure no page table walks occur in DDR, we ++ * have a another page table stored in IRAM that only ++ * contains entries pointing to IRAM, AIPS1 and AIPS2. ++ * We need to set the TTBR1 to the new IRAM TLB. ++ * Do the following steps: ++ * 1. Flush the Branch Target Address Cache (BTAC) ++ * 2. Set TTBR1 to point to IRAM page table. ++ * 3. Disable page table walks in TTBR0 (PD0 = 1) ++ * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 ++ * and 2-4G is translated by TTBR1. ++ */ ++ ++ ++ /* Now switch the TTBR. */ ++ /* Disable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ dsb ++ isb ++ ++ /* Store the IRAM table in TTBR1 */ ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ /* Read TTBCR and set PD0=1, N = 1 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ orr r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ ++ ldr r5, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) ++ ldr r6, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) ++ ldr r7, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR) ++ ++ /* Read the Original MU delay value */ ++ ldr r1, [r5, #MMDC0_MPMUR0] ++ mov r10, r1, lsr #16 ++ ldr r1, =0x3ff ++ and r10, r10, r1 ++ ++ /* 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] ++ ++ /* Add workaround for ERR005778.*/ ++ /* double the original MU_UNIT_DEL_NUM. */ ++ lsl r10, r10, #1 ++ ++ /* Bypass the automatic MU by setting the mu_byp_en */ ++ ldr r2, [r5, #MMDC0_MPMUR0] ++ orr r2, r2, #0x400 ++ orr r2, r2, r10 ++ str r2, [r5, #MMDC0_MPMUR0] ++ ldr r0, =MMDC1_MPMUR0 ++ str r2, [r5, r0] ++ ++ /* Now perform a force measure */ ++ ldr r0, [r5, #MMDC0_MPMUR0] ++ orr r0, r0, #0x800 ++ str r0, [r5, #MMDC0_MPMUR0] ++ ldr r2, =MMDC1_MPMUR0 ++ str r0, [r5, r2] ++ /* Wait for FRC_MSR to clear. */ ++1: ++ ldr r0, [r5, #MMDC0_MPMUR0] ++ and r0, r0, #0x800 ++ ldr r1, [r5, r2] ++ and r1, r1, #0x800 ++ orr r0, r0, r1 ++ cmp r0, #0x0 ++ bne 1b ++ ++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, =0xa1390003 ++ 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] ++ ++ /* Wait for FRC_MSR to clear. */ ++1: ++ ldr r0, [r5, #MMDC0_MPMUR0] ++ and r0, r0, #0x800 ++ ldr r1, [r5, r2] ++ and r1, r1, #0x800 ++ orr r0, r0, r1 ++ cmp r0, #0x0 ++ bne 1b ++ ++ /* 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 ++ ++ /* 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] ++ ++ /* Wait for FRC_MSR to clear. */ ++1: ++ ldr r0, [r5, #MMDC0_MPMUR0] ++ and r0, r0, #0x800 ++ ldr r1, [r5, r2] ++ and r1, r1, #0x800 ++ orr r0, r0, r1 ++ cmp r0, #0x0 ++ bne 1b ++ ++ /* 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: ++ /* MMDC0_MAPSR adopt power down enable. */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ bic r0, r0, #0x01 ++ str r0, [r5, #MMDC0_MAPSR] ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* Enable L2. */ ++ ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ ldr r6, =0x1 ++ str r6, [r7, #0x100] ++ isb ++ dsb ++#endif ++ ++ /* Enable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Restore the TTBCR */ ++ dsb ++ isb ++ ++ /* Read TTBCR and set PD0=0, N = 0 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ bic r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ /* Enable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ isb ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ isb ++ dsb ++ ++ /* restore registers */ ++ ldmfd sp!, {r4-r12} ++ mov pc, lr ++ ++ /* ++ * Add ltorg here to ensure that all ++ * literals are stored here and are ++ * within the text space. ++ */ ++ .ltorg ++mx6_ddr3_freq_change_end: ++ ++#ifdef CONFIG_SMP ++ .align 3 ++ ++ENTRY(wfe_ddr3_freq_change) ++wfe_ddr3_freq_change_start: ++ push {r4 - r11, lr} ++ ++ mov r6, r0 ++ mov r7, r1 ++ ++ dsb ++ isb ++ ++ disable_l1_dcache ++ ++ isb ++ ++ /* Turn off SMP bit. */ ++ mrc p15, 0, r8, c1, c0, 1 ++ bic r8, r8, #0x40 ++ mcr p15, 0, r8, c1, c0, 1 ++ ++ isb ++ ++ /* Inform the SCU we are going to enter WFE. */ ++ push {r0 - r11, lr} ++ ++ ldr r0,=imx_scu_base ++ ldr r0, [r0] ++ mov r1, #SCU_PM_DORMANT ++ ldr r3, =scu_power_mode ++ mov lr, pc ++ mov pc, r3 ++ ++ pop {r0 - r11, lr} ++ ++go_back_wfe: ++ wfe ++ ++ ldr r3, [r7] ++ cmp r3, #1 ++ beq go_back_wfe ++ ++ /* Turn ON SMP bit. */ ++ mrc p15, 0, r8, c1, c0, 1 ++ orr r8, r8, #0x40 ++ mcr p15, 0, r8, c1, c0, 1 ++ ++ isb ++ /* Enable L1 data cache. */ ++ mrc p15, 0, r8, c1, c0, 0 ++ orr r8, r8, #0x4 ++ mcr p15, 0, r8, c1, c0, 0 ++ isb ++ ++ /* Inform the SCU we have exited WFE. */ ++ push {r0 - r11, lr} ++ ++ ldr r0,=imx_scu_base ++ ldr r0, [r0] ++ mov r1, #SCU_PM_NORMAL ++ ldr r3, =scu_power_mode ++ mov lr, pc ++ mov pc, r3 ++ ++ pop {r0 - r11, lr} ++ ++ /* Pop all saved registers. */ ++ pop {r4 - r11, lr} ++ mov pc, lr ++ .ltorg ++wfe_ddr3_freq_change_end: ++#endif +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/ddr3_freq_imx6sx.S linux-3.14.72/arch/arm/mach-imx/ddr3_freq_imx6sx.S +--- linux-3.14.72.orig/arch/arm/mach-imx/ddr3_freq_imx6sx.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/ddr3_freq_imx6sx.S 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,714 @@ ++/* ++ * Copyright (C) 2011-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. ++ */ ++ ++#include ++#include "hardware.h" ++ ++.globl imx6sx_ddr3_freq_change_start ++.globl imx6sx_ddr3_freq_change_end ++ ++#define MMDC0_MDPDC 0x4 ++#define MMDC0_MDCF0 0xc ++#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 MMDC0_MPODTCTRL 0x818 ++#define MMDC0_MPDGCTRL0 0x83c ++#define MMDC0_MPMUR0 0x8b8 ++ ++#define CCM_CBCDR 0x14 ++#define CCM_CBCMR 0x18 ++#define CCM_CSCMR1 0x1c ++#define CCM_CDHIPR 0x48 ++ ++#define L2_CACHE_SYNC 0x730 ++ ++#define BUSFREQ_INFO_FREQ_OFFSET 0x0 ++#define BUSFREQ_INFO_DDR_SETTINGS_OFFSET 0x4 ++#define BUSFREQ_INFO_DLL_OFF_OFFSET 0x8 ++#define BUSFREQ_INFO_IOMUX_OFFSETS_OFFSET 0xc ++#define BUSFREQ_INFO_MU_DELAY_OFFSET 0x10 ++ ++.extern iram_tlb_phys_addr ++ ++ .align 3 ++ ++ .macro do_delay ++ ++1: ++ ldr r9, =0 ++2: ++ ldr r10, [r4, r9] ++ add r9, r9, #4 ++ cmp r9, #16 ++ bne 2b ++ sub r8, r8, #1 ++ cmp r8, #0 ++ bgt 1b ++ ++ .endm ++ ++ .macro wait_for_ccm_handshake ++ ++3: ++ ldr r8, [r5, #CCM_CDHIPR] ++ cmp r8, #0 ++ bne 3b ++ ++ .endm ++ ++ .macro switch_to_400MHz ++ ++ /* check whether periph2_clk is already from top path */ ++ ldr r8, [r5, #CCM_CBCDR] ++ ands r8, #(1 << 26) ++ beq skip_periph2_clk2_switch_400m ++ ++ /* now switch periph2_clk back. */ ++ ldr r8, [r5, #CCM_CBCDR] ++ bic r8, r8, #(1 << 26) ++ str r8, [r5, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ /* ++ * on i.MX6SX, pre_periph2_clk will be always from ++ * pll2_pfd2, so no need to set pre_periph2_clk ++ * parent, just set the mmdc divider directly. ++ */ ++skip_periph2_clk2_switch_400m: ++ ++ /* fabric_mmdc_podf to 0 */ ++ ldr r8, [r5, #CCM_CBCDR] ++ bic r8, r8, #(0x7 << 3) ++ str r8, [r5, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ .endm ++ ++ .macro switch_to_50MHz ++ ++ /* check whether periph2_clk is already from top path */ ++ ldr r8, [r5, #CCM_CBCDR] ++ ands r8, #(1 << 26) ++ beq skip_periph2_clk2_switch_50m ++ ++ /* now switch periph2_clk back. */ ++ ldr r8, [r5, #CCM_CBCDR] ++ bic r8, r8, #(1 << 26) ++ str r8, [r5, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ /* ++ * on i.MX6SX, pre_periph2_clk will be always from ++ * pll2_pfd2, so no need to set pre_periph2_clk ++ * parent, just set the mmdc divider directly. ++ */ ++skip_periph2_clk2_switch_50m: ++ ++ /* fabric_mmdc_podf to 7 so that mmdc is 400 / 8 = 50MHz */ ++ ldr r8, [r5, #CCM_CBCDR] ++ orr r8, r8, #(0x7 << 3) ++ str r8, [r5, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ .endm ++ ++ .macro switch_to_24MHz ++ ++ /* periph2_clk2 sel to OSC_CLK */ ++ ldr r8, [r5, #CCM_CBCMR] ++ orr r8, r8, #(1 << 20) ++ str r8, [r5, #CCM_CBCMR] ++ ++ /* periph2_clk2_podf to 0 */ ++ ldr r8, [r5, #CCM_CBCDR] ++ bic r8, r8, #0x7 ++ str r8, [r5, #CCM_CBCDR] ++ ++ /* periph2_clk sel to periph2_clk2 */ ++ ldr r8, [r5, #CCM_CBCDR] ++ orr r8, r8, #(0x1 << 26) ++ str r8, [r5, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ /* fabric_mmdc_podf to 0 */ ++ ldr r8, [r5, #CCM_CBCDR] ++ bic r8, r8, #(0x7 << 3) ++ str r8, [r5, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ .endm ++ ++/* ++ * imx6sx_ddr3_freq_change ++ * ++ * idle the processor (eg, wait for interrupt). ++ * make sure DDR is in self-refresh. ++ * IRQs are already disabled. ++ */ ++ENTRY(imx6sx_ddr3_freq_change) ++ ++imx6sx_ddr3_freq_change_start: ++ stmfd sp!, {r4 - r11} ++ ++ ldr r1, [r0, #BUSFREQ_INFO_DDR_SETTINGS_OFFSET] ++ ldr r2, [r0, #BUSFREQ_INFO_DLL_OFF_OFFSET] ++ ldr r3, [r0, #BUSFREQ_INFO_IOMUX_OFFSETS_OFFSET] ++ ++ /* ++ * To ensure no page table walks occur in DDR, we ++ * have a another page table stored in IRAM that only ++ * contains entries pointing to IRAM, AIPS1 and AIPS2. ++ * We need to set the TTBR1 to the new IRAM TLB. ++ * Do the following steps: ++ * 1. Flush the Branch Target Address Cache (BTAC) ++ * 2. Set TTBR1 to point to IRAM page table. ++ * 3. Disable page table walks in TTBR0 (PD0 = 1) ++ * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 ++ * and 2-4G is translated by TTBR1. ++ */ ++ ++ ldr r6, =iram_tlb_phys_addr ++ ldr r7, [r6] ++ ++ /* Disable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ dsb ++ isb ++ ++ /* Store the IRAM table in TTBR1 */ ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ /* Read TTBCR and set PD0=1, N = 1 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ orr r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ /* Disable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ ldr r4, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) ++ ldr r5, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) ++ ldr r6, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR) ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* ++ * make sure the L2 buffers are drained, ++ * sync operation on L2 drains the buffers. ++ */ ++ ldr r8, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ ++ /* Wait for background operations to complete. */ ++wait_for_l2_to_idle: ++ ldr r7, [r8, #0x730] ++ cmp r7, #0x0 ++ bne wait_for_l2_to_idle ++ ++ mov r7, #0x0 ++ str r7, [r8, #L2_CACHE_SYNC] ++ ++ /* Disable L2. */ ++ mov r7, #0x0 ++ str r7, [r8, #0x100] ++ ++ /* ++ * The second dsb might be needed to keep cache sync (device write) ++ * ordering with the memory accesses before it. ++ */ ++ dsb ++ isb ++#endif ++ ++ /* disable automatic power saving. */ ++ ldr r8, [r4, #MMDC0_MAPSR] ++ orr r8, r8, #0x1 ++ str r8, [r4, #MMDC0_MAPSR] ++ ++ /* disable MMDC power down timer. */ ++ ldr r8, [r4, #MMDC0_MDPDC] ++ bic r8, r8, #(0xff << 8) ++ str r8, [r4, #MMDC0_MDPDC] ++ ++ /* delay for a while */ ++ ldr r8, =4 ++ do_delay ++ ++ /* set CON_REG */ ++ ldr r8, =0x8000 ++ str r8, [r4, #MMDC0_MDSCR] ++poll_conreq_set_1: ++ ldr r8, [r4, #MMDC0_MDSCR] ++ and r8, r8, #(0x4 << 12) ++ cmp r8, #(0x4 << 12) ++ bne poll_conreq_set_1 ++ ++ /* ++ * if requested frequency is greater than ++ * 300MHz go to DLL on mode. ++ */ ++ ldr r8, [r0, #BUSFREQ_INFO_FREQ_OFFSET] ++ ldr r9, =300000000 ++ cmp r8, r9 ++ bge dll_on_mode ++ ++dll_off_mode: ++ /* if DLL is currently on, turn it off. */ ++ cmp r2, #1 ++ beq continue_dll_off_1 ++ ++ ldr r8, =0x00018031 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x00018039 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =10 ++ do_delay ++ ++continue_dll_off_1: ++ /* set DVFS - enter self refresh mode */ ++ ldr r8, [r4, #MMDC0_MAPSR] ++ orr r8, r8, #(1 << 21) ++ str r8, [r4, #MMDC0_MAPSR] ++ ++ /* de-assert con_req */ ++ mov r8, #0x0 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++poll_dvfs_set_1: ++ ldr r8, [r4, #MMDC0_MAPSR] ++ and r8, r8, #(1 << 25) ++ cmp r8, #(1 << 25) ++ bne poll_dvfs_set_1 ++ ++ ldr r8, [r0, #BUSFREQ_INFO_FREQ_OFFSET] ++ ldr r9, =24000000 ++ cmp r8, r9 ++ 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 r8, [r4, #MMDC0_MADPCR0] ++ orr r8, r8, #(1 << 8) ++ str r8, [r4, #MMDC0_MADPCR0] ++ ++ /* clear DVFS - exit from self refresh mode */ ++ ldr r8, [r4, #MMDC0_MAPSR] ++ bic r8, r8, #(1 << 21) ++ str r8, [r4, #MMDC0_MAPSR] ++ ++poll_dvfs_clear_1: ++ ldr r8, [r4, #MMDC0_MAPSR] ++ and r8, r8, #(1 << 25) ++ cmp r8, #(1 << 25) ++ beq poll_dvfs_clear_1 ++ ++ /* if DLL was previously on, continue DLL off routine. */ ++ cmp r2, #1 ++ beq continue_dll_off_3 ++ ++ ldr r8, =0x00018031 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x00018039 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x04208030 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x04208038 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x00088032 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x0008803A ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ /* delay for a while. */ ++ ldr r8, =4 ++ do_delay ++ ++ ldr r8, [r4, #MMDC0_MDCF0] ++ bic r8, r8, #0xf ++ orr r8, r8, #0x3 ++ str r8, [r4, #MMDC0_MDCF0] ++ ++ ldr r8, [r4, #MMDC0_MDCF1] ++ bic r8, r8, #0x7 ++ orr r8, r8, #0x4 ++ str r8, [r4, #MMDC0_MDCF1] ++ ++ ldr r8, =0x00091680 ++ str r8, [r4, #MMDC0_MDMISC] ++ ++ /* enable dqs pull down in the IOMUX. */ ++ ldr r8, [r3] ++ add r3, r3, #8 ++ ldr r9, =0x3028 ++update_iomux: ++ ldr r10, [r3] ++ ldr r11, [r6, r10] ++ bic r11, r11, r9 ++ orr r11, r11, #(0x3 << 12) ++ orr r11, r11, #0x28 ++ str r11, [r6, r10] ++ add r3, r3, #8 ++ sub r8, r8, #1 ++ cmp r8, #0 ++ bgt update_iomux ++ ++ /* ODT disabled. */ ++ ldr r8, =0x0 ++ str r8, [r4, #MMDC0_MPODTCTRL] ++ ++ /* DQS gating disabled. */ ++ ldr r8, [r4, #MMDC0_MPDGCTRL0] ++ orr r8, r8, #(1 << 29) ++ str r8, [r4, #MMDC0_MPDGCTRL0] ++ ++ /* Add workaround for ERR005778.*/ ++ /* double the original MU_UNIT_DEL_NUM. */ ++ ldr r8, [r0, #BUSFREQ_INFO_MU_DELAY_OFFSET] ++ lsl r8, r8, #1 ++ ++ /* Bypass the automatic MU by setting the mu_byp_en */ ++ ldr r10, [r4, #MMDC0_MPMUR0] ++ orr r10, r10, #0x400 ++ /* Set the MU_BYP_VAL */ ++ orr r10, r10, r8 ++ str r10, [r4, #MMDC0_MPMUR0] ++ ++ /* Now perform a force measure */ ++ ldr r8, [r4, #MMDC0_MPMUR0] ++ orr r8, r8, #0x800 ++ str r8, [r4, #MMDC0_MPMUR0] ++ /* Wait for FRC_MSR to clear. */ ++1: ++ ldr r8, [r4, #MMDC0_MPMUR0] ++ and r8, r8, #0x800 ++ cmp r8, #0x0 ++ bne 1b ++ ++continue_dll_off_3: ++ /* clear SBS - unblock accesses to DDR. */ ++ ldr r8, [r4, #MMDC0_MADPCR0] ++ bic r8, r8, #(0x1 << 8) ++ str r8, [r4, #MMDC0_MADPCR0] ++ ++ mov r8, #0x0 ++ str r8, [r4, #MMDC0_MDSCR] ++poll_conreq_clear_1: ++ ldr r8, [r4, #MMDC0_MDSCR] ++ and r8, r8, #(0x4 << 12) ++ cmp r8, #(0x4 << 12) ++ beq poll_conreq_clear_1 ++ ++ b done ++ ++dll_on_mode: ++ /* assert DVFS - enter self refresh mode. */ ++ ldr r8, [r4, #MMDC0_MAPSR] ++ orr r8, r8, #(1 << 21) ++ str r8, [r4, #MMDC0_MAPSR] ++ ++ /* de-assert CON_REQ. */ ++ mov r8, #0x0 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ /* poll DVFS ack. */ ++poll_dvfs_set_2: ++ ldr r8, [r4, #MMDC0_MAPSR] ++ and r8, r8, #(1 << 25) ++ cmp r8, #(1 << 25) ++ bne poll_dvfs_set_2 ++ ++ switch_to_400MHz ++ ++ /* set SBS step-by-step mode. */ ++ ldr r8, [r4, #MMDC0_MADPCR0] ++ orr r8, r8, #(1 << 8) ++ str r8, [r4, #MMDC0_MADPCR0] ++ ++ /* clear DVFS - exit self refresh mode. */ ++ ldr r8, [r4, #MMDC0_MAPSR] ++ bic r8, r8, #(1 << 21) ++ str r8, [r4, #MMDC0_MAPSR] ++ ++poll_dvfs_clear_2: ++ ldr r8, [r4, #MMDC0_MAPSR] ++ ands r8, r8, #(1 << 25) ++ bne poll_dvfs_clear_2 ++ ++ /* if DLL is currently off, turn it back on. */ ++ cmp r2, #0 ++ beq update_calibration_only ++ ++ ldr r8, =0xa5390003 ++ str r8, [r4, #MMDC0_MPZQHWCTRL] ++ ++ /* enable DQS gating. */ ++ ldr r10, =MMDC0_MPDGCTRL0 ++ ldr r8, [r4, r10] ++ bic r8, r8, #(1 << 29) ++ str r8, [r4, r10] ++ ++ /* Now perform a force measure */ ++ ldr r8, =0x00000800 ++ str r8, [r4, #MMDC0_MPMUR0] ++ /* Wait for FRC_MSR to clear. */ ++1: ++ ldr r8, [r4, #MMDC0_MPMUR0] ++ and r8, r8, #0x800 ++ cmp r8, #0x0 ++ bne 1b ++ ++ /* disable dqs pull down in the IOMUX. */ ++ ldr r8, [r3] ++ add r3, r3, #8 ++update_iomux1: ++ ldr r10, [r3, #0x0] ++ ldr r11, [r3, #0x4] ++ str r11, [r6, r10] ++ add r3, r3, #8 ++ sub r8, r8, #1 ++ cmp r8, #0 ++ bgt update_iomux1 ++ ++ /* config MMDC timings to 400MHz. */ ++ ldr r1, [r0, #BUSFREQ_INFO_DDR_SETTINGS_OFFSET] ++ ldr r7, [r1] ++ add r1, r1, #8 ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ ++ /* update MISC register: WALAT, RALAT */ ++ ldr r8, =0x00081740 ++ str r8, [r4, #MMDC0_MDMISC] ++ ++ /* configure ddr devices to dll on, odt. */ ++ ldr r8, =0x00028031 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x00028039 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ /* delay for while. */ ++ ldr r8, =4 ++ do_delay ++ ++ /* reset dll. */ ++ ldr r8, =0x09208030 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x09208038 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ /* delay for while. */ ++ ldr r8, =100 ++ do_delay ++ ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ ++ ldr r8, =0x00428031 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x00428039 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ ++ /* issue a zq command. */ ++ ldr r8, =0x04008040 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ ldr r8, =0x04008048 ++ str r8, [r4, #MMDC0_MDSCR] ++ ++ /* MMDC ODT enable. */ ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ ++ /* delay for while. */ ++ ldr r8, =40 ++ do_delay ++ ++ /* enable MMDC power down timer. */ ++ ldr r8, [r4, #MMDC0_MDPDC] ++ orr r8, r8, #(0x55 << 8) ++ str r8, [r4, #MMDC0_MDPDC] ++ ++ b update_calibration ++ ++update_calibration_only: ++ ldr r8, [r1] ++ sub r8, r8, #7 ++ add r1, r1, #64 ++ b update_calib ++ ++update_calibration: ++ /* write the new calibration values. */ ++ mov r8, r7 ++ sub r8, r8, #7 ++ ++update_calib: ++ ldr r10, [r1, #0x0] ++ ldr r11, [r1, #0x4] ++ str r11, [r4, r10] ++ add r1, r1, #8 ++ sub r8, r8, #1 ++ cmp r8, #0 ++ bgt update_calib ++ ++ /* perform a force measurement. */ ++ ldr r8, =0x800 ++ str r8, [r4, #MMDC0_MPMUR0] ++ /* Wait for FRC_MSR to clear. */ ++1: ++ ldr r8, [r4, #MMDC0_MPMUR0] ++ and r8, r8, #0x800 ++ cmp r8, #0x0 ++ bne 1b ++ ++ /* clear SBS - unblock DDR accesses. */ ++ ldr r8, [r4, #MMDC0_MADPCR0] ++ bic r8, r8, #(1 << 8) ++ str r8, [r4, #MMDC0_MADPCR0] ++ ++ mov r8, #0x0 ++ str r8, [r4, #MMDC0_MDSCR] ++poll_conreq_clear_2: ++ ldr r8, [r4, #MMDC0_MDSCR] ++ and r8, r8, #(0x4 << 12) ++ cmp r8, #(0x4 << 12) ++ beq poll_conreq_clear_2 ++ ++done: ++ ++ /* MMDC0_MAPSR adopt power down enable. */ ++ ldr r8, [r4, #MMDC0_MAPSR] ++ bic r8, r8, #0x01 ++ str r8, [r4, #MMDC0_MAPSR] ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* Enable L2. */ ++ ldr r8, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ ldr r7, =0x1 ++ str r7, [r8, #0x100] ++#endif ++ ++ /* Enable L1 data cache. */ ++ mrc p15, 0, r7, c1, c0, 0 ++ orr r7, r7, #0x4 ++ mcr p15, 0, r7, c1, c0, 0 ++ ++ /* Restore the TTBCR */ ++ dsb ++ isb ++ ++ /* Read TTBCR and set PD0=0, N = 0 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ bic r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ /* Enable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r7, c1, c0, 0 ++ orr r7, r7, #0x800 ++ mcr p15, 0, r7, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r7, =0x0 ++ mcr p15, 0, r7, c7, c1, 6 ++ ++ /* restore registers */ ++ ldmfd sp!, {r4 - r11} ++ mov pc, lr ++ ++ /* ++ * Add ltorg here to ensure that all ++ * literals are stored here and are ++ * within the text space. ++ */ ++ .ltorg ++imx6sx_ddr3_freq_change_end: ++ENDPROC(imx6sx_ddr3_freq_change) +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/gpc.c linux-3.14.72/arch/arm/mach-imx/gpc.c +--- linux-3.14.72.orig/arch/arm/mach-imx/gpc.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/gpc.c 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011-2013 Freescale Semiconductor, Inc. ++ * Copyright 2011-2015 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -10,30 +10,162 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include ++#include + #include + #include + #include + #include + #include ++#include ++#include ++#include + #include + #include "common.h" ++#include "hardware.h" + ++#define GPC_CNTR 0x000 ++#define GPC_CNTR_PCIE_PHY_PDU_SHIFT 0x7 ++#define GPC_CNTR_PCIE_PHY_PDN_SHIFT 0x6 ++#define PGC_PCIE_PHY_CTRL 0x200 ++#define PGC_PCIE_PHY_PDN_EN 0x1 + #define GPC_IMR1 0x008 ++#define GPC_PGC_MF_PDN 0x220 ++#define GPC_PGC_GPU_PDN 0x260 ++#define GPC_PGC_GPU_PUPSCR 0x264 ++#define GPC_PGC_GPU_PDNSCR 0x268 + #define GPC_PGC_CPU_PDN 0x2a0 ++#define GPC_PGC_DISP_PGCR_OFFSET 0x240 ++#define GPC_PGC_DISP_PUPSCR_OFFSET 0x244 ++#define GPC_PGC_DISP_PDNSCR_OFFSET 0x248 ++#define GPC_PGC_DISP_SR_OFFSET 0x24c ++#define GPC_M4_LPSR 0x2c ++#define GPC_M4_LPSR_M4_SLEEPING_SHIFT 4 ++#define GPC_M4_LPSR_M4_SLEEPING_MASK 0x1 ++#define GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK 0x1 ++#define GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT 0 ++#define GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_MASK 0x1 ++#define GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_SHIFT 1 + + #define IMR_NUM 4 + ++#define GPU_VPU_PUP_REQ BIT(1) ++#define GPU_VPU_PDN_REQ BIT(0) ++ ++#define GPC_CLK_MAX 10 ++ ++struct pu_domain { ++ struct generic_pm_domain base; ++ struct regulator *reg; ++ struct clk *clk[GPC_CLK_MAX]; ++ int num_clks; ++}; ++ ++struct disp_domain { ++ struct generic_pm_domain base; ++ struct clk *clk[GPC_CLK_MAX]; ++ int num_clks; ++}; ++ + static void __iomem *gpc_base; ++static u32 gpc_mf_irqs[IMR_NUM]; + static u32 gpc_wake_irqs[IMR_NUM]; + static u32 gpc_saved_imrs[IMR_NUM]; ++static u32 gpc_mf_request_on[IMR_NUM]; ++static u32 bypass; ++static DEFINE_SPINLOCK(gpc_lock); ++static struct notifier_block nb_pcie; ++ ++void imx_gpc_add_m4_wake_up_irq(u32 irq, bool enable) ++{ ++ unsigned int idx = irq / 32 - 1; ++ unsigned long flags; ++ u32 mask; ++ ++ /* Sanity check for SPI irq */ ++ if (irq < 32) ++ return; ++ ++ mask = 1 << irq % 32; ++ spin_lock_irqsave(&gpc_lock, flags); ++ gpc_wake_irqs[idx] = enable ? gpc_wake_irqs[idx] | mask : ++ gpc_wake_irqs[idx] & ~mask; ++ spin_unlock_irqrestore(&gpc_lock, flags); ++} ++ ++void imx_gpc_hold_m4_in_sleep(void) ++{ ++ int val; ++ unsigned long timeout = jiffies + msecs_to_jiffies(500); ++ ++ /* wait M4 in wfi before asserting hold request */ ++ while (!imx_gpc_is_m4_sleeping()) ++ if (time_after(jiffies, timeout)) ++ pr_err("M4 is NOT in expected sleep!\n"); ++ ++ val = readl_relaxed(gpc_base + GPC_M4_LPSR); ++ val &= ~(GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK << ++ GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT); ++ writel_relaxed(val, gpc_base + GPC_M4_LPSR); ++ ++ timeout = jiffies + msecs_to_jiffies(500); ++ while (readl_relaxed(gpc_base + GPC_M4_LPSR) ++ & (GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_MASK << ++ GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_SHIFT)) ++ if (time_after(jiffies, timeout)) ++ pr_err("Wait M4 hold ack timeout!\n"); ++} + +-void imx_gpc_pre_suspend(void) ++void imx_gpc_release_m4_in_sleep(void) ++{ ++ int val; ++ ++ val = readl_relaxed(gpc_base + GPC_M4_LPSR); ++ val |= GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK << ++ GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT; ++ writel_relaxed(val, gpc_base + GPC_M4_LPSR); ++} ++ ++unsigned int imx_gpc_is_m4_sleeping(void) ++{ ++ if (readl_relaxed(gpc_base + GPC_M4_LPSR) & ++ (GPC_M4_LPSR_M4_SLEEPING_MASK << ++ GPC_M4_LPSR_M4_SLEEPING_SHIFT)) ++ return 1; ++ ++ return 0; ++} ++ ++unsigned int imx_gpc_is_mf_mix_off(void) ++{ ++ return readl_relaxed(gpc_base + GPC_PGC_MF_PDN); ++} ++ ++static void imx_gpc_mf_mix_off(void) ++{ ++ int i; ++ ++ for (i = 0; i < IMR_NUM; i++) ++ if (((gpc_wake_irqs[i] | gpc_mf_request_on[i]) & ++ gpc_mf_irqs[i]) != 0) ++ return; ++ ++ pr_info("Turn off M/F mix!\n"); ++ /* turn off mega/fast mix */ ++ writel_relaxed(0x1, gpc_base + GPC_PGC_MF_PDN); ++} ++ ++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 (cpu_is_imx6sx() && arm_power_off) ++ imx_gpc_mf_mix_off(); ++ ++ if (arm_power_off) ++ 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); +@@ -48,6 +180,9 @@ + + /* Keep ARM core powered on for other low-power modes */ + writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN); ++ /* Keep M/F mix powered on for other low-power modes */ ++ if (cpu_is_imx6sx()) ++ writel_relaxed(0x0, gpc_base + GPC_PGC_MF_PDN); + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); +@@ -56,6 +191,7 @@ + static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) + { + unsigned int idx = d->irq / 32 - 1; ++ unsigned long flags; + u32 mask; + + /* Sanity check for SPI irq */ +@@ -63,8 +199,10 @@ + return -EINVAL; + + mask = 1 << d->irq % 32; ++ spin_lock_irqsave(&gpc_lock, flags); + gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask : + gpc_wake_irqs[idx] & ~mask; ++ spin_unlock_irqrestore(&gpc_lock, flags); + + return 0; + } +@@ -120,6 +258,46 @@ + writel_relaxed(val, reg); + } + ++static int imx_pcie_regulator_notify(struct notifier_block *nb, ++ unsigned long event, ++ void *ignored) ++{ ++ u32 value = readl_relaxed(gpc_base + GPC_CNTR); ++ ++ switch (event) { ++ case REGULATOR_EVENT_PRE_ENABLE: ++ value |= 1 << GPC_CNTR_PCIE_PHY_PDU_SHIFT; ++ writel_relaxed(value, gpc_base + GPC_CNTR); ++ break; ++ case REGULATOR_EVENT_PRE_DISABLE: ++ value |= 1 << GPC_CNTR_PCIE_PHY_PDN_SHIFT; ++ writel_relaxed(value, gpc_base + GPC_CNTR); ++ writel_relaxed(PGC_PCIE_PHY_PDN_EN, ++ gpc_base + PGC_PCIE_PHY_CTRL); ++ break; ++ default: ++ break; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++int imx_gpc_mf_request_on(unsigned int irq, unsigned int on) ++{ ++ unsigned int idx = irq / 32 - 1; ++ unsigned long flags; ++ u32 mask; ++ ++ mask = 1 << (irq % 32); ++ spin_lock_irqsave(&gpc_lock, flags); ++ gpc_mf_request_on[idx] = on ? gpc_mf_request_on[idx] | mask : ++ gpc_mf_request_on[idx] & ~mask; ++ spin_unlock_irqrestore(&gpc_lock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(imx_gpc_mf_request_on); ++ + void __init imx_gpc_init(void) + { + struct device_node *np; +@@ -133,8 +311,307 @@ + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4); + ++ /* Read supported wakeup source in M/F domain */ ++ if (cpu_is_imx6sx()) { ++ of_property_read_u32_index(np, "fsl,mf-mix-wakeup-irq", 0, ++ &gpc_mf_irqs[0]); ++ of_property_read_u32_index(np, "fsl,mf-mix-wakeup-irq", 1, ++ &gpc_mf_irqs[1]); ++ of_property_read_u32_index(np, "fsl,mf-mix-wakeup-irq", 2, ++ &gpc_mf_irqs[2]); ++ of_property_read_u32_index(np, "fsl,mf-mix-wakeup-irq", 3, ++ &gpc_mf_irqs[3]); ++ if (!(gpc_mf_irqs[0] | gpc_mf_irqs[1] | ++ gpc_mf_irqs[2] | gpc_mf_irqs[3])) ++ pr_info("No wakeup source in Mega/Fast domain found!\n"); ++ } ++ + /* Register GPC as the secondary interrupt controller behind GIC */ + 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; + } ++ ++#ifdef CONFIG_PM ++ ++static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) ++{ ++ struct pu_domain *pu = container_of(genpd, struct pu_domain, base); ++ int iso, iso2sw; ++ u32 val; ++ ++ /* Read ISO and ISO2SW power down delays */ ++ val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR); ++ iso = val & 0x3f; ++ iso2sw = (val >> 8) & 0x3f; ++ ++ /* Gate off PU domain when GPU/VPU when powered down */ ++ writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); ++ ++ /* Request GPC to power down GPU/VPU */ ++ val = readl_relaxed(gpc_base + GPC_CNTR); ++ val |= GPU_VPU_PDN_REQ; ++ writel_relaxed(val, gpc_base + GPC_CNTR); ++ ++ /* Wait ISO + ISO2SW IPG clock cycles */ ++ ndelay((iso + iso2sw) * 1000 / 66); ++ ++ if (pu->reg) ++ regulator_disable(pu->reg); ++ ++ return 0; ++} ++ ++static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd) ++{ ++ struct pu_domain *pu = container_of(genpd, struct pu_domain, base); ++ int i, ret, sw, sw2iso; ++ u32 val; ++ ++ if (pu->reg) { ++ ret = regulator_enable(pu->reg); ++ if (ret) { ++ pr_err("%s: failed to enable regulator: %d\n", __func__, ret); ++ return ret; ++ } ++ } ++ /* Enable reset clocks for all devices in the PU domain */ ++ for (i = 0; i < pu->num_clks; i++) ++ clk_prepare_enable(pu->clk[i]); ++ ++ /* Gate off PU domain when GPU/VPU when powered down */ ++ writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); ++ ++ /* Read ISO and ISO2SW power down delays */ ++ val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR); ++ sw = val & 0x3f; ++ sw2iso = (val >> 8) & 0x3f; ++ ++ /* Request GPC to power up GPU/VPU */ ++ val = readl_relaxed(gpc_base + GPC_CNTR); ++ val |= GPU_VPU_PUP_REQ; ++ writel_relaxed(val, gpc_base + GPC_CNTR); ++ ++ /* Wait ISO + ISO2SW IPG clock cycles */ ++ ndelay((sw + sw2iso) * 1000 / 66); ++ ++ /* Disable reset clocks for all devices in the PU domain */ ++ for (i = 0; i < pu->num_clks; i++) ++ clk_disable_unprepare(pu->clk[i]); ++ ++ return 0; ++} ++ ++static int imx_pm_dispmix_on(struct generic_pm_domain *genpd) ++{ ++ struct disp_domain *disp = container_of(genpd, struct disp_domain, base); ++ u32 val = readl_relaxed(gpc_base + GPC_CNTR); ++ int i; ++ ++ if ((cpu_is_imx6sl() && ++ imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2) || cpu_is_imx6sx()) { ++ ++ /* Enable reset clocks for all devices in the disp domain */ ++ for (i = 0; i < disp->num_clks; i++) ++ clk_prepare_enable(disp->clk[i]); ++ ++ writel_relaxed(0x0, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); ++ writel_relaxed(0x20 | val, gpc_base + GPC_CNTR); ++ while (readl_relaxed(gpc_base + GPC_CNTR) & 0x20) ++ ; ++ ++ writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET); ++ ++ /* Disable reset clocks for all devices in the disp domain */ ++ for (i = 0; i < disp->num_clks; i++) ++ clk_disable_unprepare(disp->clk[i]); ++ } ++ return 0; ++} ++ ++static int imx_pm_dispmix_off(struct generic_pm_domain *genpd) ++{ ++ struct disp_domain *disp = container_of(genpd, struct disp_domain, base); ++ u32 val = readl_relaxed(gpc_base + GPC_CNTR); ++ int i; ++ ++ if ((cpu_is_imx6sl() && ++ imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2) || cpu_is_imx6sx()) { ++ ++ /* Enable reset clocks for all devices in the disp domain */ ++ for (i = 0; i < disp->num_clks; i++) ++ clk_prepare_enable(disp->clk[i]); ++ ++ writel_relaxed(0xFFFFFFFF, ++ gpc_base + GPC_PGC_DISP_PUPSCR_OFFSET); ++ writel_relaxed(0xFFFFFFFF, ++ gpc_base + GPC_PGC_DISP_PDNSCR_OFFSET); ++ writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); ++ writel_relaxed(0x10 | val, gpc_base + GPC_CNTR); ++ while (readl_relaxed(gpc_base + GPC_CNTR) & 0x10) ++ ; ++ ++ /* Disable reset clocks for all devices in the disp domain */ ++ for (i = 0; i < disp->num_clks; i++) ++ clk_disable_unprepare(disp->clk[i]); ++ } ++ return 0; ++} ++ ++static struct generic_pm_domain imx6q_arm_domain = { ++ .name = "ARM", ++}; ++ ++static struct pu_domain imx6q_pu_domain = { ++ .base = { ++ .name = "PU", ++ .power_off = imx6q_pm_pu_power_off, ++ .power_on = imx6q_pm_pu_power_on, ++ .power_off_latency_ns = 25000, ++ .power_on_latency_ns = 2000000, ++ }, ++}; ++ ++static struct disp_domain imx6s_display_domain = { ++ .base = { ++ .name = "DISPLAY", ++ .power_off = imx_pm_dispmix_off, ++ .power_on = imx_pm_dispmix_on, ++ }, ++}; ++ ++static struct generic_pm_domain *imx_gpc_domains[] = { ++ &imx6q_arm_domain, ++ &imx6q_pu_domain.base, ++ &imx6s_display_domain.base, ++}; ++ ++static struct genpd_onecell_data imx_gpc_onecell_data = { ++ .domains = imx_gpc_domains, ++ .num_domains = ARRAY_SIZE(imx_gpc_domains), ++}; ++ ++static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) ++{ ++ struct clk *clk; ++ bool is_off; ++ int pu_clks, disp_clks; ++ int i = 0, k = 0; ++ ++ imx6q_pu_domain.base.of_node = dev->of_node; ++ imx6q_pu_domain.reg = pu_reg; ++ ++ imx6s_display_domain.base.of_node = dev->of_node; ++ ++ if ((cpu_is_imx6sl() && ++ imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2)) { ++ pu_clks = 2 ; ++ disp_clks = 6; ++ } else if (cpu_is_imx6sx()) { ++ pu_clks = 1; ++ disp_clks = 8; ++ } else { ++ pu_clks = GPC_CLK_MAX; ++ disp_clks = 0; ++ } ++ ++ /* Get pu domain clks */ ++ for (i = 0; i < pu_clks ; i++) { ++ clk = of_clk_get(dev->of_node, i); ++ if (IS_ERR(clk)) ++ break; ++ imx6q_pu_domain.clk[i] = clk; ++ } ++ imx6q_pu_domain.num_clks = i; ++ ++ /* Get disp domain clks */ ++ for (k = 0, i = pu_clks; i < pu_clks + disp_clks ; i++, k++) { ++ clk = of_clk_get(dev->of_node, i); ++ if (IS_ERR(clk)) ++ break; ++ imx6s_display_domain.clk[k] = clk; ++ } ++ imx6s_display_domain.num_clks = k; ++ ++ is_off = IS_ENABLED(CONFIG_PM_RUNTIME); ++ if (is_off) ++ imx6q_pm_pu_power_off(&imx6q_pu_domain.base); ++ ++ pm_genpd_init(&imx6q_pu_domain.base, NULL, is_off); ++ pm_genpd_init(&imx6s_display_domain.base, NULL, is_off); ++ ++ return __of_genpd_add_provider(dev->of_node, __of_genpd_xlate_onecell, ++ &imx_gpc_onecell_data); ++ ++} ++ ++#else ++static inline int imx_gpc_genpd_init(struct device *dev, struct regulator *reg) ++{ ++ return 0; ++} ++#endif /* CONFIG_PM */ ++ ++static int imx_gpc_probe(struct platform_device *pdev) ++{ ++ struct regulator *pu_reg; ++ int ret; ++ ++ of_property_read_u32(pdev->dev.of_node, "fsl,ldo-bypass", &bypass); ++ pu_reg = devm_regulator_get(&pdev->dev, "pu"); ++ if (!IS_ERR(pu_reg)) { ++ /* The regulator is initially enabled */ ++ ret = regulator_enable(pu_reg); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to enable pu regulator: %d\n", ret); ++ return ret; ++ } ++ /* We only bypass pu since arm and soc has been set in u-boot */ ++ if (bypass) ++ regulator_allow_bypass(pu_reg, true); ++ } else { ++ pu_reg = NULL; ++ } ++ ++ if (cpu_is_imx6sx()) { ++ struct regulator *pcie_reg; ++ ++ pcie_reg = devm_regulator_get(&pdev->dev, "pcie-phy"); ++ if (IS_ERR(pcie_reg)) { ++ ret = PTR_ERR(pcie_reg); ++ dev_info(&pdev->dev, "pcie regulator not ready.\n"); ++ return ret; ++ } ++ nb_pcie.notifier_call = &imx_pcie_regulator_notify; ++ ++ ret = regulator_register_notifier(pcie_reg, &nb_pcie); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "pcie regulator notifier request failed\n"); ++ return ret; ++ } ++ } ++ ++ return imx_gpc_genpd_init(&pdev->dev, pu_reg); ++} ++ ++static struct of_device_id imx_gpc_dt_ids[] = { ++ { .compatible = "fsl,imx6q-gpc" }, ++ { .compatible = "fsl,imx6sl-gpc" }, ++ { } ++}; ++ ++static struct platform_driver imx_gpc_driver = { ++ .driver = { ++ .name = "imx-gpc", ++ .owner = THIS_MODULE, ++ .of_match_table = imx_gpc_dt_ids, ++ }, ++ .probe = imx_gpc_probe, ++}; ++ ++static int __init imx_pgc_init(void) ++{ ++ return platform_driver_register(&imx_gpc_driver); ++} ++subsys_initcall(imx_pgc_init); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/hardware.h linux-3.14.72/arch/arm/mach-imx/hardware.h +--- linux-3.14.72.orig/arch/arm/mach-imx/hardware.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/hardware.h 2016-06-19 22:11:55.049156848 +0200 +@@ -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) \ +@@ -87,17 +89,16 @@ + * AIPS1 0x53f00000+0x100000 -> 0xf5700000+0x100000 + * AIPS2 0x63f00000+0x100000 -> 0xf5300000+0x100000 + * mx6q: +- * SCU 0x00a00000+0x004000 -> 0xf4000000+0x004000 ++ * SCU 0x00a00000+0x004000 -> 0xf4a00000+0x004000 + * CCM 0x020c4000+0x004000 -> 0xf42c4000+0x004000 + * ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000 +- * UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000 ++ * UART4 0x021f0000+0x004000 -> 0xf43f0000+0x004000 + */ +-#define IMX_IO_P2V(x) ( \ +- (((x) & 0x80000000) >> 7) | \ +- (0xf4000000 + \ +- (((x) & 0x50000000) >> 6) + \ +- (((x) & 0x0b000000) >> 4) + \ +- (((x) & 0x000fffff)))) ++#define IMX_IO_P2V(x) ( \ ++ (0xf4000000 + \ ++ (((x) & 0x50000000) >> 4) + \ ++ (((x) & 0x0a000000) >> 4) + \ ++ (((x) & 0x00ffffff)))) + + #define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x)) + +@@ -113,6 +114,7 @@ + #include "mx27.h" + #include "mx1.h" + #include "mx25.h" ++#include "mx6.h" + + #define imx_map_entry(soc, name, _type) { \ + .virtual = soc ## _IO_P2V(soc ## _ ## name ## _BASE_ADDR), \ +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/headsmp.S linux-3.14.72/arch/arm/mach-imx/headsmp.S +--- linux-3.14.72.orig/arch/arm/mach-imx/headsmp.S 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/headsmp.S 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -14,8 +14,12 @@ + #include + #include + #include ++#include ++ ++#define SCU_CPU_STATUS 0x08 + + .section ".text.head", "ax" ++.extern imx_scu_base + + #ifdef CONFIG_SMP + diag_reg_offset: +@@ -32,6 +36,16 @@ + ENTRY(v7_secondary_startup) + bl v7_invalidate_l1 + set_diag_reg ++ ++ /* Set the CPU status in SCU CPU status register. */ ++ mrc p15, 0, r0, c0, c0, 5 ++ and r0, r0, #3 ++ mrc p15, 4, r1, c15, c0, 0 ++ ldr r2, =SCU_CPU_STATUS ++ orr r2, r2, r0 ++ ldr r0, =SCU_PM_NORMAL ++ strb r0, [r1, r2] ++ + b secondary_startup + ENDPROC(v7_secondary_startup) + #endif +@@ -51,6 +65,10 @@ + 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 ++ ldr r1, [r2, #L2X0_R_TAG_LATENCY] @ get tag latency value ++ str r1, [r0, #L2X0_TAG_LATENCY_CTRL] @ restore tag latency ++ ldr r1, [r2, #L2X0_R_DATA_LATENCY] @ get data latency value ++ str r1, [r0, #L2X0_DATA_LATENCY_CTRL] @ restore data latency + mov r1, #0x1 + str r1, [r0, #L2X0_CTRL] @ re-enable L2 + .endm +@@ -62,10 +80,4 @@ + .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.72.orig/arch/arm/mach-imx/hotplug.c linux-3.14.72/arch/arm/mach-imx/hotplug.c +--- linux-3.14.72.orig/arch/arm/mach-imx/hotplug.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/hotplug.c 2016-06-19 22:11:55.049156848 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -14,9 +14,12 @@ + #include + #include + #include ++#include + + #include "common.h" + ++extern void __iomem *imx_scu_base; ++ + static inline void cpu_enter_lowpower(void) + { + unsigned int v; +@@ -36,6 +39,8 @@ + : "=&r" (v) + : "r" (0), "Ir" (CR_C), "Ir" (0x40) + : "cc"); ++ ++ scu_power_mode(imx_scu_base, SCU_PM_DORMANT); + } + + /* +@@ -52,8 +57,7 @@ + * the register being cleared to kill the cpu. + */ + imx_set_cpu_arg(cpu, ~0); +- +- while (1) ++ for (;;) + cpu_do_idle(); + } + +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/imx6sl_lpm_wfi.S linux-3.14.72/arch/arm/mach-imx/imx6sl_lpm_wfi.S +--- linux-3.14.72.orig/arch/arm/mach-imx/imx6sl_lpm_wfi.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/imx6sl_lpm_wfi.S 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,777 @@ ++/* ++ * Copyright (C) 2015 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 teh hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++ ++#define PM_INFO_PM_INFO_SIZE_OFFSET 0x0 ++#define PM_INFO_TTBR_OFFSET 0x4 ++#define PM_INFO_MMDC_V_OFFSET 0x8 ++#define PM_INFO_IOMUXC_V_OFFSET 0xc ++#define PM_INFO_CCM_V_OFFSET 0x10 ++#define PM_INFO_L2_V_OFFSET 0x14 ++#define PM_INFO_ANATOP_V_OFFSET 0x18 ++#define PM_INFO_IO_NUM_OFFSET 0x1c ++#define PM_INFO_IO_VAL_OFFSET 0x20 ++ ++#define MX6Q_MMDC_MAPSR 0x404 ++#define MX6Q_MMDC_MPDGCTRL0 0x83c ++ ++.global mx6sl_lpm_wfi_start ++.global mx6sl_lpm_wfi_end ++ ++ .macro pll_do_wait_lock ++1: ++ ldr r7, [r10, r8] ++ ands r7, #0x80000000 ++ beq 1b ++ ++ .endm ++ ++ .macro ccm_do_wait ++2: ++ ldr r7, [r10, #0x48] ++ cmp r7, #0x0 ++ bne 2b ++ ++ .endm ++ ++ .macro ccm_enter_idle ++ ++ ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] ++ /* ++ * if in audio_bus_freq_mode, skip to ++ * audio_mode low power setting. ++ */ ++ cmp r1, #0x1 ++ 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, [r10, #0x14] ++ orr r6, r6, #0x07 ++ str r6, [r10, #0x14] ++ ++ /* Now set MMDC PODF to divide by 3. */ ++ ldr r6, [r10, #0x14] ++ bic r6, r6, #0x38 ++ orr r6, r6, #0x10 ++ str r6, [r10, #0x14] ++ ++ ccm_do_wait ++ ++ /* Set the AHB to 3MHz. AXI to 3MHz. */ ++ ldr r6, [r10, #0x14] ++ /*r12 stores the origin AHB podf value */ ++ mov r12, r6 ++ orr r6, r6, #0x1c00 ++ orr r6, r6, #0x70000 ++ str r6, [r10, #0x14] ++ ++ ccm_do_wait ++ ++ /* Now set ARM to 24MHz. ++ * Move ARM to be sourced from step_clk ++ * after setting step_clk to 24MHz. ++ */ ++ ldr r6, [r10, #0x0c] ++ bic r6, r6, #0x100 ++ str r6, [r10, #0xc] ++ /*Now pll1_sw_clk to step_clk */ ++ ldr r6, [r10, #0x0c] ++ orr r6, r6, #0x4 ++ str r6, [r10, #0x0c] ++ ++ /* Bypass PLL1 and power it down */ ++ ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] ++ ldr r6, =(1 << 16) ++ orr r6, r6, #0x1000 ++ str r6, [r10, #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 r10, [r0, #PM_INFO_CCM_V_OFFSET] ++ ldr r11, [r10, #0x10] ++ ldr r6, =0x07 ++ str r6, [r10, #0x10] ++ ++ ccm_do_wait ++ ++ b ccm_idle_done ++ ++audio_mode: ++ /* ++ * MMDC is sourced from pll2_200M. ++ * Set the mmdc_podf to div by 8 ++ */ ++ ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] ++ ldr r6, [r10, #0x14] ++ orr r6, r6, #0x38 ++ str r6, [r10, #0x14] ++ ++ ccm_do_wait ++ ++ /* ++ * ARM is sourced from pll2_pfd2_400M here. ++ * switch ARM to bypassed PLL1 ++ */ ++ ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] ++ ldr r6, [r10, #0x0c] ++ bic r6, r6, #0x4 ++ str r6, [r10, #0xc] ++ ++ /* ++ * set the arm_podf to divide by 3 ++ * as IPG is at 4MHz, we cannot run ++ * arm clk above 9.6MHz when system ++ * enter WAIT mode ++ */ ++ ldr r11, [r10, #0x10] ++ ldr r6, =0x2 ++ str r6, [r10, #0x10] ++ ++ ccm_do_wait ++ ++ccm_idle_done: ++ ++ .endm ++ ++ .macro ccm_exit_idle ++ ++ /* ++ * If in audio_bus_freq_mode, skip to ++ * audio_mode ccm restore. ++ */ ++ cmp r1, #0x1 ++ beq audio_ccm_restore ++ ++ ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] ++ /* Power up PLL1 and un-bypass it. */ ++ ldr r6, =(1 << 12) ++ str r6, [r10, #0x08] ++ ++ /* Wait for PLL1 to relock */ ++ ldr r8, =0x0 ++ pll_do_wait_lock ++ ++ ldr r6, =(1 << 16) ++ str r6, [r10, #0x08] ++ ++ ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] ++ /* Set PLL1_sw_clk back to PLL1 */ ++ ldr r6, [r10, #0x0c] ++ bic r6, r6, #0x4 ++ str r6, [r10, #0x0c] ++ ++ /* Restore AHB/AXI back */ ++ str r12, [r10, #0x14] ++ ++ ccm_do_wait ++ ++ /* restore mmdc back to 24MHz*/ ++ ldr r6, [r10, #0x14] ++ bic r6, r6, #0x3f ++ str r6, [r10, #0x14] ++ ++ ccm_do_wait ++ b ccm_exit_done ++ ++audio_ccm_restore: ++ /* move arm clk back to pll2_pfd2_400M */ ++ ldr r6, [r10, #0xc] ++ orr r6, r6, #0x4 ++ str r6, [r10, #0xc] ++ ++ /* restore mmdc podf */ ++ ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] ++ ldr r6, [r10, #0x14] ++ bic r6, r6, #0x38 ++ orr r6, #0x8 ++ str r6, [r10, #0x14] ++ ++ ccm_do_wait ++ ++ccm_exit_done: ++ ++ .endm ++ ++ .macro check_pll_state ++ ++ ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] ++ /* ++ * Check whether any PLL is enabled, as only when ++ * there is no PLLs enabled, 2p5 can be off and ++ * only enable the weak one. PLL1 will be powered ++ * down late, so no need to check PLL1 state. ++ */ ++ ++ /* sys PLL2 */ ++ ldr r6, [r10, #0x30] ++ ands r6, r6, #(1 << 31) ++ bne 1f ++ ++ /* usb PLL3 */ ++ ldr r6, [r10, #0x10] ++ ands r6, r6, #(1 << 31) ++ bne 1f ++ ++ /* audio PLL4 */ ++ ldr r6, [r10, #0x70] ++ ands r6, r6, #(1 << 31) ++ bne 1f ++ ++ /* video PLL5 */ ++ ldr r6, [r10, #0xa0] ++ ands r6, r6, #(1 << 31) ++ bne 1f ++ ++ /* enet PLL6 */ ++ ldr r6, [r10, #0xe0] ++ ands r6, r6, #(1 << 31) ++ bne 1f ++ ++ /* usb host PLL7 */ ++ ldr r6, [r10, #0x20] ++ ands r6, r6, #(1 << 31) ++ bne 1f ++ ++ ldr r4, =0x1 ++ b check_done ++1: ++ ldr r4, =0x0 ++ ++check_done: ++ .endm ++ ++ .macro anatop_enter_idle ++ ++ ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] ++ cmp r4, #0x0 ++ beq anatop_enter_done ++ ++ /* Disable 1p1 brown out. */ ++ ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] ++ ldr r6, [r10, #0x110] ++ bic r6, r6, #0x2 ++ str r6, [r10, #0x110] ++ /* ++ * Set the OSC bias current to -37.5% ++ * to drop the power on VDDHIGH. ++ */ ++ ldr r6, [r10, #0x150] ++ orr r6, r6, #0xc000 ++ str r6, [r10, #0x150] ++ ++ /* ++ * if the usb VBUS wakeup is enabled, skip ++ * disable main 2p5. ++ */ ++ cmp r2, #0x1 ++ beq anatop_enter_done ++ ++ /* Enable the week 2p5 */ ++ ldr r6, [r10, #0x130] ++ orr r6, r6, #0x40000 ++ str r6, [r10, #0x130] ++ ++ /* Disable main 2p5. */ ++ ldr r6, [r10, #0x130] ++ bic r6, r6, #0x1 ++ str r6, [r10, #0x130] ++ ++ /* ++ * Cannot diable regular bandgap ++ * in LDO-enable mode. The bandgap ++ * is required for ARM-LDO to regulate ++ * the voltage. ++ */ ++ ldr r6, [r10, #0x140] ++ and r6, r6, #0x1f ++ cmp r6, #0x1f ++ bne anatop_enter_done ++ ++ /* Enable low power bandgap */ ++ ldr r6, [r10, #0x260] ++ orr r6, r6, #0x20 ++ str r6, [r10, #0x260] ++ ++ /* ++ * Turn off the bias current ++ * from the regular bandgap. ++ */ ++ ldr r6, [r10, #0x260] ++ orr r6, r6, #0x80 ++ str r6, [r10, #0x260] ++ ++ /* ++ * Clear the REFTTOP+SELFBIASOFF, ++ * self_bais circuit of the band gap. ++ * Per RM, should be cleared when ++ * band gap is powered down. ++ */ ++ ldr r6, [r10, #0x150] ++ bic r6, r6, #0x8 ++ str r6, [r10, #0x150] ++ ++ /* Power down the regular bandgap */ ++ ldr r6, [r10, #0x150] ++ orr r6, r6, #0x1 ++ str r6, [r10, #0x150] ++anatop_enter_done: ++ ++ .endm ++ ++ .macro anatop_exit_idle ++ ++ ldr r10, [r0, #PM_INFO_ANATOP_V_OFFSET] ++ cmp r4, #0x0 ++ beq skip_anatop_restore ++ ++ cmp r2, #0x1 ++ beq ldo2p5_not_disabled ++ /* ++ * Regular bandgap will not be disabled ++ * in LDO-enabled mode as it is required ++ * for ARM-LDO to reguulate the voltage. ++ */ ++ ldr r6, [r10, #0x140] ++ and r6, r6, #0x1f ++ cmp r6, #0x1f ++ bne skip_bandgap_restore ++ ++ /* Power up the regular bandgap */ ++ ldr r6, [r10, #0x150] ++ bic r6, r6, #0x1 ++ str r6, [r10, #0x150] ++ ++ /* wait for bandgap stable */ ++3: ++ ldr r6, [r10, #0x150] ++ and r6, r6, #0x80 ++ cmp r6, #0x80 ++ bne 3b ++ ++ /* now disable bandgap self-bias circuit */ ++ ldr r6, [r10, #0x150] ++ orr r6, r6, #0x8 ++ str r6, [r10, #0x150] ++ ++ /* Turn on the bias current ++ * from the regular bandgap. ++ */ ++ ldr r6, [r10, #0x260] ++ bic r6, r6, #0x80 ++ str r6, [r10, #0x260] ++ ++ /* Disable the low power bandgap */ ++ ldr r6, [r10, #0x260] ++ bic r6, r6, #0x20 ++ str r6, [r10, #0x260] ++ ++skip_bandgap_restore: ++ /* Enable main 2p5. */ ++ ldr r6, [r10, #0x130] ++ orr r6, r6, #0x1 ++ str r6, [r10, #0x130] ++ ++ /* Ensure the 2p5 is up */ ++5: ++ ldr r6, [r10, #0x130] ++ and r6, r6, #0x20000 ++ cmp r6, #0x20000 ++ bne 5b ++ ++ /* Disable the weak 2p5 */ ++ ldr r6, [r10, #0x130] ++ bic r6, r6, #0x40000 ++ str r6, [r10, #0x130] ++ ++ldo2p5_not_disabled: ++ /* ++ * Set the OSC bias current to max ++ * value for normal operation. ++ */ ++ ldr r6, [r10, #0x150] ++ bic r6, r6, #0xc000 ++ str r6, [r10, #0x150] ++ ++ /* Enable 1p1 brown out, */ ++ ldr r6, [r10, #0x110] ++ orr r6, r6, #0x2 ++ str r6, [r10, #0x110] ++ ++skip_anatop_restore: ++ ++ .endm ++ ++ .macro disable_l1_dcache ++ ++ /* disable d-cache */ ++ mrc p15, 0, r7, c1, c0, 0 ++ bic r7, r7, #(1 << 2) ++ mcr p15, 0, r7, c1, c0, 0 ++ ++ dsb ++ isb ++ ++ .endm ++ ++ .macro mmdc_enter_dvfs_mode ++ ++ /* disable automatic power saving. */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #0x1 ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++ ++ /* disable power down timer */ ++ ldr r7, [r10, #0x04] ++ bic r7, r7, #0xff00 ++ str r7, [r10, #0x04] ++ ++ /* Make the DDR explicitly enter self-refresh. */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #(1 << 21) ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++ ++poll_dvfs_set: ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ beq poll_dvfs_set ++ ++ /* set SBS step-by step mode */ ++ ldr r7, [r10, #0x410] ++ orr r7, r7, #0x100 ++ str r7, [r10, #0x410] ++ ++ .endm ++ ++ .macro resume_mmdc ++ /* restore MMDC IO */ ++ ldr r10, [r0, #PM_INFO_IOMUXC_V_OFFSET] ++ ++ ldr r6, [r0, #PM_INFO_IO_NUM_OFFSET] ++ ldr r7, =PM_INFO_IO_VAL_OFFSET ++ add r7, r7, r0 ++6: ++ ldr r8, [r7], #0x4 ++ ldr r9, [r7], #0x4 ++ str r9, [r10, r8] ++ subs r6, r6, #0x1 ++ bne 6b ++ ++ /* ++ * Need to reset the FIFO to avoid MMDC lockup ++ * caused because of floating/changing the ++ * configuration of many DDR IO pads. ++ */ ++ ldr r10, [r0, #PM_INFO_MMDC_V_OFFSET] ++ /* reset read FIFO, RST_RD_FIFO */ ++ ldr r7, =MX6Q_MMDC_MPDGCTRL0 ++ ldr r6, [r10, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r10, r7] ++7: ++ ldr r6, [r10, r7] ++ ands r6, r6, #(1 << 31) ++ bne 7b ++ ++ /* reset FIFO a second time */ ++ ldr r7, =MX6Q_MMDC_MPDGCTRL0 ++ ldr r6, [r10, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r10, r7] ++8: ++ ldr r6, [r10, r7] ++ ands r6, r6, #(1 <<31) ++ bne 8b ++ ++ ldr r10, [r0, #PM_INFO_MMDC_V_OFFSET] ++ /* Let DDR out of self-refresh */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #(1 << 21) ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++9: ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ bne 9b ++ ++ /* enable power down timer */ ++ ldr r7, [r10, #0x04] ++ orr r7, r7, #0x5500 ++ str r7, [r10, #0x04] ++ ++ /* enable DDR auto power saving */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #0x1 ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++ ++ /* Clear SBS - unblock DDR accesses */ ++ ldr r7, [r10, #0x410] ++ bic r7, r7, #0x100 ++ str r7, [r10, #0x410] ++ ++ .endm ++ ++ .macro tlb_set_to_ocram ++ ++ /* save ttbr */ ++ mrc p15, 0, r7, c2, c0, 1 ++ str r7, [r0, #PM_INFO_TTBR_OFFSET] ++ ++ /* ++ * To ensure no page table walks occur in DDR, we ++ * have a another page table stored in IRAM that only ++ * contains entries pointing to IRAM, AIPS1 and AIPS2. ++ * we need to set the TTBR1 to the new IRAM TLB. ++ * Do the following steps: ++ * 1. Flush the Branch Target Address Cache (BTAC) ++ * 2. Set TTBR1 to point to the IRAM page table. ++ * 3. Disable page table walks in TTBR0 (PD0 = 1) ++ * 4. Set TTBR0.N=1, implying 0-2G is transslated by TTBR0 ++ * and 2-4G is translated by TTBR1. ++ */ ++ ++ ldr r6, =iram_tlb_phys_addr ++ ldr r7, [r6] ++ ++ /* Disable Branch Prediction, Z bit in SCTLR */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the BTAC. */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ dsb ++ isb ++ ++ /* store the IRAM table in TTBR1 */ ++ mcr p15, 0, r7, c2, c0, 1 ++ /* Read TTBCR and set PD0=1, N=1 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ orr r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* Flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ .endm ++ ++ .macro tlb_back_to_ddr ++ ++ /* Restore the TTBCR */ ++ dsb ++ isb ++ ++ /* Read TTBCR and set PD0=0, N=0 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ bic r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ /* Flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ /* Enable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x800 ++ mcr p15, 0 ,r6, c1, c0, 0 ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ /* Restore ttbr */ ++ ldr r7, [r0, #PM_INFO_TTBR_OFFSET] ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ .endm ++ ++.extern iram_tlb_phys_addr ++ ++/* ++ * imx6sl_low_power_wfi code ++ * r0: wfi code base address ++ * r1: audio_bus_freq mode stat ++ * r2: vbus_ldo status ++ * r4: used for store the PLLs state ++ * r11: used for saving the ARM_PODF origin value ++ * r12: used for saving AHB_PODF origin value ++ */ ++ .align 3 ++ENTRY(imx6sl_low_power_wfi) ++ ++mx6sl_lpm_wfi_start: ++ ++ push {r4-r12} ++ ++ tlb_set_to_ocram ++ disable_l1_dcache ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* sync L2 */ ++ ldr r10, [r0, #PM_INFO_L2_V_OFFSET] ++ /* Wait for background operations to complete. */ ++wait_for_l2_idle: ++ ldr r6, [r10, #0x730] ++ cmp r6, #0x0 ++ bne wait_for_l2_idle ++ ++ mov r6, #0x0 ++ str r6, [r10, #0x730] ++ /* disable L2 */ ++ str r6, [r10, #0x100] ++ ++ dsb ++ isb ++#endif ++ ++ /* make sure MMDC in self-refresh */ ++ ldr r10, [r0, #PM_INFO_MMDC_V_OFFSET] ++ mmdc_enter_dvfs_mode ++ /* save DDR IO settings and set to LPM mode*/ ++ ldr r10, [r0, #PM_INFO_IOMUXC_V_OFFSET] ++ ldr r6, =0x0 ++ ldr r7, [r0, #PM_INFO_IO_NUM_OFFSET] ++ ldr r8, =PM_INFO_IO_VAL_OFFSET ++ add r8, r8, r0 ++ ++ /* imx6sl's last 3 IOs need special setting */ ++ sub r7, r7, #0x3 ++save_and_set_mmdc_io_lpm: ++ ldr r9, [r8], #0x4 ++ ldr r5, [r10, r9] ++ str r6, [r10, r9] ++ str r5, [r8], #0x4 ++ subs r7, r7, #0x1 ++ bne save_and_set_mmdc_io_lpm ++ ldr r6, =0x1000 ++ ldr r9, [r8], #0x4 ++ ldr r5, [r10, r9] ++ str r5, [r8], #0x4 ++ str r6, [r10, r9] ++ ldr r9, [r8], #0x4 ++ ldr r5, [r10, r9] ++ str r6, [r10, r9] ++ str r5, [r8], #0x4 ++ ldr r6, =0x80000 ++ ldr r9, [r8], #0x4 ++ ldr r5, [r10, r9] ++ str r6, [r10, r9] ++ str r5, [r8], #0x4 ++ ++ ++ /* check the PLLs lock state */ ++ check_pll_state ++ ++ ccm_enter_idle ++ /* if in audio low power mode, no ++ * need to do anatop setting. ++ */ ++ cmp r1, #0x1 ++ beq do_wfi ++ anatop_enter_idle ++do_wfi: ++ wfi ++ /* ++ * Add these nops so that the ++ * prefetcher will not try to get ++ * any instrutions 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 ++ ++ /* ++ * restore the ARM PODF first to speed ++ * up the restore procedure ++ */ ++ ldr r10, [r0, #PM_INFO_CCM_V_OFFSET] ++ /* Restore arm_clk_podf */ ++ str r11, [r10, #0x10] ++ ccm_do_wait ++ ++ /* ++ * if in audio low power mode, skip ++ * restore the anatop setting. ++ */ ++ cmp r1, #0x1 ++ beq skip_analog_restore ++ anatop_exit_idle ++ ++skip_analog_restore: ++ ccm_exit_idle ++ resume_mmdc ++ ++ /* enable d-cache */ ++ mrc p15, 0, r7, c1, c0, 0 ++ orr r7, r7, #(1 << 2) ++ mcr p15, 0, r7, c1, c0, 0 ++ ++#ifdef CONFIG_CACHE_L2X0 ++ ldr r10, [r0, #PM_INFO_L2_V_OFFSET] ++ mov r7, #0x1 ++ /* enable L2 */ ++ str r7, [r10, #0x100] ++#endif ++ tlb_back_to_ddr ++ ++ /* Restore register */ ++ pop {r4 - r12} ++ mov pc, lr ++ ++ /* ++ * Add ltorg here to ensure that all ++ * literals are stored here and are ++ * within the text space. ++ */ ++ .ltorg ++mx6sl_lpm_wfi_end: +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/imx6sx_low_power_idle.S linux-3.14.72/arch/arm/mach-imx/imx6sx_low_power_idle.S +--- linux-3.14.72.orig/arch/arm/mach-imx/imx6sx_low_power_idle.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/imx6sx_low_power_idle.S 2016-06-19 22:11:55.049156848 +0200 +@@ -0,0 +1,887 @@ ++/* ++ * Copyright (C) 2014-2015 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. ++ */ ++ ++#include ++ ++#define PM_INFO_PBASE_OFFSET 0x0 ++#define PM_INFO_RESUME_ADDR_OFFSET 0x4 ++#define PM_INFO_PM_INFO_SIZE_OFFSET 0x8 ++#define PM_INFO_PM_INFO_TTBR_OFFSET 0xc ++#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 ++#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 ++#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x18 ++#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x1c ++#define PM_INFO_MX6Q_CCM_P_OFFSET 0x20 ++#define PM_INFO_MX6Q_CCM_V_OFFSET 0x24 ++#define PM_INFO_MX6Q_GPC_P_OFFSET 0x28 ++#define PM_INFO_MX6Q_GPC_V_OFFSET 0x2c ++#define PM_INFO_MX6Q_L2_P_OFFSET 0x30 ++#define PM_INFO_MX6Q_L2_V_OFFSET 0x34 ++#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x38 ++#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x3c ++#define PM_INFO_MX6Q_SRC_P_OFFSET 0x40 ++#define PM_INFO_MX6Q_SRC_V_OFFSET 0x44 ++#define PM_INFO_MX6Q_SEMA4_P_OFFSET 0x48 ++#define PM_INFO_MX6Q_SEMA4_V_OFFSET 0x4c ++#define PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET 0x50 ++#define PM_INFO_MMDC_IO_NUM_OFFSET 0x54 ++#define PM_INFO_MMDC_IO_VAL_OFFSET 0x58 ++ ++#define MX6Q_MMDC_MAPSR 0x404 ++#define MX6Q_MMDC_MPDGCTRL0 0x83c ++#define MX6Q_SRC_GPR1 0x20 ++#define MX6Q_SRC_GPR2 0x24 ++#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 ++ ++.globl mx6sx_lpm_wfi_start ++.globl mx6sx_lpm_wfi_end ++ ++ .macro pll_do_wait_lock ++1: ++ ldr r7, [r10, r8] ++ ands r7, #0x80000000 ++ beq 1b ++ ++ .endm ++ ++ .macro ccm_do_wait ++2: ++ ldr r7, [r10, #0x48] ++ cmp r7, #0x0 ++ bne 2b ++ ++ .endm ++ ++ .macro ccm_enter_idle ++ ++ ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] ++ ++ /* set ahb to 3MHz */ ++ ldr r7, [r10, #0x14] ++ orr r7, r7, #0x1c00 ++ str r7, [r10, #0x14] ++ ++ /* set perclk to 6MHz */ ++ ldr r7, [r10, #0x1c] ++ bic r7, r7, #0x3f ++ orr r7, r7, #0x3 ++ str r7, [r10, #0x1c] ++ ++ /* set mmdc to 1MHz, periph2_clk2 need to be @8MHz */ ++ ldr r7, [r10, #0x14] ++ orr r7, r7, #0x2 ++ orr r7, r7, #(0x7 << 3) ++ str r7, [r10, #0x14] ++ ++ ccm_do_wait ++ ++ ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] ++ ++ /* set pll1_sw to from pll1 main */ ++ ldr r7, [r10, #0xc] ++ bic r7, r7, #0x4 ++ str r7, [r10, #0xc] ++ ++ /* set step from osc */ ++ ldr r7, [r10, #0xc] ++ bic r7, r7, #0x100 ++ str r7, [r10, #0xc] ++ ++ /* set pll1_sw to from step */ ++ ldr r7, [r10, #0xc] ++ orr r7, r7, #0x4 ++ str r7, [r10, #0xc] ++ ++ ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] ++ ++ /* Disable PLL1 bypass output */ ++ ldr r7, [r10] ++ bic r7, r7, #0x12000 ++ str r7, [r10] ++ ++ /* ++ * disable pll2, suppose when system enter low ++ * power idle mode, only 396MHz pfd needs pll2, ++ * now we switch arm clock to OSC, we can disable ++ * pll2 now, gate pll2_pfd2 first. ++ */ ++ ldr r7, [r10, #0x100] ++ orr r7, #0x800000 ++ str r7, [r10, #0x100] ++ ++ ldr r7, [r10, #0x30] ++ orr r7, r7, #0x1000 ++ bic r7, r7, #0x2000 ++ str r7, [r10, #0x30] ++ ++ .endm ++ ++ .macro ccm_exit_idle ++ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] ++ ++ /* enable pll2 and pll2_pfd2 */ ++ ldr r7, [r10, #0x30] ++ bic r7, r7, #0x1000 ++ orr r7, r7, #0x2000 ++ str r7, [r10, #0x30] ++ ++ ldr r8, =0x30 ++ pll_do_wait_lock ++ ++ ldr r7, [r10, #0x100] ++ bic r7, #0x800000 ++ str r7, [r10, #0x100] ++ ++ /* enable PLL1 bypass output */ ++ ldr r7, [r10] ++ orr r7, r7, #0x12000 ++ str r7, [r10] ++ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_CCM_P_OFFSET] ++ ++ /* set perclk back to 24MHz */ ++ ldr r7, [r10, #0x1c] ++ bic r7, r7, #0x3f ++ str r7, [r10, #0x1c] ++ ++ /* set mmdc back to 24MHz */ ++ ldr r7, [r10, #0x14] ++ bic r7, r7, #0x7 ++ bic r7, r7, #(0x7 << 3) ++ str r7, [r10, #0x14] ++ ++ /* set ahb div back to 24MHz */ ++ ldr r7, [r10, #0x14] ++ bic r7, r7, #0x1c00 ++ str r7, [r10, #0x14] ++ ++ ccm_do_wait ++ ++ /* set pll1_sw to from pll1 main */ ++ ldr r7, [r10, #0xc] ++ bic r7, r7, #0x4 ++ str r7, [r10, #0xc] ++ ++ /* set step from pll2_pfd2 */ ++ ldr r7, [r10, #0xc] ++ orr r7, r7, #0x100 ++ str r7, [r10, #0xc] ++ ++ /* set pll1_sw to from step */ ++ ldr r7, [r10, #0xc] ++ orr r7, r7, #0x4 ++ str r7, [r10, #0xc] ++ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] ++ ++ .endm ++ ++ .macro anatop_enter_idle ++ ++ ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] ++ ++ /* ++ * check whether any PLL is enabled, as only when ++ * there is no PLLs enabled, 2P5 and 1P1 can be ++ * off and only enable weak ones. ++ */ ++ ++ /* arm pll1 */ ++ ldr r7, [r10, #0] ++ ands r7, r7, #(1 << 31) ++ bne 10f ++ ++ /* sys pll2 */ ++ ldr r7, [r10, #0x30] ++ ands r7, r7, #(1 << 31) ++ bne 10f ++ ++ /* usb pll3 */ ++ ldr r7, [r10, #0x10] ++ ands r7, r7, #(1 << 31) ++ bne 10f ++ ++ /* audio pll4 */ ++ ldr r7, [r10, #0x70] ++ ands r7, r7, #(1 << 31) ++ bne 10f ++ ++ /* vidio pll5 */ ++ ldr r7, [r10, #0xa0] ++ ands r7, r7, #(1 << 31) ++ bne 10f ++ ++ /* enet pll6 */ ++ ldr r7, [r10, #0xe0] ++ ands r7, r7, #(1 << 31) ++ bne 10f ++ ++ /* usb host pll7 */ ++ ldr r7, [r10, #0x20] ++ ands r7, r7, #(1 << 31) ++ bne 10f ++ ++ /* enable weak 2P5 and turn off regular 2P5 */ ++ ldr r7, [r10, #0x130] ++ orr r7, r7, #0x40000 ++ str r7, [r10, #0x130] ++ bic r7, r7, #0x1 ++ str r7, [r10, #0x130] ++ ++ /* enable weak 1p1 and turn off regular 1P1 */ ++ ldr r7, [r10, #0x110] ++ orr r7, r7, #0x40000 ++ str r7, [r10, #0x110] ++ bic r7, r7, #0x1 ++ str r7, [r10, #0x110] ++ ++ /* check whether ARM LDO is bypassed */ ++ ldr r7, [r10, #0x140] ++ and r7, r7, #0x1f ++ cmp r7, #0x1f ++ bne 10f ++ ++ /* low power band gap enable */ ++ ldr r7, [r10, #0x270] ++ orr r7, r7, #0x20 ++ str r7, [r10, #0x270] ++ ++ /* turn off the bias current from the regular bandgap */ ++ ldr r7, [r10, #0x270] ++ orr r7, r7, #0x80 ++ str r7, [r10, #0x270] ++ ++ /* ++ * clear the REFTOP_SELFBIASOFF, ++ * self-bias circuit of the band gap. ++ * Per RM, should be cleared when ++ * band gap is powered down. ++ */ ++ ldr r7, [r10, #0x150] ++ bic r7, r7, #0x8 ++ str r7, [r10, #0x150] ++ ++ /* turn off regular bandgap */ ++ ldr r7, [r10, #0x150] ++ orr r7, r7, #0x1 ++ str r7, [r10, #0x150] ++ ++ /* only switch to RC-OSC clk after TO1.2 */ ++ ldr r7, [r10, #0x260] ++ and r7, r7, #0x3 ++ cmp r7, #0x2 ++ blt 10f ++ ++ /* switch to RC-OSC */ ++ ldr r7, [r10, #0x270] ++ orr r7, r7, #0x10 ++ str r7, [r10, #0x270] ++ ++ /* turn off XTAL-OSC */ ++ ldr r7, [r10, #0x150] ++ orr r7, r7, #0x40000000 ++ str r7, [r10, #0x150] ++10: ++ /* lower OSC current by 37.5% */ ++ ldr r7, [r10, #0x150] ++ orr r7, r7, #0x6000 ++ str r7, [r10, #0x150] ++ ++ .endm ++ ++ .macro anatop_exit_idle ++ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] ++ ++ /* increase OSC current to normal */ ++ ldr r7, [r10, #0x150] ++ bic r7, r7, #0x6000 ++ str r7, [r10, #0x150] ++ ++ /* only switch to RC-OSC after TO1.2 */ ++ ldr r7, [r10, #0x260] ++ and r7, r7, #0x3 ++ cmp r7, #0x2 ++ blt 15f ++ ++ /* turn on XTAL-OSC and detector */ ++ ldr r7, [r10, #0x150] ++ bic r7, r7, #0x40000000 ++ orr r7, r7, #0x10000 ++ str r7, [r10, #0x150] ++ ++ /* wait for XTAL stable */ ++14: ++ ldr r7, [r10, #0x150] ++ ands r7, r7, #0x8000 ++ beq 14b ++ ++ /* switch to XTAL-OSC */ ++ ldr r7, [r10, #0x270] ++ bic r7, r7, #0x10 ++ str r7, [r10, #0x270] ++ ++ /* turn off XTAL-OSC detector */ ++ ldr r7, [r10, #0x150] ++ bic r7, r7, #0x10000 ++ str r7, [r10, #0x150] ++15: ++ /* check whether we need to enable 2P5/1P1 */ ++ ldr r7, [r10, #0x110] ++ ands r7, r7, #0x40000 ++ beq 11f ++ ++ /* check whether ARM LDO is bypassed */ ++ ldr r7, [r10, #0x140] ++ and r7, r7, #0x1f ++ cmp r7, #0x1f ++ bne 12f ++ ++ /* turn on regular bandgap and wait for stable */ ++ ldr r7, [r10, #0x150] ++ bic r7, r7, #0x1 ++ str r7, [r10, #0x150] ++13: ++ ldr r7, [r10, #0x150] ++ ands r7, #0x80 ++ beq 13b ++ ++ /* ++ * set the REFTOP_SELFBIASOFF, ++ * self-bias circuit of the band gap. ++ */ ++ ldr r7, [r10, #0x150] ++ orr r7, r7, #0x8 ++ str r7, [r10, #0x150] ++ ++ /* turn on the bias current from the regular bandgap */ ++ ldr r7, [r10, #0x270] ++ bic r7, r7, #0x80 ++ str r7, [r10, #0x270] ++ ++ /* low power band gap disable */ ++ ldr r7, [r10, #0x270] ++ bic r7, r7, #0x20 ++ str r7, [r10, #0x270] ++12: ++ /* enable regular 2P5 and turn off weak 2P5 */ ++ ldr r7, [r10, #0x130] ++ orr r7, r7, #0x1 ++ str r7, [r10, #0x130] ++ ++ /* Ensure the 2P5 is up. */ ++3: ++ ldr r7, [r10, #0x130] ++ ands r7, r7, #0x20000 ++ beq 3b ++ ldr r7, [r10, #0x130] ++ bic r7, r7, #0x40000 ++ str r7, [r10, #0x130] ++ ++ /* enable regular 1p1 and turn off weak 1P1 */ ++ ldr r7, [r10, #0x110] ++ orr r7, r7, #0x1 ++ str r7, [r10, #0x110] ++4: ++ ldr r7, [r10, #0x110] ++ ands r7, r7, #0x20000 ++ beq 4b ++ ldr r7, [r10, #0x110] ++ bic r7, r7, #0x40000 ++ str r7, [r10, #0x110] ++11: ++ .endm ++ ++ .macro disable_l1_dcache ++ ++ /* ++ * Flush all data from the L1 data cache before disabling ++ * SCTLR.C bit. ++ */ ++ push {r0 - r10, lr} ++ ldr r7, =v7_flush_dcache_all ++ mov lr, pc ++ mov pc, r7 ++ pop {r0 - r10, lr} ++ ++ /* disable d-cache */ ++ mrc p15, 0, r7, c1, c0, 0 ++ bic r7, r7, #(1 << 2) ++ mcr p15, 0, r7, c1, c0, 0 ++ dsb ++ isb ++ ++ push {r0 - r10, lr} ++ ldr r7, =v7_flush_dcache_all ++ mov lr, pc ++ mov pc, r7 ++ pop {r0 - r10, lr} ++ ++ .endm ++ ++ .macro mmdc_enter_dvfs_mode ++ ++ /* disable automatic power savings. */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #0x1 ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++ ++ /* disable power down timer */ ++ ldr r7, [r10, #0x4] ++ bic r7, r7, #0xff00 ++ str r7, [r10, #0x4] ++ ++ /* make the DDR explicitly enter self-refresh. */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #(1 << 21) ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++5: ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ beq 5b ++ ++ .endm ++ ++ .macro resume_mmdc ++ ++ /* restore MMDC IO */ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] ++ ldrne r10, [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 ++6: ++ ldr r8, [r7], #0x4 ++ ldr r9, [r7], #0x4 ++ str r9, [r10, r8] ++ subs r6, r6, #0x1 ++ bne 6b ++ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] ++ ++ /* reset read FIFO, RST_RD_FIFO */ ++ ldr r7, =MX6Q_MMDC_MPDGCTRL0 ++ ldr r6, [r10, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r10, r7] ++7: ++ ldr r6, [r10, r7] ++ ands r6, r6, #(1 << 31) ++ bne 7b ++ ++ /* reset FIFO a second time */ ++ ldr r6, [r10, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r10, r7] ++8: ++ ldr r6, [r10, r7] ++ ands r6, r6, #(1 << 31) ++ bne 8b ++ ++ /* let DDR out of self-refresh */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #(1 << 21) ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++9: ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ bne 9b ++ ++ /* enable power down timer */ ++ ldr r7, [r10, #0x4] ++ orr r7, r7, #0x5500 ++ str r7, [r10, #0x4] ++ ++ /* enable DDR auto power saving */ ++ ldr r7, [r10, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #0x1 ++ str r7, [r10, #MX6Q_MMDC_MAPSR] ++ ++ .endm ++ ++ .macro sema4_lock ++ ++ /* lock share memory sema4 */ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_SEMA4_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_SEMA4_P_OFFSET] ++ ldrb r6, =0x1 ++16: ++ ldrb r7, [r10, #0x6] ++ cmp r7, #0x0 ++ bne 16b ++ strb r6, [r10, #0x6] ++ ++ .endm ++ ++ .macro sema4_unlock ++ ++ /* unlock share memory sema4 */ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_SEMA4_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_SEMA4_P_OFFSET] ++ ldrb r6, =0x0 ++ strb r6, [r10, #0x6] ++ ++ .endm ++ ++ .macro tlb_set_to_ocram ++ ++ /* save ttbr */ ++ mrc p15, 0, r7, c2, c0, 1 ++ str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] ++ ++ /* ++ * To ensure no page table walks occur in DDR, we ++ * have a another page table stored in IRAM that only ++ * contains entries pointing to IRAM, AIPS1 and AIPS2. ++ * We need to set the TTBR1 to the new IRAM TLB. ++ * Do the following steps: ++ * 1. Flush the Branch Target Address Cache (BTAC) ++ * 2. Set TTBR1 to point to IRAM page table. ++ * 3. Disable page table walks in TTBR0 (PD0 = 1) ++ * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 ++ * and 2-4G is translated by TTBR1. ++ */ ++ ++ ldr r6, =iram_tlb_phys_addr ++ ldr r7, [r6] ++ ++ /* Flush the BTAC. */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ /* Disable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ dsb ++ isb ++ ++ /* Store the IRAM table in TTBR1 */ ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ /* Read TTBCR and set PD0=1, N = 1 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ orr r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ .endm ++ ++ .macro tlb_back_to_ddr ++ ++ /* Restore the TTBCR */ ++ ++ dsb ++ isb ++ ++ /* Read TTBCR and set PD0=0, N = 0 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ bic r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ /* Enable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ /* restore ttbr */ ++ ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET] ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ .endm ++ ++.extern iram_tlb_phys_addr ++ ++/* imx6sx_low_power_idle */ ++ ++ .align 3 ++ENTRY(imx6sx_low_power_idle) ++mx6sx_lpm_wfi_start: ++ push {r4 - r10} ++ ++ /* get necessary info from pm_info */ ++ ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ++ ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] ++ ++ /* ++ * counting the resume address in iram ++ * to set it in SRC register. ++ */ ++ ldr r5, =imx6sx_low_power_idle ++ ldr r6, =wakeup ++ sub r6, r6, r5 ++ add r8, r1, r2 ++ add r3, r8, r6 ++ ++ /* store physical resume addr and pm_info address. */ ++ ldr r10, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] ++ str r3, [r10, #0x20] ++ str r1, [r10, #0x24] ++ ++ /* save disagnostic register */ ++ mrc p15, 0, r7, c15, c0, 1 ++ str r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET] ++ ++ /* set ARM power to be gated */ ++ ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ++ ldr r7, =0x1 ++ str r7, [r10, #0x2a0] ++ ++ disable_l1_dcache ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* sync L2 */ ++ ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] ++ ++ /* Wait for background operations to complete. */ ++wait_for_l2_to_idle: ++ ldr r7, [r10, #0x730] ++ cmp r7, #0x0 ++ bne wait_for_l2_to_idle ++ ++ mov r7, #0x0 ++ str r7, [r10, #0x730] ++ /* disable L2 */ ++ str r7, [r10, #0x100] ++ ++ dsb ++ isb ++#endif ++ ++ tlb_set_to_ocram ++ ++ /* make sure MMDC in self-refresh */ ++ ldr r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ++ mmdc_enter_dvfs_mode ++ ++ /* save DDR IO settings */ ++ ldr r10, [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 ++save_and_set_mmdc_io_lpm: ++ ldr r9, [r8], #0x4 ++ ldr r5, [r10, r9] ++ str r6, [r10, r9] ++ str r5, [r8], #0x4 ++ subs r7, r7, #0x1 ++ bne save_and_set_mmdc_io_lpm ++ ++ mov r5, #0x0 ++ sema4_lock ++ ccm_enter_idle ++ anatop_enter_idle ++ sema4_unlock ++ ++ /* ++ * mask all GPC interrupts before ++ * enabling the RBC counters to ++ * avoid the counter starting too ++ * early if an interupt is already ++ * pending. ++ */ ++ ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ++ ldr r4, [r10, #MX6Q_GPC_IMR1] ++ ldr r5, [r10, #MX6Q_GPC_IMR2] ++ ldr r6, [r10, #MX6Q_GPC_IMR3] ++ ldr r7, [r10, #MX6Q_GPC_IMR4] ++ ++ ldr r3, =0xffffffff ++ str r3, [r10, #MX6Q_GPC_IMR1] ++ str r3, [r10, #MX6Q_GPC_IMR2] ++ str r3, [r10, #MX6Q_GPC_IMR3] ++ str r3, [r10, #MX6Q_GPC_IMR4] ++ ++ /* ++ * enable the RBC bypass counter here ++ * to hold off the interrupts. RBC counter ++ * = 1 (30us). With this setting, the latency ++ * from wakeup interrupt to ARM power up ++ * is ~40uS. ++ */ ++ ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] ++ ldr r3, [r10, #MX6Q_CCM_CCR] ++ bic r3, r3, #(0x3f << 21) ++ orr r3, r3, #(0x1 << 21) ++ str r3, [r10, #MX6Q_CCM_CCR] ++ ++ /* enable the counter. */ ++ ldr r3, [r10, #MX6Q_CCM_CCR] ++ orr r3, r3, #(0x1 << 27) ++ str r3, [r10, #MX6Q_CCM_CCR] ++ ++ /* unmask all the GPC interrupts. */ ++ ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ++ str r4, [r10, #MX6Q_GPC_IMR1] ++ str r5, [r10, #MX6Q_GPC_IMR2] ++ str r6, [r10, #MX6Q_GPC_IMR3] ++ str r7, [r10, #MX6Q_GPC_IMR4] ++ ++ /* ++ * now delay for a short while (3usec) ++ * ARM is at 1GHz at this point ++ * so a short loop should be enough. ++ * this delay is required to ensure that ++ * the RBC counter can start counting in ++ * case an interrupt is already pending ++ * or in case an interrupt arrives just ++ * as ARM is about to assert DSM_request. ++ */ ++ ldr r4, =2000 ++rbc_loop: ++ subs r4, r4, #0x1 ++ bne rbc_loop ++ ++ wfi ++ ++ 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 ++ ++ mov r5, #0x0 ++ sema4_lock ++ anatop_exit_idle ++ ccm_exit_idle ++ sema4_unlock ++ resume_mmdc ++ ++ /* clear ARM power gate setting */ ++ ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ++ ldr r7, =0x0 ++ str r7, [r10, #0x2a0] ++ ++ /* enable d-cache */ ++ mrc p15, 0, r7, c1, c0, 0 ++ orr r7, r7, #(1 << 2) ++ mcr p15, 0, r7, c1, c0, 0 ++ ++#ifdef CONFIG_CACHE_L2X0 ++ ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] ++ mov r7, #0x1 ++ /* enable L2 */ ++ str r7, [r10, #0x100] ++#endif ++ ++ tlb_back_to_ddr ++ ++ /* Restore registers */ ++ pop {r4 - r10} ++ mov pc, lr ++ ++wakeup: ++ ++ /* invalidate L1 I-cache first */ ++ mov r1, #0x0 ++ mcr p15, 0, r1, c7, c5, 0 ++ mcr p15, 0, r1, c7, c5, 0 ++ mcr p15, 0, r1, c7, c5, 6 ++ /* enable the Icache and branch prediction */ ++ mov r1, #0x1800 ++ mcr p15, 0, r1, c1, c0, 0 ++ isb ++ /* restore disagnostic register */ ++ ldr r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET] ++ mcr p15, 0, r7, c15, c0, 1 ++ ++ /* get physical resume address from pm_info. */ ++ ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] ++ /* clear core0's entry and parameter */ ++ ldr r10, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET] ++ mov r7, #0x0 ++ str r7, [r10, #MX6Q_SRC_GPR1] ++ str r7, [r10, #MX6Q_SRC_GPR2] ++ ++ /* clear ARM power gate setting */ ++ ldr r10, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET] ++ ldr r7, =0x0 ++ str r7, [r10, #0x2a0] ++ ++ mov r5, #0x1 ++ sema4_lock ++ anatop_exit_idle ++ ccm_exit_idle ++ sema4_unlock ++ resume_mmdc ++ ++ /* Restore registers */ ++ mov pc, lr ++ .ltorg ++mx6sx_lpm_wfi_end: +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/Kconfig linux-3.14.72/arch/arm/mach-imx/Kconfig +--- linux-3.14.72.orig/arch/arm/mach-imx/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/Kconfig 2016-06-19 22:11:55.049156848 +0200 +@@ -1,19 +1,23 @@ + config ARCH_MXC + bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 ++ select ARCH_HAS_CPUFREQ ++ select ARCH_HAS_OPP ++ select ARCH_HAS_RESET_CONTROLLER + select ARCH_REQUIRE_GPIOLIB + select ARM_CPU_SUSPEND if PM + select ARM_PATCH_PHYS_VIRT + select CLKSRC_MMIO + select COMMON_CLK +- select GENERIC_ALLOCATOR + select GENERIC_CLOCKEVENTS + select GENERIC_IRQ_CHIP + select MIGHT_HAVE_CACHE_L2X0 if ARCH_MULTI_V6_V7 + select MULTI_IRQ_HANDLER + select PINCTRL ++ select PM_OPP if PM + select SOC_BUS + select SPARSE_IRQ + select USE_OF ++ select SRAM + help + Support for Freescale MXC/iMX-based family of processors + +@@ -52,18 +56,28 @@ + config ARCH_HAS_RNGA + bool + ++config HAVE_IMX_RNG ++ bool ++ + config HAVE_IMX_ANATOP + bool + + config HAVE_IMX_GPC + bool ++ select PM_GENERIC_DOMAINS if PM + + config HAVE_IMX_MMDC + bool + + config HAVE_IMX_SRC + def_bool y if SMP +- select ARCH_HAS_RESET_CONTROLLER ++ ++config HAVE_IMX_MCC ++ select IMX_SEMA4 ++ bool ++ ++config HAVE_IMX_AMP ++ bool + + config IMX_HAVE_IOMUX_V1 + bool +@@ -784,53 +798,54 @@ + help + This enables support for Freescale i.MX53 processor. + +-config SOC_IMX6Q +- bool "i.MX6 Quad/DualLite support" +- select ARCH_HAS_CPUFREQ +- select ARCH_HAS_OPP ++config SOC_IMX6 ++ bool + select ARM_ERRATA_754322 +- select ARM_ERRATA_764369 if SMP + select ARM_ERRATA_775420 + select ARM_GIC + select CPU_V7 +- select HAVE_ARM_SCU if SMP +- select HAVE_ARM_TWD if SMP + select HAVE_IMX_ANATOP + select HAVE_IMX_GPC + select HAVE_IMX_MMDC + select HAVE_IMX_SRC + select HAVE_SMP + select MFD_SYSCON ++ select PL310_ERRATA_769419 if CACHE_PL310 ++ select ARM_IMX6Q_CPUFREQ ++ ++config SOC_IMX6Q ++ bool "i.MX6 Quad/DualLite support" ++ select ARM_ERRATA_764369 if SMP ++ select HAVE_ARM_SCU if SMP ++ select HAVE_ARM_TWD if SMP + select MIGHT_HAVE_PCI + select PCI_DOMAINS if PCI + 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 SOC_IMX6 ++ select ZONE_DMA + + help + This enables support for Freescale i.MX6 Quad processor. + + config SOC_IMX6SL + bool "i.MX6 SoloLite support" +- select ARM_ERRATA_754322 +- select ARM_ERRATA_775420 +- select ARM_GIC +- select CPU_V7 +- select HAVE_IMX_ANATOP +- select HAVE_IMX_GPC +- select HAVE_IMX_MMDC +- select HAVE_IMX_SRC +- select MFD_SYSCON ++ select HAVE_IMX_RNG + select PINCTRL_IMX6SL +- select PL310_ERRATA_588369 if CACHE_PL310 +- select PL310_ERRATA_727915 if CACHE_PL310 +- select PL310_ERRATA_769419 if CACHE_PL310 ++ select SOC_IMX6 + + help + This enables support for Freescale i.MX6 SoloLite processor. + ++config SOC_IMX6SX ++ bool "i.MX6 SoloX support" ++ select PINCTRL_IMX6SX ++ select HAVE_IMX_AMP ++ select HAVE_IMX_MCC ++ select SOC_IMX6 ++ ++ help ++ This enables support for Freescale i.MX6 SoloX processor. ++ + config SOC_VF610 + bool "Vybrid Family VF610 support" + select CPU_V7 +@@ -838,8 +853,6 @@ + select CLKSRC_OF + select PINCTRL_VF610 + select VF_PIT_TIMER +- select PL310_ERRATA_588369 if CACHE_PL310 +- select PL310_ERRATA_727915 if CACHE_PL310 + select PL310_ERRATA_769419 if CACHE_PL310 + + help +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/lpddr2_freq_imx6.S linux-3.14.72/arch/arm/mach-imx/lpddr2_freq_imx6.S +--- linux-3.14.72.orig/arch/arm/mach-imx/lpddr2_freq_imx6.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/lpddr2_freq_imx6.S 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,603 @@ ++/* ++ * Copyright (C) 2012-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. ++ */ ++ ++#include ++#include "hardware.h" ++ ++.globl imx6_lpddr2_freq_change_start ++.globl imx6_lpddr2_freq_change_end ++ ++ .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 ++ */ ++ .align 3 ++ENTRY(mx6_lpddr2_freq_change) ++imx6_lpddr2_freq_change_start: ++ push {r4-r10} ++ ++ /* ++ * To ensure no page table walks occur in DDR, we ++ * have a another page table stored in IRAM that only ++ * contains entries pointing to IRAM, AIPS1 and AIPS2. ++ * We need to set the TTBR1 to the new IRAM TLB. ++ * Do the following steps: ++ * 1. Flush the Branch Target Address Cache (BTAC) ++ * 2. Set TTBR1 to point to IRAM page table. ++ * 3. Disable page table walks in TTBR0 (PD0 = 1) ++ * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 ++ * and 2-4G is translated by TTBR1. ++ */ ++ ++ ldr r6, =iram_tlb_phys_addr ++ ldr r7, [r6] ++ ++ /* Disable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ dsb ++ isb ++ /* Store the IRAM table in TTBR1 */ ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ /* Read TTBCR and set PD0=1, N = 1 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ orr r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ /* Disable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ dsb ++ isb ++ ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* ++ * Need to make sure the buffers in L2 are drained. ++ * Performing a sync operation does this. ++ */ ++ ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ ++ /* Wait for background operations to complete. */ ++wait_for_l2_to_idle: ++ ldr r6, [r7, #0x730] ++ cmp r6, #0x0 ++ bne wait_for_l2_to_idle ++ ++ mov r6, #0x0 ++ str r6, [r7, #0x730] ++ ++ /* ++ * The second dsb might be needed to keep cache sync (device write) ++ * ordering with the memory accesses before it. ++ */ ++ dsb ++ isb ++ ++ /* Disable L2. */ ++ str r6, [r7, #0x100] ++#endif ++ ++ ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) ++ ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) ++ ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) ++ ++ /* 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] ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* Enable L2. */ ++ ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ ldr r6, =0x1 ++ str r6, [r7, #0x100] ++#endif ++ ++ /* Enable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Restore the TTBCR */ ++ dsb ++ isb ++ ++ /* Read TTBCR and set PD0=0, N = 0 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ bic r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ /* Enable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ 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 ++ ++ pop {r4-r10} ++ ++ /* Restore registers */ ++ mov pc, lr ++ ++ /* ++ * Add ltorg here to ensure that all ++ * literals are stored here and are ++ * within the text space. ++ */ ++ .ltorg ++imx6_lpddr2_freq_change_end: +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/lpddr2_freq_imx6sx.S linux-3.14.72/arch/arm/mach-imx/lpddr2_freq_imx6sx.S +--- linux-3.14.72.orig/arch/arm/mach-imx/lpddr2_freq_imx6sx.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/lpddr2_freq_imx6sx.S 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,450 @@ ++/* ++ * Copyright (C) 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. ++ */ ++ ++#include ++#include "hardware.h" ++ ++#define CCM_CBCDR 0x14 ++#define CCM_CBCMR 0x18 ++#define CCM_CSCMR1 0x1c ++#define CCM_CDHIPR 0x48 ++ ++#define L2_CACHE_SYNC 0x730 ++ ++#define MMDC0_MDPDC 0x4 ++#define MMDC0_MAPSR 0x404 ++#define MMDC0_MADPCR0 0x410 ++ ++ .macro wait_for_ccm_handshake ++ ++1: ++ ldr r8, [r2, #CCM_CDHIPR] ++ cmp r8, #0 ++ bne 1b ++ ++ .endm ++ ++ .macro switch_to_24MHz ++ ++ /* periph2_clk2 sel to OSC_CLK */ ++ ldr r8, [r2, #CCM_CBCMR] ++ orr r8, r8, #(1 << 20) ++ str r8, [r2, #CCM_CBCMR] ++ ++ /* periph2_clk2_podf to 0 */ ++ ldr r8, [r2, #CCM_CBCDR] ++ bic r8, r8, #0x7 ++ str r8, [r2, #CCM_CBCDR] ++ ++ /* periph2_clk sel to periph2_clk2 */ ++ ldr r8, [r2, #CCM_CBCDR] ++ orr r8, r8, #(0x1 << 26) ++ str r8, [r2, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ /* fabric_mmdc_podf to 0 */ ++ ldr r8, [r2, #CCM_CBCDR] ++ bic r8, r8, #(0x7 << 3) ++ str r8, [r2, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ .endm ++ ++ .macro switch_to_100MHz ++ ++ /* check whether periph2_clk is from top path */ ++ ldr r8, [r2, #CCM_CBCDR] ++ ands r8, #(1 << 26) ++ beq skip_periph2_clk2_switch_100m ++ ++ /* now switch periph2_clk back. */ ++ ldr r8, [r2, #CCM_CBCDR] ++ bic r8, r8, #(1 << 26) ++ str r8, [r2, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ /* ++ * on i.MX6SX, pre_periph2_clk will be always from ++ * pll2_pfd2, so no need to set pre_periph2_clk ++ * parent, just set the mmdc divider directly. ++ */ ++skip_periph2_clk2_switch_100m: ++ ++ /* fabric_mmdc_podf to 3 so that mmdc is 400 / 4 = 100MHz */ ++ ldr r8, [r2, #CCM_CBCDR] ++ bic r8, r8, #(0x7 << 3) ++ orr r8, r8, #(0x3 << 3) ++ str r8, [r2, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ .endm ++ ++ .macro switch_to_400MHz ++ ++ /* check whether periph2_clk is from top path */ ++ ldr r8, [r2, #CCM_CBCDR] ++ ands r8, #(1 << 26) ++ beq skip_periph2_clk2_switch_400m ++ ++ /* now switch periph2_clk back. */ ++ ldr r8, [r2, #CCM_CBCDR] ++ bic r8, r8, #(1 << 26) ++ str r8, [r2, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ /* ++ * on i.MX6SX, pre_periph2_clk will be always from ++ * pll2_pfd2, so no need to set pre_periph2_clk ++ * parent, just set the mmdc divider directly. ++ */ ++skip_periph2_clk2_switch_400m: ++ ++ /* fabric_mmdc_podf to 0 */ ++ ldr r8, [r2, #CCM_CBCDR] ++ bic r8, r8, #(0x7 << 3) ++ str r8, [r2, #CCM_CBCDR] ++ ++ wait_for_ccm_handshake ++ ++ .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 r8, =0x8B8 ++ ldr r6, [r5, r8] ++ /* 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, [r5, r8] ++ orr r6, r6, #0x400 ++ str r6, [r5, r8] ++ /* ++ * 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, [r5, r8] ++ ldr r4, =0x3FF ++ bic r6, r6, r4 ++ orr r6, r6, r7 ++ str r6, [r5, r8] ++ /* Now perform a Force Measurement. */ ++ ldr r6, [r5, r8] ++ orr r6, r6, #0x800 ++ str r6, [r5, r8] ++ /* Wait for FRC_MSR to clear. */ ++force_measure: ++ ldr r6, [r5, r8] ++ and r6, r6, #0x800 ++ cmp r6, #0x0 ++ bne force_measure ++ ++ /* For freq lower than 100MHz, need to set RALAT to 2 */ ++ ldr r6, [r5, #0x18] ++ bic r6, r6, #(0x7 << 6) ++ orr r6, r6, #(0x2 << 6) ++ str r6, [r5, #0x18] ++ ++ .endm ++ ++ .macro mmdc_clk_above_100MHz ++ ++ /* Make sure that the PHY measurement unit is NOT in bypass mode */ ++ ldr r8, =0x8B8 ++ ldr r6, [r5, r8] ++ bic r6, r6, #0x400 ++ str r6, [r5, r8] ++ /* Now perform a Force Measurement. */ ++ ldr r6, [r5, r8] ++ orr r6, r6, #0x800 ++ str r6, [r5, r8] ++ /* Wait for FRC_MSR to clear. */ ++force_measure1: ++ ldr r6, [r5, r8] ++ and r6, r6, #0x800 ++ cmp r6, #0x0 ++ bne force_measure1 ++ ++ /* For freq higher than 100MHz, need to set RALAT to 5 */ ++ ldr r6, [r5, #0x18] ++ bic r6, r6, #(0x7 << 6) ++ orr r6, r6, #(0x5 << 6) ++ str r6, [r5, #0x18] ++ ++ .endm ++ ++ .align 3 ++ENTRY(imx6sx_lpddr2_freq_change) ++ ++ push {r2 - r8} ++ ++ /* ++ * To ensure no page table walks occur in DDR, we ++ * have a another page table stored in IRAM that only ++ * contains entries pointing to IRAM, AIPS1 and AIPS2. ++ * We need to set the TTBR1 to the new IRAM TLB. ++ * Do the following steps: ++ * 1. Flush the Branch Target Address Cache (BTAC) ++ * 2. Set TTBR1 to point to IRAM page table. ++ * 3. Disable page table walks in TTBR0 (PD0 = 1) ++ * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 ++ * and 2-4G is translated by TTBR1. ++ */ ++ ++ ldr r6, =iram_tlb_phys_addr ++ ldr r7, [r6] ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ /* Disable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ dsb ++ isb ++ /* Store the IRAM table in TTBR1 */ ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ /* Read TTBCR and set PD0=1, N = 1 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ orr r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ /* Disable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ dsb ++ isb ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* ++ * Need to make sure the buffers in L2 are drained. ++ * Performing a sync operation does this. ++ */ ++ ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ mov r6, #0x0 ++ str r6, [r7, #L2_CACHE_SYNC] ++ ++ /* ++ * The second dsb might be needed to keep cache sync (device write) ++ * ordering with the memory accesses before it. ++ */ ++ dsb ++ isb ++ ++ /* Disable L2. */ ++ str r6, [r7, #0x100] ++#endif ++ ++ ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) ++ ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) ++ ldr r5, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) ++ ++ /* Disable Automatic power savings. */ ++ ldr r6, [r5, #MMDC0_MAPSR] ++ orr r6, r6, #0x1 ++ str r6, [r5, #MMDC0_MAPSR] ++ ++ /* MMDC0_MDPDC disable power down timer */ ++ ldr r6, [r5, #MMDC0_MDPDC] ++ bic r6, r6, #0xff00 ++ str r6, [r5, #MMDC0_MDPDC] ++ ++ /* Delay for a while */ ++ ldr r8, =10 ++delay: ++ ldr r7, =0 ++cont: ++ ldr r6, [r5, r7] ++ add r7, r7, #4 ++ cmp r7, #16 ++ bne cont ++ sub r8, r8, #1 ++ cmp r8, #0 ++ bgt delay ++ ++ /* Make the DDR explicitly enter self-refresh. */ ++ ldr r6, [r5, #MMDC0_MAPSR] ++ orr r6, r6, #0x200000 ++ str r6, [r5, #MMDC0_MAPSR] ++ ++poll_dvfs_set_1: ++ ldr r6, [r5, #MMDC0_MAPSR] ++ and r6, r6, #0x2000000 ++ cmp r6, #0x2000000 ++ bne poll_dvfs_set_1 ++ ++ /* set SBS step-by-step mode */ ++ ldr r6, [r5, #MMDC0_MADPCR0] ++ orr r6, r6, #0x100 ++ str r6, [r5, #MMDC0_MADPCR0] ++ ++ ldr r6, =100000000 ++ cmp r0, r6 ++ bgt set_ddr_mu_above_100 ++ mmdc_clk_lower_100MHz ++ ++set_ddr_mu_above_100: ++ ldr r6, =24000000 ++ cmp r0, r6 ++ beq set_to_24MHz ++ ++ ldr r6, =100000000 ++ cmp r0, r6 ++ beq set_to_100MHz ++ ++ switch_to_400MHz ++ ++ mmdc_clk_above_100MHz ++ ++ b done ++ ++set_to_24MHz: ++ switch_to_24MHz ++ b done ++set_to_100MHz: ++ switch_to_100MHz ++done: ++ /* clear DVFS - exit from self refresh mode */ ++ ldr r6, [r5, #MMDC0_MAPSR] ++ bic r6, r6, #0x200000 ++ str r6, [r5, #MMDC0_MAPSR] ++ ++poll_dvfs_clear_1: ++ ldr r6, [r5, #MMDC0_MAPSR] ++ and r6, r6, #0x2000000 ++ cmp r6, #0x2000000 ++ beq poll_dvfs_clear_1 ++ ++ /* Enable Automatic power savings. */ ++ ldr r6, [r5, #MMDC0_MAPSR] ++ bic r6, r6, #0x1 ++ str r6, [r5, #MMDC0_MAPSR] ++ ++ ldr r6, =24000000 ++ cmp r0, r6 ++ beq skip_power_down ++ ++ /* Enable MMDC power down timer. */ ++ ldr r6, [r5, #MMDC0_MDPDC] ++ orr r6, r6, #0x5500 ++ str r6, [r5, #MMDC0_MDPDC] ++ ++skip_power_down: ++ /* clear SBS - unblock DDR accesses */ ++ ldr r6, [r5, #MMDC0_MADPCR0] ++ bic r6, r6, #0x100 ++ str r6, [r5, #MMDC0_MADPCR0] ++ ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* Enable L2. */ ++ ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ ldr r6, =0x1 ++ str r6, [r7, #0x100] ++#endif ++ ++ /* Enable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Restore the TTBCR */ ++ dsb ++ isb ++ ++ /* Read TTBCR and set PD0=0, N = 0 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ bic r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ dsb ++ isb ++ ++ /* Enable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ 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 ++ ++ /* Restore registers */ ++ pop {r2 - r8} ++ mov pc, lr +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mach-imx6q.c linux-3.14.72/arch/arm/mach-imx/mach-imx6q.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mach-imx6q.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/mach-imx6q.c 2016-06-19 22:11:55.053156547 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011-2013 Freescale Semiconductor, Inc. ++ * Copyright 2011-2015 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -10,17 +10,20 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -31,6 +34,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -39,6 +45,108 @@ + #include "cpuidle.h" + #include "hardware.h" + ++static struct fec_platform_data fec_pdata; ++static struct flexcan_platform_data flexcan_pdata[2]; ++static int flexcan_en_gpio; ++static int flexcan_stby_gpio; ++static int flexcan0_en; ++static int flexcan1_en; ++ ++static int ar803x_smarteee = 0; ++ ++static int __init ar803x_smarteee_setup(char *__unused) ++{ ++ ar803x_smarteee = 1; ++ return 1; ++} ++ ++__setup("ar803x_smarteee", ar803x_smarteee_setup); ++ ++ ++static void imx6q_fec_sleep_enable(int enabled) ++{ ++ struct regmap *gpr; ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ if (enabled) ++ regmap_update_bits(gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_ENET_STOP_REQ, ++ IMX6Q_GPR13_ENET_STOP_REQ); ++ else ++ regmap_update_bits(gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_ENET_STOP_REQ, 0); ++ } else ++ pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); ++} ++ ++static void __init imx6q_enet_plt_init(void) ++{ ++ struct device_node *np; ++ ++ np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000"); ++ if (np && of_get_property(np, "fsl,magic-packet", NULL)) ++ fec_pdata.sleep_mode_enable = imx6q_fec_sleep_enable; ++} ++ ++static void mx6q_flexcan_switch(void) ++{ ++ if (flexcan0_en || flexcan1_en) { ++ /* ++ * The transceiver TJA1041A on sabreauto RevE baseboard will ++ * fail to transit to Normal state if EN/STBY is high by default ++ * after board power up. So we set the EN/STBY initial state to low ++ * first then to high to guarantee the state transition successfully. ++ */ ++ gpio_set_value_cansleep(flexcan_en_gpio, 0); ++ gpio_set_value_cansleep(flexcan_stby_gpio, 0); ++ ++ gpio_set_value_cansleep(flexcan_en_gpio, 1); ++ gpio_set_value_cansleep(flexcan_stby_gpio, 1); ++ } else { ++ /* ++ * avoid to disable CAN xcvr if any of the CAN interfaces ++ * are down. XCRV will be disabled only if both CAN2 ++ * interfaces are DOWN. ++ */ ++ gpio_set_value_cansleep(flexcan_en_gpio, 0); ++ gpio_set_value_cansleep(flexcan_stby_gpio, 0); ++ } ++} ++ ++static void imx6q_flexcan0_switch_auto(int enable) ++{ ++ flexcan0_en = enable; ++ mx6q_flexcan_switch(); ++} ++ ++static void imx6q_flexcan1_switch_auto(int enable) ++{ ++ flexcan1_en = enable; ++ mx6q_flexcan_switch(); ++} ++ ++static int __init imx6q_flexcan_fixup_auto(void) ++{ ++ struct device_node *np; ++ ++ np = of_find_node_by_path("/soc/aips-bus@02000000/can@02090000"); ++ if (!np) ++ return -ENODEV; ++ ++ flexcan_en_gpio = of_get_named_gpio(np, "trx-en-gpio", 0); ++ flexcan_stby_gpio = of_get_named_gpio(np, "trx-stby-gpio", 0); ++ if (gpio_is_valid(flexcan_en_gpio) && gpio_is_valid(flexcan_stby_gpio) && ++ !gpio_request_one(flexcan_en_gpio, GPIOF_DIR_OUT, "flexcan-trx-en") && ++ !gpio_request_one(flexcan_stby_gpio, GPIOF_DIR_OUT, "flexcan-trx-stby")) { ++ /* flexcan 0 & 1 are using the same GPIOs for transceiver */ ++ flexcan_pdata[0].transceiver_switch = imx6q_flexcan0_switch_auto; ++ flexcan_pdata[1].transceiver_switch = imx6q_flexcan1_switch_auto; ++ } ++ ++ return 0; ++} ++ + /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ + static int ksz9021rn_phy_fixup(struct phy_device *phydev) + { +@@ -112,6 +220,14 @@ + { + u16 val; + ++ /* disable phy AR8031 SmartEEE function. */ ++ phy_write(dev, 0xd, 0x3); ++ phy_write(dev, 0xe, 0x805d); ++ phy_write(dev, 0xd, 0x4003); ++ val = phy_read(dev, 0xe); ++ val &= ~(0x1 << 8); ++ phy_write(dev, 0xe, val); ++ + /* To enable AR8031 output a 125MHz clk from CLK_25M */ + phy_write(dev, 0xd, 0x7); + phy_write(dev, 0xe, 0x8016); +@@ -137,20 +253,11 @@ + { + u16 val; + +- /* Ar803x phy SmartEEE feature cause link status generates glitch, +- * which cause ethernet link down/up issue, so disable SmartEEE +- */ +- phy_write(dev, 0xd, 0x3); +- phy_write(dev, 0xe, 0x805d); +- phy_write(dev, 0xd, 0x4003); +- +- val = phy_read(dev, 0xe); +- phy_write(dev, 0xe, val & ~(1 << 8)); +- + /* +- * Enable 125MHz clock from CLK_25M on the AR8031. This +- * is fed in to the IMX6 on the ENET_REF_CLK (V22) pad. +- * Also, introduce a tx clock delay. ++ * Disable SmartEEE and Enable 125MHz clock from ++ * CLK_25M on the AR8031. This is fed in to the ++ * IMX6 on the ENET_REF_CLK (V22) pad. Also, ++ * introduce a tx clock delay. + * + * This is the same as is the AR8031 fixup. + */ +@@ -161,6 +268,31 @@ + if (val & BMCR_PDOWN) + phy_write(dev, 0x0, val & ~BMCR_PDOWN); + ++ if (!ar803x_smarteee) ++ return 0; ++ ++ /* Ar803x phy SmartEEE feature cause link status generates glitch, ++ * which cause ethernet link down/up issue, so disable SmartEEE ++ */ ++ phy_write(dev, 0xd, 0x3); ++ phy_write(dev, 0xe, 0x805d); ++ phy_write(dev, 0xd, 0x4003); ++ val = phy_read(dev, 0xe); ++ val |= (0x1 << 8); ++ phy_write(dev, 0xe, val); ++ ++ /* Increase 1000BT tw time for SmartEEE. It seems that we need ++ * a bit more time than standard to git up and running. Bumping ++ * up the Tw time allows us to enable SmartEEE without generating ++ * ethernet disconnects occasionally ++ */ ++ phy_write(dev, 0xd, 0x3); ++ phy_write(dev, 0xe, 0x805b); ++ phy_write(dev, 0xd, 0x4003); ++ val = phy_read(dev, 0xe); ++ val = 0x1717; ++ phy_write(dev, 0xe, val); ++ + return 0; + } + +@@ -182,8 +314,27 @@ + + static void __init imx6q_1588_init(void) + { ++ struct device_node *np; ++ struct clk *ptp_clk; + struct regmap *gpr; + ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec"); ++ if (!np) { ++ pr_warn("%s: failed to find fec node\n", __func__); ++ return; ++ } ++ ++ ptp_clk = of_clk_get(np, 2); ++ if (IS_ERR(ptp_clk)) { ++ pr_warn("%s: failed to get ptp clock\n", __func__); ++ goto put_node; ++ } ++ ++ /* ++ * If enet_ref from ANATOP/CCM is the PTP clock source, we need to ++ * set bit IOMUXC_GPR1[21]. Or the PTP clock must be from pad ++ * (external OSC), and we need to clear the bit. ++ */ + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (!IS_ERR(gpr)) + regmap_update_bits(gpr, IOMUXC_GPR1, +@@ -192,6 +343,87 @@ + else + pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); + ++ clk_put(ptp_clk); ++put_node: ++ of_node_put(np); ++} ++ ++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__); ++ } ++} ++ ++static inline void imx6q_enet_init(void) ++{ ++ imx6_enet_mac_init("fsl,imx6q-fec"); ++ imx6q_enet_phy_init(); ++ imx6q_1588_init(); ++ imx6q_enet_plt_init(); ++} ++ ++/* Add auxdata to pass platform data */ ++static const struct of_dev_auxdata imx6q_auxdata_lookup[] __initconst = { ++ OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02090000, NULL, &flexcan_pdata[0]), ++ OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02094000, NULL, &flexcan_pdata[1]), ++ OF_DEV_AUXDATA("fsl,imx6q-fec", 0x02188000, NULL, &fec_pdata), ++ { /* sentinel */ } ++}; ++ ++static void __init imx6q_axi_init(void) ++{ ++ struct regmap *gpr; ++ unsigned int mask; ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ /* ++ * Enable the cacheable attribute of VPU and IPU ++ * AXI transactions. ++ */ ++ mask = IMX6Q_GPR4_VPU_WR_CACHE_SEL | ++ IMX6Q_GPR4_VPU_RD_CACHE_SEL | ++ IMX6Q_GPR4_VPU_P_WR_CACHE_VAL | ++ IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK | ++ IMX6Q_GPR4_IPU_WR_CACHE_CTL | ++ IMX6Q_GPR4_IPU_RD_CACHE_CTL; ++ regmap_update_bits(gpr, IOMUXC_GPR4, mask, mask); ++ ++ /* Increase IPU read QoS priority */ ++ regmap_update_bits(gpr, IOMUXC_GPR6, ++ IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK | ++ IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK, ++ (0xf << 16) | (0x7 << 20)); ++ regmap_update_bits(gpr, IOMUXC_GPR7, ++ IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK | ++ IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK, ++ (0xf << 16) | (0x7 << 20)); ++ } else { ++ pr_warn("failed to find fsl,imx6q-iomuxc-gpr regmap\n"); ++ } + } + + static void __init imx6q_init_machine(void) +@@ -207,22 +439,26 @@ + 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); ++ of_platform_populate(NULL, of_default_bus_match_table, ++ imx6q_auxdata_lookup, parent); + ++ imx6q_enet_init(); + imx_anatop_init(); +- imx6q_pm_init(); +- imx6q_1588_init(); ++ imx6q_csi_mux_init(); ++ cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); ++ imx6q_axi_init(); + } + + #define OCOTP_CFG3 0x440 + #define OCOTP_CFG3_SPEED_SHIFT 16 + #define OCOTP_CFG3_SPEED_1P2GHZ 0x3 ++#define OCOTP_CFG3_SPEED_996MHZ 0x2 ++#define OCOTP_CFG3_SPEED_852MHZ 0x1 + +-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; ++ struct dev_pm_opp *opp; + void __iomem *base; + u32 val; + +@@ -238,11 +474,50 @@ + goto put_node; + } + ++ /* ++ * SPEED_GRADING[1:0] defines the max speed of ARM: ++ * 2b'11: 1200000000Hz; ++ * 2b'10: 996000000Hz; ++ * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. ++ * 2b'00: 792000000Hz; ++ * 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"); ++ val &= 0x3; ++ ++ if (val != OCOTP_CFG3_SPEED_1P2GHZ) { ++ opp = dev_pm_opp_find_freq_exact(cpu_dev, 1200000000, true); ++ if (!IS_ERR(opp)) { ++ if (dev_pm_opp_disable(cpu_dev, 1200000000)) ++ pr_warn("failed to disable 1.2 GHz OPP\n"); ++ } ++ } ++ if (val < OCOTP_CFG3_SPEED_996MHZ) { ++ opp = dev_pm_opp_find_freq_exact(cpu_dev, 996000000, true); ++ if (!IS_ERR(opp)) { ++ if (dev_pm_opp_disable(cpu_dev, 996000000)) ++ pr_warn("failed to disable 996 MHz OPP\n"); ++ } ++ } ++ if (cpu_is_imx6q()) { ++ if (val != OCOTP_CFG3_SPEED_852MHZ) { ++ opp = dev_pm_opp_find_freq_exact(cpu_dev, 852000000, true); ++ if (!IS_ERR(opp)) { ++ if (dev_pm_opp_disable(cpu_dev, 852000000)) ++ pr_warn("failed to disable 852 MHz OPP\n"); ++ } ++ } ++ } ++ ++ if (IS_ENABLED(CONFIG_MX6_VPU_352M)) { ++ opp = dev_pm_opp_find_freq_exact(cpu_dev, 352000000, true); ++ if (!IS_ERR(opp)) { ++ if (dev_pm_opp_disable(cpu_dev, 396000000)) ++ pr_warn("failed to disable 396MHz OPP\n"); ++ pr_info("remove 396MHz OPP for VPU running at 352MHz!\n"); ++ } ++ } + + put_node: + of_node_put(np); +@@ -268,7 +543,7 @@ + goto put_node; + } + +- imx6q_opp_check_1p2ghz(cpu_dev); ++ imx6q_opp_check_speed_grading(cpu_dev); + + put_node: + of_node_put(np); +@@ -284,19 +559,27 @@ + * 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)) { + 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_flexcan_fixup_auto(); + } + + static void __init imx6q_map_io(void) + { + debug_ll_io_init(); + imx_scu_map_io(); ++ imx6_pm_map_io(); ++ imx6_busfreq_map_io(); + } + + static void __init imx6q_init_irq(void) +@@ -308,13 +591,19 @@ + irqchip_init(); + } + +-static const char *imx6q_dt_compat[] __initconst = { ++static const char *imx6q_dt_compat[] __initdata = { + "fsl,imx6dl", + "fsl,imx6q", + NULL, + }; + + 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.72.orig/arch/arm/mach-imx/mach-imx6sl.c linux-3.14.72/arch/arm/mach-imx/mach-imx6sl.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mach-imx6sl.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/mach-imx6sl.c 2016-06-19 22:11:55.053156547 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2013 Freescale Semiconductor, Inc. ++ * Copyright (C) 2013-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 +@@ -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; + +@@ -29,9 +30,14 @@ + IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK, 0); + regmap_update_bits(gpr, IOMUXC_GPR1, + IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK, 0); +- } else { ++ } else + pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n"); +- } ++} ++ ++static inline void imx6sl_fec_init(void) ++{ ++ imx6sl_fec_clk_init(); ++ imx6_enet_mac_init("fsl,imx6sl-fec"); + } + + static void __init imx6sl_init_late(void) +@@ -39,6 +45,8 @@ + /* imx6sl reuses imx6q cpufreq driver */ + if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) + platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); ++ ++ imx6sl_cpuidle_init(); + } + + static void __init imx6sl_init_machine(void) +@@ -55,8 +63,7 @@ + + imx6sl_fec_init(); + imx_anatop_init(); +- /* Reuse imx6q pm code */ +- imx6q_pm_init(); ++ imx6sl_pm_init(); + } + + static void __init imx6sl_init_irq(void) +@@ -73,8 +80,15 @@ + NULL, + }; + ++static void __init imx6sl_map_io(void) ++{ ++ debug_ll_io_init(); ++ imx6_pm_map_io(); ++ imx6_busfreq_map_io(); ++} ++ + DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)") +- .map_io = debug_ll_io_init, ++ .map_io = imx6sl_map_io, + .init_irq = imx6sl_init_irq, + .init_machine = imx6sl_init_machine, + .init_late = imx6sl_init_late, +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mach-imx6sx.c linux-3.14.72/arch/arm/mach-imx/mach-imx6sx.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mach-imx6sx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mach-imx6sx.c 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,340 @@ ++/* ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "cpuidle.h" ++ ++static struct fec_platform_data fec_pdata[2]; ++static struct flexcan_platform_data flexcan_pdata[2]; ++static int flexcan_en_gpio; ++static int flexcan_en_active_high; ++static int flexcan_stby_gpio; ++static int flexcan_stby_active_high; ++static int flexcan0_en; ++static int flexcan1_en; ++ ++static void imx6sx_fec1_sleep_enable(int enabled) ++{ ++ struct regmap *gpr; ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ if (enabled) ++ regmap_update_bits(gpr, IOMUXC_GPR4, ++ IMX6SX_GPR4_FEC_ENET1_STOP_REQ, ++ IMX6SX_GPR4_FEC_ENET1_STOP_REQ); ++ else ++ regmap_update_bits(gpr, IOMUXC_GPR4, ++ IMX6SX_GPR4_FEC_ENET1_STOP_REQ, 0); ++ } else ++ pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n"); ++} ++ ++static void imx6sx_fec2_sleep_enable(int enabled) ++{ ++ struct regmap *gpr; ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ if (enabled) ++ regmap_update_bits(gpr, IOMUXC_GPR4, ++ IMX6SX_GPR4_FEC_ENET2_STOP_REQ, ++ IMX6SX_GPR4_FEC_ENET2_STOP_REQ); ++ else ++ regmap_update_bits(gpr, IOMUXC_GPR4, ++ IMX6SX_GPR4_FEC_ENET2_STOP_REQ, 0); ++ } else ++ pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n"); ++} ++ ++static void __init imx6sx_enet_plt_init(void) ++{ ++ struct device_node *np; ++ ++ np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000"); ++ if (np && of_get_property(np, "fsl,magic-packet", NULL)) ++ fec_pdata[0].sleep_mode_enable = imx6sx_fec1_sleep_enable; ++ np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@021b4000"); ++ if (np && of_get_property(np, "fsl,magic-packet", NULL)) ++ fec_pdata[1].sleep_mode_enable = imx6sx_fec2_sleep_enable; ++} ++ ++static void mx6sx_flexcan_switch(void) ++{ ++ if (flexcan0_en || flexcan1_en) { ++ gpio_set_value_cansleep(flexcan_en_gpio, ++ !flexcan_en_active_high); ++ gpio_set_value_cansleep(flexcan_stby_gpio, ++ !flexcan_stby_active_high); ++ gpio_set_value_cansleep(flexcan_en_gpio, ++ flexcan_en_active_high); ++ gpio_set_value_cansleep(flexcan_stby_gpio, ++ flexcan_stby_active_high); ++ } else { ++ /* ++ * avoid to disable CAN xcvr if any of the CAN interfaces ++ * are down. XCRV will be disabled only if both CAN2 ++ * interfaces are DOWN. ++ */ ++ gpio_set_value_cansleep(flexcan_en_gpio, ++ !flexcan_en_active_high); ++ gpio_set_value_cansleep(flexcan_stby_gpio, ++ !flexcan_stby_active_high); ++ } ++} ++ ++static void imx6sx_arm2_flexcan0_switch(int enable) ++{ ++ flexcan0_en = enable; ++ mx6sx_flexcan_switch(); ++} ++ ++static void imx6sx_arm2_flexcan1_switch(int enable) ++{ ++ flexcan1_en = enable; ++ mx6sx_flexcan_switch(); ++} ++ ++static int __init imx6sx_arm2_flexcan_fixup(void) ++{ ++ struct device_node *np; ++ enum of_gpio_flags en_flags, stby_flags; ++ bool canfd_en = false; ++ int wakeup_gpio; ++ ++ np = of_find_node_by_path("/soc/aips-bus@02000000/can@02090000"); ++ if (!np) ++ return -ENODEV; ++ ++ ++ /* Wakeup transceiver first in case it's in sleep mode by default */ ++ wakeup_gpio = of_get_named_gpio(np, "trx-wakeup-gpio", 0); ++ if (gpio_is_valid(wakeup_gpio) && ++ !gpio_request_one(wakeup_gpio, GPIOF_OUT_INIT_HIGH, "flexcan-trx-wakeup")) { ++ gpio_set_value_cansleep(wakeup_gpio, 0); ++ gpio_set_value_cansleep(wakeup_gpio, 1); ++ } ++ ++ flexcan_en_gpio = of_get_named_gpio_flags(np, "trx-en-gpio", 0, &en_flags); ++ flexcan_stby_gpio = of_get_named_gpio_flags(np, "trx-stby-gpio", 0, &stby_flags); ++ ++ if (gpio_is_valid(flexcan_en_gpio) && gpio_is_valid(flexcan_stby_gpio) && ++ !gpio_request_one(flexcan_en_gpio, GPIOF_DIR_OUT, "flexcan-trx-en") && ++ !gpio_request_one(flexcan_stby_gpio, GPIOF_DIR_OUT, "flexcan-trx-stby")) { ++ /* flexcan 0 & 1 are using the same GPIOs for transceiver */ ++ flexcan_pdata[0].transceiver_switch = imx6sx_arm2_flexcan0_switch; ++ flexcan_pdata[1].transceiver_switch = imx6sx_arm2_flexcan1_switch; ++ if (!(en_flags & OF_GPIO_ACTIVE_LOW)) ++ flexcan_en_active_high = 1; ++ ++ if (!(stby_flags & OF_GPIO_ACTIVE_LOW)) ++ flexcan_stby_active_high = 1; ++ } ++ ++ /* ++ * Switch on the transceiver by default for board with canfd enabled ++ * since canfd driver does not handle it. ++ * Two CAN instances share the same switch. ++ */ ++ for_each_node_by_name(np, "canfd") { ++ if (of_device_is_available(np)) { ++ canfd_en = true; ++ break; ++ } ++ } ++ ++ if (of_machine_is_compatible("fsl,imx6sx-sdb") && canfd_en) ++ imx6sx_arm2_flexcan0_switch(1); ++ ++ return 0; ++} ++ ++static int ar8031_phy_fixup(struct phy_device *dev) ++{ ++ u16 val; ++ ++ /* Set RGMII IO voltage to 1.8V */ ++ phy_write(dev, 0x1d, 0x1f); ++ phy_write(dev, 0x1e, 0x8); ++ ++ /* disable phy AR8031 SmartEEE function. */ ++ phy_write(dev, 0xd, 0x3); ++ phy_write(dev, 0xe, 0x805d); ++ phy_write(dev, 0xd, 0x4003); ++ val = phy_read(dev, 0xe); ++ val &= ~(0x1 << 8); ++ phy_write(dev, 0xe, val); ++ ++ /* introduce tx clock delay */ ++ phy_write(dev, 0x1d, 0x5); ++ val = phy_read(dev, 0x1e); ++ val |= 0x0100; ++ phy_write(dev, 0x1e, val); ++ return 0; ++} ++ ++#define PHY_ID_AR8031 0x004dd074 ++static void __init imx6sx_enet_phy_init(void) ++{ ++ if (IS_BUILTIN(CONFIG_PHYLIB)) ++ phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, ++ ar8031_phy_fixup); ++} ++ ++static void __init imx6sx_enet_clk_sel(void) ++{ ++ struct regmap *gpr; ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ regmap_update_bits(gpr, IOMUXC_GPR1, ++ IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK, 0); ++ regmap_update_bits(gpr, IOMUXC_GPR1, ++ IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK, 0); ++ } else { ++ pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n"); ++ } ++} ++ ++static inline void imx6sx_enet_init(void) ++{ ++ imx6_enet_mac_init("fsl,imx6sx-fec"); ++ imx6sx_enet_phy_init(); ++ imx6sx_enet_clk_sel(); ++ imx6sx_enet_plt_init(); ++} ++ ++/* Add auxdata to pass platform data */ ++static const struct of_dev_auxdata imx6sx_auxdata_lookup[] __initconst = { ++ OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02090000, NULL, &flexcan_pdata[0]), ++ OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02094000, NULL, &flexcan_pdata[1]), ++ OF_DEV_AUXDATA("fsl,imx6sx-fec", 0x02188000, NULL, &fec_pdata[0]), ++ OF_DEV_AUXDATA("fsl,imx6sx-fec", 0x021b4000, NULL, &fec_pdata[1]), ++ { /* sentinel */ } ++}; ++ ++static inline void imx6sx_qos_init(void) ++{ ++ struct device_node *np; ++ void __iomem *src_base; ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-gpu"); ++ if (!np || !of_device_is_available(np)) ++ return; ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-qosc"); ++ if (!np) ++ return; ++ src_base = of_iomap(np, 0); ++ writel_relaxed(0, src_base); /* Disable clkgate & soft_rst */ ++ writel_relaxed(0, src_base+0x60); /* Enable all masters */ ++ writel_relaxed(0, src_base+0x1400); /* Disable clkgate & soft_rst for gpu */ ++ writel_relaxed(0x0f000222, src_base+0x1400+0xd0); /* Set Write QoS 2 for gpu */ ++ writel_relaxed(0x0f000822, src_base+0x1400+0xe0); /* Set Read QoS 8 for gpu */ ++ return; ++} ++ ++static void __init imx6sx_init_machine(void) ++{ ++ struct device *parent; ++ ++ mxc_arch_reset_init_dt(); ++ ++ parent = imx_soc_device_init(); ++ if (parent == NULL) ++ pr_warn("failed to initialize soc device\n"); ++ ++ of_platform_populate(NULL, of_default_bus_match_table, ++ imx6sx_auxdata_lookup, parent); ++ ++ imx6sx_enet_init(); ++ imx_anatop_init(); ++ imx6sx_pm_init(); ++ imx6sx_qos_init(); ++} ++ ++static void __init imx6sx_init_irq(void) ++{ ++ imx_init_revision_from_anatop(); ++ imx_init_l2cache(); ++ imx_src_init(); ++ imx_gpc_init(); ++ irqchip_init(); ++} ++ ++static const char *imx6sx_dt_compat[] __initdata = { ++ "fsl,imx6sx", ++ NULL, ++}; ++ ++static void __init imx6sx_opp_init(struct device *cpu_dev) ++{ ++ struct device_node *np; ++ ++ np = of_find_node_by_path("/cpus/cpu@0"); ++ if (!np) { ++ pr_warn("failed to find cpu0 node\n"); ++ return; ++ } ++ ++ cpu_dev->of_node = np; ++ if (of_init_opp_table(cpu_dev)) ++ pr_warn("failed to init OPP table\n"); ++ ++ of_node_put(np); ++} ++ ++static struct platform_device imx6sx_cpufreq_pdev = { ++ .name = "imx6q-cpufreq", ++}; ++ ++static void __init imx6sx_init_late(void) ++{ ++ if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) { ++ imx6sx_opp_init(&imx6sx_cpufreq_pdev.dev); ++ platform_device_register(&imx6sx_cpufreq_pdev); ++ } ++ ++ if (of_machine_is_compatible("fsl,imx6sx-sdb") || ++ of_machine_is_compatible("fsl,imx6sx-sabreauto")) ++ imx6sx_arm2_flexcan_fixup(); ++ ++ imx6sx_cpuidle_init(); ++} ++ ++static void __init imx6sx_map_io(void) ++{ ++ debug_ll_io_init(); ++ imx6_pm_map_io(); ++ imx6_busfreq_map_io(); ++} ++ ++DT_MACHINE_START(IMX6SX, "Freescale i.MX6 SoloX (Device Tree)") ++ .map_io = imx6sx_map_io, ++ .init_irq = imx6sx_init_irq, ++ .init_machine = imx6sx_init_machine, ++ .init_late = imx6sx_init_late, ++ .dt_compat = imx6sx_dt_compat, ++ .restart = mxc_restart, ++MACHINE_END +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mach-vf610.c linux-3.14.72/arch/arm/mach-imx/mach-vf610.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mach-vf610.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/mach-vf610.c 2016-06-19 22:11:55.053156547 +0200 +@@ -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.72.orig/arch/arm/mach-imx/Makefile linux-3.14.72/arch/arm/mach-imx/Makefile +--- linux-3.14.72.orig/arch/arm/mach-imx/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/Makefile 2016-06-19 22:11:55.053156547 +0200 +@@ -16,7 +16,8 @@ + + obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ + clk-pfd.o clk-busy.o clk.o \ +- clk-fixup-div.o clk-fixup-mux.o ++ clk-fixup-div.o clk-fixup-mux.o \ ++ clk-gate-exclusive.o + + obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o + obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o +@@ -30,6 +31,8 @@ + 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 ++obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o + endif + + ifdef CONFIG_SND_IMX_SOC +@@ -95,15 +98,34 @@ + obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o + obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o + obj-$(CONFIG_HAVE_IMX_SRC) += src.o ++obj-$(CONFIG_HAVE_IMX_MCC) += mcc_api.o mcc_common.o mcc_linux.o mcc_imx6sx.o + AFLAGS_headsmp.o :=-Wa,-march=armv7-a + obj-$(CONFIG_SMP) += headsmp.o platsmp.o + obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +-obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o +-obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o ++obj-$(CONFIG_SOC_IMX6Q) += common-imx6.o clk-imx6q.o mach-imx6q.o ++obj-$(CONFIG_SOC_IMX6SL) += common-imx6.o clk-imx6sl.o mach-imx6sl.o ++obj-$(CONFIG_SOC_IMX6SX) += common-imx6.o clk-imx6sx.o mach-imx6sx.o mu.o ++ ++ifeq ($(CONFIG_SUSPEND),y) ++AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a ++obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o ++endif ++obj-$(CONFIG_SOC_IMX6) += pm-imx6.o ++ ++ifeq ($(CONFIG_ARM_IMX6Q_CPUFREQ),y) ++obj-y += busfreq-imx6.o ++AFLAGS_ddr3_freq_imx6.o :=-Wa,-march=armv7-a ++obj-$(CONFIG_SOC_IMX6Q) += ddr3_freq_imx6.o busfreq_ddr3.o ++AFLAGS_lpddr2_freq_imx6.o :=-Wa,-march=armv7-a ++AFLAGS_imx6sl_lpm_wfi.o :=-Wa,-march=armv7-a ++obj-$(CONFIG_SOC_IMX6SL) += busfreq_lpddr2.o lpddr2_freq_imx6.o imx6sl_lpm_wfi.o ++AFLAGS_lpddr2_freq_imx6sx.o :=-Wa,-march=armv7-a ++AFLAGS_ddr3_freq_imx6sx.o :=-Wa,-march=armv7-a ++AFLAGS_imx6sx_low_power_idle.o :=-Wa,-march=armv7-a ++obj-$(CONFIG_SOC_IMX6SX) += ddr3_freq_imx6sx.o busfreq_ddr3.o lpddr2_freq_imx6sx.o \ ++ imx6sx_low_power_idle.o busfreq_lpddr2.o lpddr2_freq_imx6.o ++endif + +-obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o +-# i.MX6SL reuses i.MX6Q code +-obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o + + # i.MX5 based machines + obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mcc_api.c linux-3.14.72/arch/arm/mach-imx/mcc_api.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mcc_api.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mcc_api.c 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,951 @@ ++/* ++ * This file contains MCC library API functions implementation ++ * ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * ++ * SPDX-License-Identifier: GPL-2.0+ and/or BSD-3-Clause ++ * The GPL-2.0+ license for this file can be found in the COPYING.GPL file ++ * included with this distribution or at ++ * http://www.gnu.org/licenses/gpl-2.0.html ++ * The BSD-3-Clause License for this file can be found in the COPYING.BSD file ++ * included with this distribution or at ++ * http://opensource.org/licenses/BSD-3-Clause ++ */ ++ ++#include "mcc_config.h" ++#if (MCC_OS_USED == MCC_MQX) ++#include ++#include "mcc_config.h" ++#include "mcc_common.h" ++#include "mcc_api.h" ++#include "mcc_mqx.h" ++#elif (MCC_OS_USED == MCC_LINUX) ++#include ++#include ++#include ++#include ++#endif ++ ++const char * const init_string = MCC_INIT_STRING; ++const char * const version_string = MCC_VERSION_STRING; ++ ++static int mcc_recv_common_part(MCC_ENDPOINT *endpoint, unsigned int timeout_ms, MCC_RECEIVE_LIST **list); ++static int mcc_get_buffer_internal(void **buffer, MCC_MEM_SIZE *buf_size, unsigned int timeout_ms); ++static int mcc_free_buffer_internal(void *buffer); ++/*! ++ * \brief This function initializes the Multi Core Communication subsystem for a given node. ++ * ++ * This function should only be called once per node (once in MQX, once per a process in Linux). ++ * It tries to initialize the bookkeeping structure when the init_string member of this structure ++ * is not equal to MCC_INIT_STRING, i.e. when no other core had performed the initialization yet. ++ * Note, that this way of bookkeeping data re-initialization protection is not powerful enough and ++ * the user application should not rely on this method. Instead, the application should be designed ++ * to unambiguously assign the core that will perform the MCC initialization. ++ * Clear the shared memory before the first core is attempting to initialize the MCC ++ * (in some cases MCC_INIT_STRING remains in the shared memory after the application reset and could ++ * cause that the bookkeeping data structure is not initialized correctly). ++ * ++ * \param[in] node Node number that will be used in endpoints created by this process. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_INT (interrupt registration error) ++ * \return MCC_ERR_VERSION (incorrect MCC version used - compatibility issue) ++ * \return MCC_ERR_OSSYNC (OS synchronization module(s) initialization failed) ++ * ++ * \see mcc_destroy ++ * \see MCC_BOOKEEPING_STRUCT ++ */ ++int mcc_initialize(MCC_NODE node) ++{ ++ int i,j = 0; ++ int return_value = MCC_SUCCESS; ++ MCC_SIGNAL tmp_signals_received = {(MCC_SIGNAL_TYPE)0, {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0}}; ++ ++ /* Initialize synchronization module for shared data protection */ ++ return_value = mcc_init_semaphore(MCC_SHMEM_SEMAPHORE_NUMBER); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Initialize all necessary OS synchronization module(s) ++ (for unblocking tasks waiting for new received data and for unblocking tasks waiting for a free buffer) */ ++ return_value = mcc_init_os_sync(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Register CPU-to-CPU interrupt for inter-core signaling */ ++ //mcc_register_cpu_to_cpu_isr(MCC_CORE0_CPU_TO_CPU_VECTOR); ++ return_value = mcc_register_cpu_to_cpu_isr(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Initialize the bookeeping structure */ ++ bookeeping_data = (MCC_BOOKEEPING_STRUCT *)mcc_get_bookeeping_data(); ++ MCC_DCACHE_INVALIDATE_MLINES(bookeeping_data, sizeof(MCC_BOOKEEPING_STRUCT)); ++ if(strcmp(bookeeping_data->init_string, init_string) != 0) { ++ /* MCC not initialized yet, do it now */ ++ /* Zero it all - no guarantee Linux or uboot didnt touch it before it was reserved */ ++ memset((void*) bookeeping_data, 0, sizeof(struct mcc_bookeeping_struct)); ++ ++ /* Set init_string in case it has not been set yet by another core */ ++ mcc_memcpy((void*)init_string, bookeeping_data->init_string, (unsigned int)sizeof(bookeeping_data->init_string)); ++ ++ /* Set version_string */ ++ mcc_memcpy((void*)version_string, bookeeping_data->version_string, (unsigned int)sizeof(bookeeping_data->version_string)); ++ ++ /* Initialize the free list */ ++ bookeeping_data->free_list.head = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(&bookeeping_data->r_buffers[0]); ++ bookeeping_data->free_list.tail = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(&bookeeping_data->r_buffers[MCC_ATTR_NUM_RECEIVE_BUFFERS-1]); ++ ++ /* Initialize receive buffers */ ++ for(i=0; ir_buffers[i].next = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(&bookeeping_data->r_buffers[i+1]); ++ } ++ bookeeping_data->r_buffers[MCC_ATTR_NUM_RECEIVE_BUFFERS-1].next = null; ++ ++ /* Initialize signal queues */ ++ for(i=0; isignals_received[i][j] = tmp_signals_received; ++ } ++ bookeeping_data->signal_queue_head[i] = 0; ++ bookeeping_data->signal_queue_tail[i] = 0; ++ } ++ ++ /* Mark all endpoint ports as free */ ++ for(i=0; iendpoint_table[i].endpoint.port = MCC_RESERVED_PORT_NUMBER; ++ } ++ } ++ else { ++ /* MCC already initialized - check the major number of the version string to ensure compatibility */ ++ if(strncmp(bookeeping_data->version_string, version_string, 4) != 0) { ++ return_value = MCC_ERR_VERSION; ++ } ++ } ++ ++ MCC_DCACHE_FLUSH_MLINES(bookeeping_data, sizeof(MCC_BOOKEEPING_STRUCT)); ++ return return_value; ++} ++ ++/*! ++ * \brief This function de-initializes the Multi Core Communication subsystem for a given node. ++ * ++ * The function frees all resources of the node. Deletes all endpoints and frees any buffers that may have been queued there. ++ * ++ * \param[in] node Node number to be deinitialized. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_OSSYNC (OS synchronization module(s) deinitialization failed) ++ * ++ * \see mcc_initialize ++ */ ++int mcc_destroy(MCC_NODE node) ++{ ++ int i = 0, return_value; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* All endpoints of the particular node have to be removed from the endpoint table */ ++ MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM)); ++ for(i = 0; i < MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) { ++ if (bookeeping_data->endpoint_table[i].endpoint.node == node) { ++ /* Remove the endpoint from the table */ ++ mcc_remove_endpoint(bookeeping_data->endpoint_table[i].endpoint); ++ } ++ } ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Deinitialize synchronization module */ ++ mcc_deinit_semaphore(MCC_SHMEM_SEMAPHORE_NUMBER); ++ ++ /* De-initialize OS synchronization module(s) ++ (for unblocking tasks waiting for new data and for unblocking tasks waiting for a free buffer */ ++ return_value = mcc_deinit_os_sync(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ return return_value; ++} ++ ++/*! ++ * \brief This function creates an endpoint. ++ * ++ * The function creates an endpoint on the local node with the specified port number. ++ * The core and node provided in the endpoint must match the caller's core and ++ * node, and the port argument must match the endpoint port. ++ * ++ * \param[out] endpoint Pointer to the endpoint triplet to be created. ++ * \param[in] port Port number. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_NOMEM (maximum number of endpoints exceeded) ++ * \return MCC_ERR_ENDPOINT (invalid value for port or endpoint already registered) ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * ++ * \see mcc_destroy_endpoint ++ * \see MCC_ENDPOINT ++ */ ++int mcc_create_endpoint(MCC_ENDPOINT *endpoint, MCC_PORT port) ++{ ++ int return_value = MCC_SUCCESS; ++ ++ /* Fill the endpoint structure */ ++ endpoint->core = (MCC_CORE)MCC_CORE_NUMBER; ++ endpoint->node = (MCC_NODE)MCC_NODE_NUMBER; ++ endpoint->port = (MCC_PORT)port; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Add new endpoint data into the book-keeping structure */ ++ return_value = mcc_register_endpoint(*endpoint); ++ if(return_value != MCC_SUCCESS) { ++ mcc_release_semaphore(); ++ return return_value; ++ } ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ return return_value; ++} ++ ++/*! ++ * \brief This function destroys an endpoint. ++ * ++ * The function destroys an endpoint on the local node and frees any buffers that may be queued. ++ * ++ * \param[in] endpoint Pointer to the endpoint triplet to be deleted. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_ENDPOINT (the endpoint doesn't exist) ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * ++ * \see mcc_create_endpoint ++ * \see MCC_ENDPOINT ++ */ ++int mcc_destroy_endpoint(MCC_ENDPOINT *endpoint) ++{ ++ int return_value = MCC_SUCCESS; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Remove the endpoint data from the book-keeping structure */ ++ return_value = mcc_remove_endpoint(*endpoint); ++ if(return_value != MCC_SUCCESS) { ++ mcc_release_semaphore(); ++ return return_value; ++ } ++ ++ /* Clear OS synchronization module parts associated with the endpoint to be destroyed */ ++ mcc_clear_os_sync_for_ep(endpoint); ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ return return_value; ++} ++ ++/*! ++ * \brief This function sends a message to an endpoint. ++ * ++ * The message is copied into the MCC buffer and the destination core is signaled. ++ * ++ * \param[in] src_endpoint Pointer to the local endpoint identifying the source endpoint. ++ * \param[in] dest_endpoint Pointer to the destination endpoint to send the message to. ++ * \param[in] msg Pointer to the message to be sent. ++ * \param[in] msg_size Size of the message to be sent in bytes. ++ * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_ENDPOINT (the endpoint does not exist) ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer) ++ * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available) ++ * \return MCC_ERR_NOMEM (no free buffer available and timeout_ms set to 0) ++ * \return MCC_ERR_SQ_FULL (signal queue is full) ++ * ++ * \see mcc_recv ++ * \see mcc_recv_nocopy ++ * \see MCC_ENDPOINT ++ */ ++int mcc_send(MCC_ENDPOINT *src_endpoint, MCC_ENDPOINT *dest_endpoint, void *msg, MCC_MEM_SIZE msg_size, unsigned int timeout_ms) ++{ ++ int return_value; ++ MCC_RECEIVE_LIST *list; ++ MCC_RECEIVE_BUFFER * buf; ++ MCC_SIGNAL affiliated_signal; ++ MCC_MEM_SIZE buffer_size; ++ ++ /* Reuse the mcc_get_buffer_internal() function to get the MCC buffer pointer. */ ++ return_value = mcc_get_buffer_internal((void**)&buf, &buffer_size, timeout_ms); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */ ++ if(msg_size > buffer_size) { ++ while(MCC_SUCCESS != mcc_free_buffer_internal(buf)) {}; ++ return MCC_ERR_INVAL; ++ } ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* As the mcc_get_buffer_internal() returns the pointer to the data field, it ++ is necessary to adjust the pointer to point at the MCC buffer structure beginning. */ ++ buf = (MCC_RECEIVE_BUFFER *)((unsigned int)buf - (unsigned int)(&(((MCC_RECEIVE_BUFFER*)0)->data))); ++ ++ /* Copy the message into the MCC receive buffer */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)buf, sizeof(MCC_RECEIVE_BUFFER)); ++ mcc_memcpy(msg, (void*)buf->data, (unsigned int)msg_size); ++ mcc_memcpy((void*)src_endpoint, (void*)&buf->source, sizeof(MCC_ENDPOINT)); ++ buf->data_len = msg_size; ++ MCC_DCACHE_FLUSH_MLINES((void*)buf, sizeof(MCC_RECEIVE_BUFFER)); ++ ++ /* Get list of buffers kept by the particular endpoint */ ++ list = mcc_get_endpoint_list(*dest_endpoint); ++ ++ if(list == null) { ++ /* The endpoint does not exists (has not been registered so far), ++ free the buffer and return immediately - error */ ++ /* Enqueue the buffer back into the free list */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); ++ mcc_queue_buffer(&bookeeping_data->free_list, buf); ++ ++ mcc_release_semaphore(); ++ return MCC_ERR_ENDPOINT; ++ } ++ ++ /* Write the signal type into the signal queue of the particular core */ ++ affiliated_signal.type = BUFFER_QUEUED; ++ affiliated_signal.destination = *dest_endpoint; ++ return_value = mcc_queue_signal(dest_endpoint->core, affiliated_signal); ++ if(return_value != MCC_SUCCESS) { ++ /* Signal queue is full, free the buffer and return immediately - error */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); ++ mcc_queue_buffer(&bookeeping_data->free_list, buf); ++ ++ mcc_release_semaphore(); ++ return return_value; ++ } ++ ++ /* Enqueue the buffer into the endpoint buffer list */ ++ mcc_queue_buffer(list, buf); ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Signal the other core by generating the CPU-to-CPU interrupt */ ++ return_value = mcc_generate_cpu_to_cpu_interrupt(); ++ ++ return return_value; ++} ++ ++/*! ++ * \private ++ * ++ * \brief This function dequeues a buffer from the free list. ++ * ++ * This is an internal implementation of the mcc_get_buffer() function. It is called ++ * either from the mcc_send() or from mcc_get_buffer() when the non-copy-send ++ * mechanism is enabled by the MCC_SEND_RECV_NOCOPY_API_ENABLED macro in mcc_config.h. ++ * ++ * \param[out] buffer Pointer to the MCC buffer dequeued from the free list. ++ * \param[out] buf_size Pointer to an MCC_MEM_SIZE that is used for passing the size of the dequeued MCC buffer to the application. ++ * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available) ++ * \return MCC_ERR_NOMEM (no free buffer available and timeout_ms set to 0) ++ * ++ * \see mcc_send_nocopy ++ * \see mcc_send ++ * \see mcc_get_buffer ++ */ ++static int mcc_get_buffer_internal(void **buffer, MCC_MEM_SIZE *buf_size, unsigned int timeout_ms) ++{ ++ int return_value; ++ MCC_RECEIVE_BUFFER * buf = null; ++ ++ *buffer = null; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Dequeue the buffer from the free list */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); ++ buf = mcc_dequeue_buffer(&bookeeping_data->free_list); ++ ++ /* Semaphore-protected section end */ ++ mcc_release_semaphore(); ++ ++ if(buf == null) { ++ /* Non-blocking call */ ++ if(timeout_ms == 0) { ++ return MCC_ERR_NOMEM; ++ } else { ++ /* Wait for the buffer freed event */ ++ return_value = mcc_wait_for_buffer_freed((MCC_RECEIVE_BUFFER **)&buf, timeout_ms); ++ if(MCC_SUCCESS != return_value) { ++ return return_value; ++ } ++ } ++ } ++ ++ /* Return the MCC buffer size and the pointer to the dequeued MCC buffer */ ++ *buf_size = (MCC_MEM_SIZE)sizeof(bookeeping_data->r_buffers[0].data); ++ *buffer = (void*)buf->data; ++ return MCC_SUCCESS; ++} ++ ++#if MCC_SEND_RECV_NOCOPY_API_ENABLED ++/*! ++ * \brief This function dequeues a buffer from the free list. ++ * ++ * The application has take the responsibility for MCC buffer de-allocation and ++ * filling the data to be sent into the pre-allocated MCC buffer. ++ * ++ * \param[out] buffer Pointer to the MCC buffer dequeued from the free list. ++ * \param[out] buf_size Pointer to an MCC_MEM_SIZE that is used for passing the size of the dequeued MCC buffer to the application. ++ * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available) ++ * \return MCC_ERR_NOMEM (no free buffer available and timeout_ms set to 0) ++ * ++ * \see mcc_send_nocopy ++ */ ++int mcc_get_buffer(void **buffer, MCC_MEM_SIZE *buf_size, unsigned int timeout_ms) ++{ ++ return mcc_get_buffer_internal(buffer, buf_size, timeout_ms); ++} ++ ++/*! ++ * \brief This function sends a message to an endpoint. The data is NOT copied ++ * from the user-app. buffer but the pointer to already filled message buffer is ++ * provided. ++ * ++ * The application has to take the responsibility for: ++ * 1. MCC buffer de-allocation ++ * 2. filling the data to be sent into the pre-allocated MCC buffer ++ * 3. not exceeding the buffer size when filling the data (MCC_ATTR_BUFFER_SIZE_IN_BYTES) ++ * ++ * Once the data cache is used on the target platform it is good to have MCC buffers ++ * in shared RAM aligned to the cache line size in order not to corrupt entities placed ++ * just before and just after the MCC buffer when flushing the MCC buffer content into ++ * the shared RAM. It is also the application responsibility to flush the data in ++ * that case. If the alignment condition is not fulfilled the application ++ * has to take care about the data cache coherency. ++ * The following scenarios can happen: ++ * A. Data cache is OFF: ++ * - No cache operation needs to be done, the application just ++ * 1. calls the mcc_get_buffer() function, ++ * 2. fills data into the provided MCC buffer, ++ * 3. and finally issues the mcc_send_nocopy() function. ++ * B. Data cache is ON, shared RAM MCC buffers ALIGNED to the cache line size: ++ * - The application has to perform following steps: ++ * 1. call the mcc_get_buffer() to get the pointer to a free message buffer ++ * 2. copy data to be sent into the message buffer ++ * 3. flush all cache lines occupied by the message buffer new data ++ * (maximum of MCC_ATTR_BUFFER_SIZE_IN_BYTES bytes). ++ * 4. call the mcc_send_nocopy() with the correct buffer pointer and the message size passed ++ * C. Data cache is ON, shared RAM MCC buffers NOT ALIGNED: ++ * - The application has to perform following steps: ++ * 1. call the mcc_get_buffer() to get the pointer to a free message buffer ++ * 2. grab the hw semaphore by calling the mcc_get_semaphore() low level MCC function. ++ * 3. invalidate all cache lines occupied by data to be filled into the free message buffer. ++ * (maximum of MCC_ATTR_BUFFER_SIZE_IN_BYTES bytes). ++ * 4. copy data to be sent into the message buffer. ++ * 5. flush all cache lines occupied by the message buffer new data ++ * (maximum of MCC_ATTR_BUFFER_SIZE_IN_BYTES bytes). ++ * 6. release the hw semaphore by calling the mcc_release_semaphore() low level MCC function. ++ * 7. call the mcc_send_nocopy() with the correct buffer pointer and the message size passed. ++ * ++ * After the mcc_send_nocopy() function is issued the message buffer is no more owned ++ * by the sending task and must not be touched anymore unless the mcc_send_nocopy() ++ * function fails and returns an error. In that case the application should try ++ * to re-issue the mcc_send_nocopy() again and if it is still not possible to send ++ * the message and the application wants to give it up from whatever reasons ++ * (for instance the MCC_ERR_ENDPOINT error is returned meaning the endpoint ++ * has not been created yet) the mcc_free_buffer() function could be called, ++ * passing the pointer to the buffer to be freed as a parameter. ++ * ++ * \param[in] src_endpoint Pointer to the local endpoint identifying the source endpoint. ++ * \param[in] dest_endpoint Pointer to the destination endpoint to send the message to. ++ * \param[in] buffer_p Pointer to the MCC buffer of the shared memory where the ++ * data to be sent is stored. ++ * \param[in] msg_size Size of the message to be sent in bytes. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer) ++ * \return MCC_ERR_ENDPOINT (the endpoint does not exist) ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_SQ_FULL (signal queue is full) ++ * ++ * \see mcc_send ++ * \see mcc_get_buffer ++ * \see MCC_ENDPOINT ++ */ ++int mcc_send_nocopy(MCC_ENDPOINT *src_endpoint, MCC_ENDPOINT *dest_endpoint, void *buffer_p, MCC_MEM_SIZE msg_size) ++{ ++ int return_value; ++ MCC_RECEIVE_BUFFER * buf; ++ MCC_RECEIVE_LIST *list; ++ MCC_SIGNAL affiliated_signal; ++ ++ /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */ ++ if(msg_size > sizeof(bookeeping_data->r_buffers[0].data)) { ++ return MCC_ERR_INVAL; ++ } ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Get list of buffers kept by the particular endpoint */ ++ list = mcc_get_endpoint_list(*dest_endpoint); ++ ++ if(list == null) { ++ /* The endpoint does not exists (has not been registered so far) */ ++ mcc_release_semaphore(); ++ return MCC_ERR_ENDPOINT; ++ } ++ ++ /* Store the message size and the source endpoint in the MCC_RECEIVE_BUFFER structure */ ++ buf = (MCC_RECEIVE_BUFFER *)((unsigned int)buffer_p - (unsigned int)(&(((MCC_RECEIVE_BUFFER*)0)->data))); ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&buf->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE)); ++ ((MCC_RECEIVE_BUFFER*)buf)->data_len = msg_size; ++ mcc_memcpy((void*)src_endpoint, (void*)&buf->source, sizeof(MCC_ENDPOINT)); ++ MCC_DCACHE_FLUSH_MLINES((void*)(void*)&buf->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE)); ++ ++ ++ /* Write the signal type into the signal queue of the particular core */ ++ affiliated_signal.type = BUFFER_QUEUED; ++ affiliated_signal.destination = *dest_endpoint; ++ return_value = mcc_queue_signal(dest_endpoint->core, affiliated_signal); ++ if(return_value != MCC_SUCCESS) { ++ /* Signal queue is full - error */ ++ mcc_release_semaphore(); ++ return return_value; ++ } ++ ++ /* Enqueue the buffer into the endpoint buffer list */ ++ mcc_queue_buffer(list, (MCC_RECEIVE_BUFFER*)buf); ++ ++ /* Semaphore-protected section end */ ++ mcc_release_semaphore(); ++ ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Signal the other core by generating the CPU-to-CPU interrupt */ ++ return_value = mcc_generate_cpu_to_cpu_interrupt(); ++ ++ return return_value; ++} ++#endif /* MCC_SEND_RECV_NOCOPY_API_ENABLED */ ++ ++/*! ++ * \brief This function receives a message from the specified endpoint if one is available. ++ * The data is copied from the receive buffer into the user supplied buffer. ++ * ++ * This is the "receive with copy" version of the MCC receive function. This version is simple ++ * to use but it requires copying data from shared memory into the user space buffer. ++ * The user has no obligation or burden to manage the shared memory buffers. ++ * ++ * \param[out] src_endpoint Pointer to the MCC_ENDPOINT structure to be filled by the endpoint identifying the message sender. ++ * \param[in] dest_endpoint Pointer to the local receiving endpoint to receive from. ++ * \param[in] buffer Pointer to the user-app. buffer where data will be copied into. ++ * \param[in] buffer_size The maximum number of bytes to copy. ++ * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of bytes actually copied into the buffer. ++ * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_ENDPOINT (the endpoint does not exist) ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came) ++ * ++ * \see mcc_send ++ * \see mcc_recv_nocopy ++ * \see MCC_ENDPOINT ++ */ ++int mcc_recv(MCC_ENDPOINT *src_endpoint, MCC_ENDPOINT *dest_endpoint, void *buffer, MCC_MEM_SIZE buffer_size, MCC_MEM_SIZE *recv_size, unsigned int timeout_ms) ++{ ++ MCC_RECEIVE_LIST *list = null; ++ MCC_RECEIVE_BUFFER * buf; ++ MCC_SIGNAL affiliated_signal; ++ MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0}; ++ int return_value, i = 0; ++ ++ return_value = mcc_recv_common_part(dest_endpoint, timeout_ms, (MCC_RECEIVE_LIST**)&list); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*)); ++ ++ if(list->head == (MCC_RECEIVE_BUFFER*)0) { ++ /* Buffer not dequeued before the timeout */ ++ mcc_release_semaphore(); ++ return MCC_ERR_TIMEOUT; ++ } ++ ++ /* Copy the message from the MCC receive buffer into the user-app. buffer */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE)); ++ mcc_memcpy((void*)&list->head->source, (void*)src_endpoint, sizeof(MCC_ENDPOINT)); ++ if (list->head->data_len > buffer_size) { ++ list->head->data_len = buffer_size; ++ } ++ *recv_size = (MCC_MEM_SIZE)(list->head->data_len); ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len); ++ mcc_memcpy((void*)list->head->data, buffer, list->head->data_len); ++ ++ /* Dequeue the buffer from the endpoint list */ ++ list->head = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(list->head); ++ buf = mcc_dequeue_buffer(list); ++ ++ /* Enqueue the buffer into the free list */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); ++ mcc_queue_buffer(&bookeeping_data->free_list, buf); ++ ++ /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */ ++ affiliated_signal.type = BUFFER_FREED; ++ affiliated_signal.destination = tmp_destination; ++ for (i=0; ihead == (MCC_RECEIVE_BUFFER*)0) { ++ /* Buffer not dequeued before the timeout */ ++ mcc_release_semaphore(); ++ return MCC_ERR_TIMEOUT; ++ } ++ ++ /* Get the message pointer from the head of the receive buffer list */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len); ++ *buffer_p = (void*)&list->head->data; ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE)); ++ mcc_memcpy((void*)&list->head->source, (void*)src_endpoint, sizeof(MCC_ENDPOINT)); ++ *recv_size = (MCC_MEM_SIZE)(list->head->data_len); ++ ++ /* Dequeue the buffer from the endpoint list */ ++ mcc_dequeue_buffer(list); ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ return return_value; ++} ++#endif /* MCC_SEND_RECV_NOCOPY_API_ENABLED */ ++ ++/*! ++ * \private ++ * ++ * \brief This function is common part for mcc_recv() and mcc_recv_nocopy() function. ++ * ++ * It tries to get the list of buffers kept by the particular endpoint. If the list is empty ++ * it waits for a new message until the timeout expires. ++ * ++ * \param[in] endpoint Pointer to the receiving endpoint to receive from. ++ * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). ++ * \param[out] list Pointer to the list of buffers kept by the particular endpoint. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_ENDPOINT (the endpoint does not exist) ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came) ++ * ++ * \see mcc_recv ++ * \see mcc_recv_nocopy ++ * \see MCC_ENDPOINT ++ */ ++static int mcc_recv_common_part(MCC_ENDPOINT *endpoint, unsigned int timeout_ms, MCC_RECEIVE_LIST **list) ++{ ++ MCC_RECEIVE_LIST *tmp_list; ++ int return_value; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Get list of buffers kept by the particular endpoint */ ++ tmp_list = mcc_get_endpoint_list(*endpoint); ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* The endpoint is not valid */ ++ if(tmp_list == null) { ++ return MCC_ERR_ENDPOINT; ++ } ++ ++ if(tmp_list->head == (MCC_RECEIVE_BUFFER*)0) { ++ /* Non-blocking call */ ++ if(timeout_ms == 0) { ++ return MCC_ERR_TIMEOUT; ++ } ++ /* Blocking call */ ++ else { ++ /* Wait for the buffer queued event */ ++ return_value = mcc_wait_for_buffer_queued(endpoint, timeout_ms); ++ if(MCC_SUCCESS != return_value) { ++ return return_value; ++ } ++ } ++ } ++ else { ++ tmp_list->head = (MCC_RECEIVE_BUFFER*)MCC_MEM_PHYS_TO_VIRT(tmp_list->head); ++ } ++ /* Clear event bit specified for the particular endpoint */ ++ mcc_clear_os_sync_for_ep(endpoint); ++ ++ *list = (MCC_RECEIVE_LIST*)tmp_list; ++ return MCC_SUCCESS; ++} ++ ++/*! ++ * \brief This function returns the number of buffers currently queued at the endpoint. ++ * ++ * The function checks if messages are available on a receive endpoint. While the call only checks the ++ * availability of messages, it does not dequeue them. ++ * ++ * \param[in] endpoint Pointer to the endpoint structure. ++ * \param[out] num_msgs Pointer to an unsigned int that will contain the number of buffers queued. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_ENDPOINT (the endpoint does not exist) ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * ++ * \see mcc_recv ++ * \see mcc_recv_nocopy ++ * \see MCC_ENDPOINT ++ */ ++int mcc_msgs_available(MCC_ENDPOINT *endpoint, unsigned int *num_msgs) ++{ ++ unsigned int count = 0; ++ MCC_RECEIVE_LIST *list; ++ MCC_RECEIVE_BUFFER * buf; ++ int return_value; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Get list of buffers kept by the particular endpoint */ ++ list = mcc_get_endpoint_list(*endpoint); ++ if(list == null) { ++ /* The endpoint does not exists (has not been registered so far), return immediately - error */ ++ mcc_release_semaphore(); ++ return MCC_ERR_ENDPOINT; ++ } ++ ++ buf = list->head; ++ while(buf != (MCC_RECEIVE_BUFFER*)0) { ++ count++; ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&buf->next, sizeof(MCC_RECEIVE_BUFFER*)); ++ buf = (MCC_RECEIVE_BUFFER*)buf->next; ++ } ++ *num_msgs = count; ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ return return_value; ++} ++ ++/*! ++ * \private ++ * ++ * \brief This function frees a buffer previously returned by mcc_recv_nocopy(). ++ * ++ * Once the zero-copy mechanism of receiving data is used, this function ++ * has to be called to free a buffer and to make it available for the next data ++ * transfer. ++ * ++ * \param[in] buffer Pointer to the buffer to be freed. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_SEMAPHORE (semaphore handling error) ++ * ++ * \see mcc_recv_nocopy ++ */ ++static int mcc_free_buffer_internal(void *buffer) ++{ ++ MCC_SIGNAL affiliated_signal; ++ MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0}; ++ int return_value, i = 0; ++ ++ /* Semaphore-protected section start */ ++ return_value = mcc_get_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ /* Enqueue the buffer into the free list */ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); ++ mcc_queue_buffer(&bookeeping_data->free_list, (MCC_RECEIVE_BUFFER *)((unsigned int)buffer - (unsigned int)(&(((MCC_RECEIVE_BUFFER*)0)->data)))); ++ ++ /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */ ++ affiliated_signal.type = BUFFER_FREED; ++ affiliated_signal.destination = tmp_destination; ++ for (i=0; iversion_string, (void*)info_data->version_string, (unsigned int)sizeof(bookeeping_data->version_string)); ++ ++ /* Semaphore-protected section end */ ++ return_value = mcc_release_semaphore(); ++ if(return_value != MCC_SUCCESS) ++ return return_value; ++ ++ return return_value; ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mcc_common.c linux-3.14.72/arch/arm/mach-imx/mcc_common.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mcc_common.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mcc_common.c 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,262 @@ ++/* ++ * This file contains MCC library common functions ++ * ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * ++ * SPDX-License-Identifier: GPL-2.0+ and/or BSD-3-Clause ++ * The GPL-2.0+ license for this file can be found in the COPYING.GPL file ++ * included with this distribution or at ++ * http://www.gnu.org/licenses/gpl-2.0.html ++ * The BSD-3-Clause License for this file can be found in the COPYING.BSD file ++ * included with this distribution or at ++ * http://opensource.org/licenses/BSD-3-Clause ++ */ ++ ++#include "mcc_config.h" ++#if (MCC_OS_USED == MCC_MQX) ++#include "mcc_common.h" ++#include "mcc_mqx.h" ++#elif (MCC_OS_USED == MCC_LINUX) ++#include ++#include ++#endif ++ ++ ++/*! ++ * \brief This function registers an endpoint. ++ * ++ * Register an endpoint with specified structure / params (core, node and port). ++ * ++ * \param[in] endpoint Pointer to the endpoint structure. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_NOMEM (maximum number of endpoints exceeded) ++ * \return MCC_ERR_ENDPOINT (invalid value for port or endpoint already registered) ++ */ ++int mcc_register_endpoint(MCC_ENDPOINT endpoint) ++{ ++ int i; ++ ++ /* must be valid */ ++ if(endpoint.port == MCC_RESERVED_PORT_NUMBER) ++ return MCC_ERR_ENDPOINT; ++ ++ /* check not already registered */ ++ if(mcc_get_endpoint_list(endpoint)) ++ return MCC_ERR_ENDPOINT; ++ ++ MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM)); ++ for(i = 0; i < MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) { ++ if(bookeeping_data->endpoint_table[i].endpoint.port == MCC_RESERVED_PORT_NUMBER) { ++ bookeeping_data->endpoint_table[i].endpoint.core = endpoint.core; ++ bookeeping_data->endpoint_table[i].endpoint.node = endpoint.node; ++ bookeeping_data->endpoint_table[i].endpoint.port = endpoint.port; ++ MCC_DCACHE_FLUSH_MLINES(&bookeeping_data->endpoint_table[i], sizeof(MCC_ENDPOINT_MAP_ITEM)); ++ return MCC_SUCCESS; ++ } ++ } ++ return MCC_ERR_NOMEM; ++} ++ ++/*! ++ * \brief This function removes an endpoint. ++ * ++ * Removes an endpoint with specified structure / params (core, node and port). ++ * ++ * \param[in] endpoint Pointer to the endpoint structure. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_ENDPOINT (invalid value for port or the endpoint doesn't exist) ++ */ ++int mcc_remove_endpoint(MCC_ENDPOINT endpoint) ++{ ++ int i=0; ++ ++ /* must be valid */ ++ if(endpoint.port == MCC_RESERVED_PORT_NUMBER) ++ return MCC_ERR_ENDPOINT; ++ ++ MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM)); ++ for(i = 0; i < MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) { ++ ++ if(MCC_ENDPOINTS_EQUAL(bookeeping_data->endpoint_table[i].endpoint, endpoint)) { ++ /* clear the queue */ ++ MCC_RECEIVE_BUFFER * buffer = mcc_dequeue_buffer((MCC_RECEIVE_LIST *)&bookeeping_data->endpoint_table[i].list); ++ while(buffer) { ++ mcc_queue_buffer(&bookeeping_data->free_list, buffer); ++ buffer = mcc_dequeue_buffer((MCC_RECEIVE_LIST *)&bookeeping_data->endpoint_table[i].list); ++ } ++ /* indicate free */ ++ bookeeping_data->endpoint_table[i].endpoint.port = MCC_RESERVED_PORT_NUMBER; ++ MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->endpoint_table[i].endpoint.port, sizeof(MCC_PORT)); ++ return MCC_SUCCESS; ++ } ++ } ++ return MCC_ERR_ENDPOINT; ++} ++ ++/*! ++ * \brief This function dequeues the buffer. ++ * ++ * Dequeues the buffer from the list. ++ * ++ * \param[in] list Pointer to the MCC_RECEIVE_LIST structure. ++ * ++ * \return Pointer to MCC_RECEIVE_BUFFER ++ */ ++MCC_RECEIVE_BUFFER * mcc_dequeue_buffer(MCC_RECEIVE_LIST *list) ++{ ++ MCC_RECEIVE_BUFFER * next_buf, * next_buf_virt; ++ MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST)); ++ ++ next_buf = list->head; ++ ++ next_buf_virt = (MCC_RECEIVE_BUFFER *)MCC_MEM_PHYS_TO_VIRT(next_buf); ++ if(next_buf) { ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&next_buf_virt->next, sizeof(MCC_RECEIVE_BUFFER*)); ++ list->head = next_buf_virt->next; ++ if(list->tail == next_buf) ++ list->tail = null; ++ } ++ MCC_DCACHE_FLUSH_MLINES(list, sizeof(MCC_RECEIVE_LIST)); ++ return next_buf_virt; ++} ++ ++/*! ++ * \brief This function queues the buffer. ++ * ++ * Queues the buffer in the list. ++ * ++ * \param[in] list Pointer to the MCC_RECEIVE_LIST structure. ++ * \param[in] r_buffer Pointer to MCC_RECEIVE_BUFFER. ++ * ++ * \return none ++ */ ++void mcc_queue_buffer(MCC_RECEIVE_LIST *list, MCC_RECEIVE_BUFFER * r_buffer) ++{ ++ MCC_RECEIVE_BUFFER * last_buf; ++ MCC_RECEIVE_BUFFER * r_buffer_phys; ++ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST)); ++ ++ last_buf = (MCC_RECEIVE_BUFFER *)MCC_MEM_PHYS_TO_VIRT(list->tail); ++ r_buffer_phys = (MCC_RECEIVE_BUFFER *)MCC_MEM_VIRT_TO_PHYS(r_buffer); ++ if(last_buf) { ++ last_buf->next = r_buffer_phys; ++ MCC_DCACHE_FLUSH_MLINES((void*)&last_buf->next, sizeof(MCC_RECEIVE_BUFFER*)); ++ } ++ else { ++ list->head = r_buffer_phys; ++ } ++ r_buffer->next = null; ++ list->tail = r_buffer_phys; ++ MCC_DCACHE_FLUSH_MLINES(list, sizeof(MCC_RECEIVE_LIST)); ++ MCC_DCACHE_FLUSH_MLINES((void*)&r_buffer->next, sizeof(MCC_RECEIVE_BUFFER*)); ++} ++ ++/*! ++ * \brief This function returns the endpoint list. ++ * ++ * Returns the MCC_RECEIVE_LIST respective to the endpoint structure provided. ++ * ++ * \param[in] endpoint Pointer to the MCC_ENDPOINT structure. ++ * ++ * \return MCC_RECEIVE_LIST pointer ++ * \return null pointer ++ */ ++MCC_RECEIVE_LIST * mcc_get_endpoint_list(MCC_ENDPOINT endpoint) ++{ ++ int i=0; ++ ++ /* must be valid */ ++ if(endpoint.port == MCC_RESERVED_PORT_NUMBER) ++ return null; ++ ++ MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM)); ++ for(i = 0; iendpoint_table[i].endpoint, endpoint)) { ++ return (MCC_RECEIVE_LIST *)&bookeeping_data->endpoint_table[i].list; ++ } ++ } ++ return null; ++} ++ ++/*! ++ * \brief This function queues a signal ++ * ++ * Signal circular queue rules: ++ * tail points to next free slot ++ * head points to first occupied slot ++ * head == tail indicates empty ++ * (tail + 1) % len = fill ++ * This method costs 1 slot since you need to differentiate ++ * between full and empty (if you fill the last slot it looks ++ * like empty since h == t) ++ * ++ * \param[in] core Core number. ++ * \param[in] signal Signal to be queued. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_SQ_FULL (signal queue is full - no more that MCC_MAX_OUTSTANDING_SIGNALS items allowed) ++ */ ++int mcc_queue_signal(MCC_CORE core, MCC_SIGNAL signal) ++{ ++ int tail, new_tail; ++ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_head[core], sizeof(unsigned int)); ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_tail[core], sizeof(unsigned int)); ++ tail = bookeeping_data->signal_queue_tail[core]; ++ new_tail = tail == (MCC_MAX_OUTSTANDING_SIGNALS-1) ? 0 : tail+1; ++ ++ if(MCC_SIGNAL_QUEUE_FULL(core)) ++ return MCC_ERR_SQ_FULL; ++ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signals_received[core][tail], sizeof(MCC_SIGNAL)); ++ bookeeping_data->signals_received[core][tail].type = signal.type; ++ bookeeping_data->signals_received[core][tail].destination.core = signal.destination.core; ++ bookeeping_data->signals_received[core][tail].destination.node = signal.destination.node; ++ bookeeping_data->signals_received[core][tail].destination.port = signal.destination.port; ++ ++ bookeeping_data->signal_queue_tail[core] = new_tail; ++ MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->signal_queue_tail[core], sizeof(unsigned int)); ++ MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->signals_received[core][tail], sizeof(MCC_SIGNAL)); ++ ++ return MCC_SUCCESS; ++} ++ ++/*! ++ * \brief This function dequeues a signal ++ * ++ * It dequeues a signal from the signal queue for the particular core. ++ * ++ * \param[in] core Core number. ++ * \param[in] signal Signal to be dequeued. ++ * ++ * \return MCC_SUCCESS ++ * \return MCC_ERR_SQ_EMPTY (signal queue is empty, nothing to dequeue) ++ */ ++int mcc_dequeue_signal(MCC_CORE core, MCC_SIGNAL *signal) ++{ ++ int head; ++ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_head[core], sizeof(unsigned int)); ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_tail[core], sizeof(unsigned int)); ++ head = bookeeping_data->signal_queue_head[core]; ++ ++ if(MCC_SIGNAL_QUEUE_EMPTY(core)) ++ return MCC_ERR_SQ_EMPTY; ++ ++ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signals_received[core][head], sizeof(MCC_SIGNAL)); ++ signal->type = bookeeping_data->signals_received[core][head].type; ++ signal->destination.core = bookeeping_data->signals_received[core][head].destination.core; ++ signal->destination.node = bookeeping_data->signals_received[core][head].destination.node; ++ signal->destination.port = bookeeping_data->signals_received[core][head].destination.port; ++ ++ bookeeping_data->signal_queue_head[core] = head == (MCC_MAX_OUTSTANDING_SIGNALS-1) ? 0 : head+1; ++ MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->signal_queue_head[core], sizeof(unsigned int)); ++ ++ return MCC_SUCCESS; ++} ++ +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mcc_config.h linux-3.14.72/arch/arm/mach-imx/mcc_config.h +--- linux-3.14.72.orig/arch/arm/mach-imx/mcc_config.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mcc_config.h 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * This is the main MCC configuration file ++ * ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * ++ * SPDX-License-Identifier: GPL-2.0+ and/or BSD-3-Clause ++ * The GPL-2.0+ license for this file can be found in the COPYING.GPL file ++ * included with this distribution or at ++ * http://www.gnu.org/licenses/gpl-2.0.html ++ * The BSD-3-Clause License for this file can be found in the COPYING.BSD file ++ * included with this distribution or at ++ * http://opensource.org/licenses/BSD-3-Clause ++ */ ++ ++#ifndef __MCC_CONFIG__ ++#define __MCC_CONFIG__ ++ ++#include ++#include ++ ++/* used OS */ ++#define MCC_OS_USED (MCC_LINUX) ++ ++#endif /* __MCC_CONFIG__ */ +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mcc_imx6sx.c linux-3.14.72/arch/arm/mach-imx/mcc_imx6sx.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mcc_imx6sx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mcc_imx6sx.c 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * SPDX-License-Identifier: GPL-2.0+ and/or BSD-3-Clause ++ * The GPL-2.0+ license for this file can be found in the COPYING.GPL file ++ * included with this distribution or at ++ * http://www.gnu.org/licenses/gpl-2.0.html ++ * The BSD-3-Clause License for this file can be found in the COPYING.BSD file ++ * included with this distribution or at ++ * http://opensource.org/licenses/BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++ ++/*! ++ * \brief This function returns the core number ++ * ++ * \return int ++ */ ++unsigned int _psp_core_num(void) ++{ ++ return 0; ++} ++ ++/*! ++ * \brief This function returns the node number ++ * ++ * \return unsigned int ++ */ ++unsigned int _psp_node_num(void) ++{ ++ return MCC_LINUX_NODE_NUMBER; ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mcc_linux.c linux-3.14.72/arch/arm/mach-imx/mcc_linux.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mcc_linux.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mcc_linux.c 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,200 @@ ++/* ++ * This file contains Linux-specific MCC library functions ++ * ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * ++ * SPDX-License-Identifier: GPL-2.0+ and/or BSD-3-Clause ++ * The GPL-2.0+ license for this file can be found in the COPYING.GPL file ++ * included with this distribution or at ++ * http://www.gnu.org/licenses/gpl-2.0.html ++ * The BSD-3-Clause License for this file can be found in the COPYING.BSD file ++ * included with this distribution or at ++ * http://opensource.org/licenses/BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include "mcc_config.h" ++#include ++ ++/* Global variables */ ++static unsigned long mcc_shm_offset; ++ ++MCC_BOOKEEPING_STRUCT *bookeeping_data; ++ ++/*! ++ * \brief This function initializes the hw semaphore (SEMA4). ++ * ++ * Calls core-mutex driver to create a core mutex. ++ * ++ * \param[in] sem_num SEMA4 gate number. ++ */ ++int mcc_init_semaphore(unsigned int sem_num) ++{ ++ /* Create a core mutex */ ++ mcc_shm_ptr = imx_sema4_mutex_create(0, sem_num); ++ ++ if (NULL == mcc_shm_ptr) ++ return MCC_ERR_SEMAPHORE; ++ else ++ return MCC_SUCCESS; ++} ++ ++/*! ++ * \brief This function de-initializes the hw semaphore (SEMA4). ++ * ++ * Calls core-mutex driver to destroy a core mutex. ++ * ++ * \param[in] sem_num SEMA4 gate number. ++ */ ++int mcc_deinit_semaphore(unsigned int sem_num) ++{ ++ /* Destroy the core mutex */ ++ if (0 == imx_sema4_mutex_destroy(mcc_shm_ptr)) ++ return MCC_SUCCESS; ++ else ++ return MCC_ERR_SEMAPHORE; ++} ++ ++/*! ++ * \brief This function locks the specified core mutex. ++ * ++ * Calls core-mutex driver to lock the core mutex. ++ * ++ */ ++int mcc_get_semaphore(void) ++{ ++ if (imx_mcc_bsp_int_disable()) { ++ pr_err("ERR:failed to disable mcc int.\n"); ++ return MCC_ERR_SEMAPHORE; ++ } ++ ++ if (0 == imx_sema4_mutex_lock(mcc_shm_ptr)) { ++ return MCC_SUCCESS; ++ } else { ++ if (imx_mcc_bsp_int_enable()) { ++ pr_err("ERR:failed to enable mcc int.\n"); ++ return MCC_ERR_INT; ++ } ++ return MCC_ERR_SEMAPHORE; ++ } ++} ++ ++/*! ++ * \brief This function unlocks the specified core mutex. ++ * ++ * Calls core-mutex driver to unlock the core mutex. ++ * ++ */ ++int mcc_release_semaphore(void) ++{ ++ if (0 == imx_sema4_mutex_unlock(mcc_shm_ptr)) { ++ /* ++ * Enable the cpu-to-cpu isr just in case imx_semae_mutex_unlock ++ * function has not woke up another task waiting for the core ++ * mutex. ++ */ ++ if (mcc_shm_ptr->gate_val != (MCC_CORE_NUMBER + 1)) ++ imx_mcc_bsp_int_enable(); ++ return MCC_SUCCESS; ++ } ++ ++ return MCC_ERR_SEMAPHORE; ++} ++ ++/*! ++ * \brief This function registers the CPU-to-CPU interrupt. ++ * ++ * Calls interrupt component functions to install and enable the ++ * CPU-to-CPU interrupt. ++ * ++ */ ++int mcc_register_cpu_to_cpu_isr(void) ++{ ++ /* ++ * CPU to CPU ISR had been registered in MU driver. ++ * return success directly. ++ */ ++ return MCC_SUCCESS; ++} ++ ++/*! ++ * \brief This function triggers an interrupt to other core(s). ++ * ++ */ ++int mcc_generate_cpu_to_cpu_interrupt(void) ++{ ++ int ret; ++ ++ /* ++ * Assert directed CPU interrupts for all processors except ++ * the requesting core ++ */ ++ ret = mcc_triger_cpu_to_cpu_interrupt(); ++ ++ if (ret == 0) ++ return MCC_SUCCESS; ++ else ++ return ret; ++} ++ ++/*! ++ * \brief This function copies data. ++ * ++ * Copies the number of single-addressable units from the source address ++ * to destination address. ++ * ++ * \param[in] src Source address. ++ * \param[in] dest Destination address. ++ * \param[in] size Number of single-addressable units to copy. ++ */ ++void mcc_memcpy(void *src, void *dest, unsigned int size) ++{ ++ memcpy(dest, src, size); ++} ++ ++void *mcc_virt_to_phys(void *x) ++{ ++ if (null == x) ++ return NULL; ++ else ++ return (void *)((unsigned long) (x) - mcc_shm_offset); ++} ++ ++void *mcc_phys_to_virt(void *x) ++{ ++ if (null == x) ++ return NULL; ++ else ++ return (void *)((unsigned long) (x) + mcc_shm_offset); ++} ++ ++int mcc_init_os_sync(void) ++{ ++ /* No used in linux */ ++ return MCC_SUCCESS; ++} ++ ++int mcc_deinit_os_sync(void) ++{ ++ /* No used in linux */ ++ return MCC_SUCCESS; ++} ++ ++void mcc_clear_os_sync_for_ep(MCC_ENDPOINT *endpoint) ++{ ++ /* No used in linux */ ++} ++ ++MCC_BOOKEEPING_STRUCT *mcc_get_bookeeping_data(void) ++{ ++ bookeeping_data = (MCC_BOOKEEPING_STRUCT *)ioremap_nocache ++ (MCC_BASE_ADDRESS, sizeof(struct mcc_bookeeping_struct)); ++ mcc_shm_offset = (unsigned long)bookeeping_data ++ - (unsigned long)MCC_BASE_ADDRESS; ++ ++ return bookeeping_data; ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mmdc.c linux-3.14.72/arch/arm/mach-imx/mmdc.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mmdc.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/mmdc.c 2016-06-19 22:11:55.053156547 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -21,6 +21,12 @@ + #define BP_MMDC_MAPSR_PSD 0 + #define BP_MMDC_MAPSR_PSS 4 + ++#define MMDC_MDMISC 0x18 ++#define BM_MMDC_MDMISC_DDR_TYPE 0x18 ++#define BP_MMDC_MDMISC_DDR_TYPE 0x3 ++ ++static int ddr_type; ++ + static int imx_mmdc_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -31,6 +37,13 @@ + mmdc_base = of_iomap(np, 0); + WARN_ON(!mmdc_base); + ++ reg = mmdc_base + MMDC_MDMISC; ++ /* Get ddr type */ ++ val = readl_relaxed(reg); ++ val &= BM_MMDC_MDMISC_DDR_TYPE; ++ val >>= BP_MMDC_MDMISC_DDR_TYPE; ++ ddr_type = val; ++ + reg = mmdc_base + MMDC_MAPSR; + + /* Enable automatic power saving */ +@@ -51,6 +64,11 @@ + return 0; + } + ++int imx_mmdc_get_ddr_type(void) ++{ ++ return ddr_type; ++} ++ + static struct of_device_id imx_mmdc_dt_ids[] = { + { .compatible = "fsl,imx6q-mmdc", }, + { /* sentinel */ } +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mu.c linux-3.14.72/arch/arm/mach-imx/mu.c +--- linux-3.14.72.orig/arch/arm/mach-imx/mu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mu.c 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,475 @@ ++/* ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "common.h" ++#include "hardware.h" ++#include "mcc_config.h" ++#include ++#include ++#include ++ ++#define MU_ATR0_OFFSET 0x0 ++#define MU_ARR0_OFFSET 0x10 ++#define MU_ASR 0x20 ++#define MU_ACR 0x24 ++ ++#define MU_LPM_HANDSHAKE_INDEX 0 ++#define MU_LPM_BUS_HIGH_READY_FOR_M4 0xFFFF6666 ++#define MU_LPM_M4_FREQ_CHANGE_READY 0xFFFF7777 ++#define MU_LPM_M4_REQUEST_HIGH_BUS 0x2222CCCC ++#define MU_LPM_M4_RELEASE_HIGH_BUS 0x2222BBBB ++#define MU_LPM_M4_WAKEUP_SRC_VAL 0x55555000 ++#define MU_LPM_M4_WAKEUP_SRC_MASK 0xFFFFF000 ++#define MU_LPM_M4_WAKEUP_IRQ_MASK 0xFF0 ++#define MU_LPM_M4_WAKEUP_IRQ_SHIFT 0x4 ++#define MU_LPM_M4_WAKEUP_ENABLE_MASK 0xF ++#define MU_LPM_M4_WAKEUP_ENABLE_SHIFT 0x0 ++ ++static void __iomem *mu_base; ++static u32 m4_message; ++static struct delayed_work mu_work; ++static u32 m4_wake_irqs[4]; ++static bool m4_freq_low; ++ ++struct imx_sema4_mutex *mcc_shm_ptr; ++unsigned int imx_mcc_buffer_freed = 0, imx_mcc_buffer_queued = 0; ++/* Used for blocking send */ ++static DECLARE_WAIT_QUEUE_HEAD(buffer_freed_wait_queue); ++/* Used for blocking recv */ ++static DECLARE_WAIT_QUEUE_HEAD(buffer_queued_wait_queue); ++ ++bool imx_mu_is_m4_in_low_freq(void) ++{ ++ return m4_freq_low; ++} ++ ++void imx_mu_enable_m4_irqs_in_gic(bool enable) ++{ ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ if (m4_wake_irqs[i] == 0) ++ continue; ++ for (j = 0; j < 32; j++) { ++ if (m4_wake_irqs[i] & (1 << j)) { ++ if (enable) ++ enable_irq((i + 1) * 32 + j); ++ else ++ disable_irq((i + 1) * 32 + j); ++ } ++ } ++ } ++} ++ ++static irqreturn_t mcc_m4_dummy_isr(int irq, void *param) ++{ ++ return IRQ_HANDLED; ++} ++ ++static void imx_mu_send_message(unsigned int index, unsigned int data) ++{ ++ u32 val; ++ unsigned long timeout = jiffies + msecs_to_jiffies(500); ++ ++ /* wait for transfer buffer empty */ ++ do { ++ val = readl_relaxed(mu_base + MU_ASR); ++ if (time_after(jiffies, timeout)) { ++ pr_err("Waiting MU transmit buffer empty timeout!\n"); ++ break; ++ } ++ } while ((val & (1 << (20 + index))) == 0); ++ ++ writel_relaxed(data, mu_base + index * 0x4 + MU_ATR0_OFFSET); ++} ++ ++static void mu_work_handler(struct work_struct *work) ++{ ++ int ret; ++ u32 irq, enable, idx, mask; ++ ++ pr_debug("receive M4 message 0x%x\n", m4_message); ++ ++ switch (m4_message) { ++ case MU_LPM_M4_REQUEST_HIGH_BUS: ++ request_bus_freq(BUS_FREQ_HIGH); ++ imx6sx_set_m4_highfreq(true); ++ imx_mu_send_message(MU_LPM_HANDSHAKE_INDEX, ++ MU_LPM_BUS_HIGH_READY_FOR_M4); ++ m4_freq_low = false; ++ break; ++ case MU_LPM_M4_RELEASE_HIGH_BUS: ++ release_bus_freq(BUS_FREQ_HIGH); ++ imx6sx_set_m4_highfreq(false); ++ imx_mu_send_message(MU_LPM_HANDSHAKE_INDEX, ++ MU_LPM_M4_FREQ_CHANGE_READY); ++ m4_freq_low = true; ++ break; ++ default: ++ if ((m4_message & MU_LPM_M4_WAKEUP_SRC_MASK) == ++ MU_LPM_M4_WAKEUP_SRC_VAL) { ++ irq = (m4_message & MU_LPM_M4_WAKEUP_IRQ_MASK) >> ++ MU_LPM_M4_WAKEUP_IRQ_SHIFT; ++ ++ enable = (m4_message & MU_LPM_M4_WAKEUP_ENABLE_MASK) >> ++ MU_LPM_M4_WAKEUP_ENABLE_SHIFT; ++ ++ idx = irq / 32 - 1; ++ mask = 1 << irq % 32; ++ ++ if (enable && can_request_irq(irq, 0)) { ++ ret = request_irq(irq, mcc_m4_dummy_isr, ++ IRQF_NO_SUSPEND, "imx-m4-dummy", NULL); ++ if (ret) { ++ pr_err("%s: register interrupt %d failed, rc %d\n", ++ __func__, irq, ret); ++ break; ++ } ++ disable_irq(irq); ++ m4_wake_irqs[idx] = m4_wake_irqs[idx] | mask; ++ } ++ imx_gpc_add_m4_wake_up_irq(irq, enable); ++ } ++ break; ++ } ++ m4_message = 0; ++ /* enable RIE3 interrupt */ ++ writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(27), ++ mu_base + MU_ACR); ++} ++ ++/*! ++ * \brief This function clears the CPU-to-CPU int flag for the particular core. ++ * ++ * Implementation is platform-specific. ++ */ ++void mcc_clear_cpu_to_cpu_interrupt(void) ++{ ++ u32 val; ++ ++ val = readl_relaxed(mu_base + MU_ASR); ++ /* write 1 to BIT31 to clear the bit31(GIP3) of MU_ASR */ ++ val = val | (1 << 31); ++ writel_relaxed(val, mu_base + MU_ASR); ++} ++ ++/*! ++ * \brief This function triggers the CPU-to-CPU interrupt. ++ * ++ * Platform-specific software triggering the inter-CPU interrupts. ++ */ ++int mcc_triger_cpu_to_cpu_interrupt(void) ++{ ++ int i = 0; ++ u32 val; ++ ++ val = readl_relaxed(mu_base + MU_ACR); ++ ++ if ((val & BIT(19)) != 0) { ++ do { ++ val = readl_relaxed(mu_base + MU_ACR); ++ msleep(1); ++ } while (((val & BIT(19)) > 0) && (i++ < 100)); ++ } ++ ++ if ((val & BIT(19)) == 0) { ++ /* Enable the bit19(GIR3) of MU_ACR */ ++ val = readl_relaxed(mu_base + MU_ACR); ++ val |= BIT(19); ++ writel_relaxed(val, mu_base + MU_ACR); ++ return 0; ++ } else { ++ pr_info("mcc int still be triggered after %d ms polling!\n", i); ++ return -EIO; ++ } ++} ++ ++/*! ++ * \brief This function disable the CPU-to-CPU interrupt. ++ * ++ * Platform-specific software disable the inter-CPU interrupts. ++ */ ++int imx_mcc_bsp_int_disable(void) ++{ ++ u32 val; ++ ++ /* Disablethe bit31(GIE3) and bit19(GIR3) of MU_ACR */ ++ val = readl_relaxed(mu_base + MU_ACR); ++ val &= ~(BIT(31) | BIT(27)); ++ writel_relaxed(val, mu_base + MU_ACR); ++ ++ /* flush */ ++ val = readl_relaxed(mu_base + MU_ACR); ++ return 0; ++} ++ ++/*! ++ * \brief This function enable the CPU-to-CPU interrupt. ++ * ++ * Platform-specific software enable the inter-CPU interrupts. ++ */ ++int imx_mcc_bsp_int_enable(void) ++{ ++ u32 val; ++ ++ /* Enable bit31(GIE3) and bit19(GIR3) of MU_ACR */ ++ val = readl_relaxed(mu_base + MU_ACR); ++ val |= (BIT(31) | BIT(27)); ++ writel_relaxed(val, mu_base + MU_ACR); ++ ++ /* flush */ ++ val = readl_relaxed(mu_base + MU_ACR); ++ return 0; ++} ++ ++int mcc_wait_for_buffer_freed(MCC_RECEIVE_BUFFER **buffer, unsigned int timeout) ++{ ++ int return_value; ++ unsigned long timeout_j; /* jiffies */ ++ MCC_RECEIVE_BUFFER *buf = null; ++ ++ /* ++ * Blocking calls: CPU-to-CPU ISR sets the event and thus ++ * resumes tasks waiting for a free MCC buffer. ++ * As the interrupt request is send to all cores when a buffer ++ * is freed it could happen that several tasks from different ++ * cores/nodes are waiting for a free buffer and all of them ++ * are notified that the buffer has been freed. This function ++ * has to check (after the wake up) that a buffer is really ++ * available and has not been already grabbed by another ++ * "competitor task" that has been faster. If so, it has to ++ * wait again for the next notification. ++ */ ++ while (buf == null) { ++ if (timeout == 0xffffffff) { ++ /* ++ * In order to level up the robust, do not always ++ * wait event here. Wake up itself after every 1~s. ++ */ ++ timeout_j = usecs_to_jiffies(1000); ++ wait_event_timeout(buffer_freed_wait_queue, ++ imx_mcc_buffer_freed == 1, timeout_j); ++ } else { ++ timeout_j = msecs_to_jiffies(timeout); ++ wait_event_timeout(buffer_freed_wait_queue, ++ imx_mcc_buffer_freed == 1, timeout_j); ++ } ++ ++ return_value = mcc_get_semaphore(); ++ if (return_value != MCC_SUCCESS) ++ return return_value; ++ ++ MCC_DCACHE_INVALIDATE_MLINES((void *) ++ &bookeeping_data->free_list, ++ sizeof(MCC_RECEIVE_LIST *)); ++ ++ buf = mcc_dequeue_buffer(&bookeeping_data->free_list); ++ mcc_release_semaphore(); ++ if (imx_mcc_buffer_freed) ++ imx_mcc_buffer_freed = 0; ++ } ++ ++ *buffer = buf; ++ return MCC_SUCCESS; ++} ++ ++int mcc_wait_for_buffer_queued(MCC_ENDPOINT *endpoint, unsigned int timeout) ++{ ++ unsigned long timeout_j; /* jiffies */ ++ MCC_RECEIVE_LIST *tmp_list; ++ ++ /* Get list of buffers kept by the particular endpoint */ ++ tmp_list = mcc_get_endpoint_list(*endpoint); ++ ++ if (timeout == 0xffffffff) { ++ wait_event(buffer_queued_wait_queue, ++ imx_mcc_buffer_queued == 1); ++ mcc_get_semaphore(); ++ /* ++ * double check if the tmp_list head is still null ++ * or not, if yes, wait again. ++ */ ++ while (tmp_list->head == null) { ++ imx_mcc_buffer_queued = 0; ++ mcc_release_semaphore(); ++ wait_event(buffer_queued_wait_queue, ++ imx_mcc_buffer_queued == 1); ++ mcc_get_semaphore(); ++ } ++ } else { ++ timeout_j = msecs_to_jiffies(timeout); ++ wait_event_timeout(buffer_queued_wait_queue, ++ imx_mcc_buffer_queued == 1, timeout_j); ++ mcc_get_semaphore(); ++ } ++ ++ if (imx_mcc_buffer_queued) ++ imx_mcc_buffer_queued = 0; ++ ++ if (tmp_list->head == null) { ++ pr_err("%s can't get queued buffer.\n", __func__); ++ mcc_release_semaphore(); ++ return MCC_ERR_TIMEOUT; ++ } ++ ++ tmp_list->head = (MCC_RECEIVE_BUFFER *) ++ MCC_MEM_PHYS_TO_VIRT(tmp_list->head); ++ mcc_release_semaphore(); ++ ++ return MCC_SUCCESS; ++} ++ ++static irqreturn_t imx_mu_isr(int irq, void *param) ++{ ++ u32 irqs; ++ ++ irqs = readl_relaxed(mu_base + MU_ASR); ++ ++ if (irqs & (1 << 27)) { ++ /* get message from receive buffer */ ++ m4_message = readl_relaxed(mu_base + MU_ARR0_OFFSET); ++ /* disable RIE3 interrupt */ ++ writel_relaxed(readl_relaxed(mu_base + MU_ACR) & (~BIT(27)), ++ mu_base + MU_ACR); ++ schedule_delayed_work(&mu_work, 0); ++ } ++ ++ /* ++ * MCC CPU-to-CPU interrupt. ++ * Each core can interrupt the other. There are two logical signals: ++ * - Receive data available for (Node,Port) ++ * - signaled when a buffer is queued to a Receive Data Queue. ++ * - Buffer available ++ * - signaled when a buffer is queued to the Free Buffer Queue. ++ * It is possible that several signals can occur while one interrupt ++ * is being processed. ++ * Therefore, a Receive Signal Queue of received signals is also ++ * required ++ * - one for each core. ++ * The interrupting core queues to the tail and the interrupted core ++ * pulls from the head. ++ * For a circular file, no semaphore is required since only the sender ++ * modifies the tail and only the receiver modifies the head. ++ */ ++ if (irqs & (1 << 31)) { ++ /* ++ * Try to lock the core mutex. If successfully locked, perform ++ * mcc_dequeue_signal(), release the gate and finally clear the ++ * interrupt flag. If trylock fails (HW semaphore already locked ++ * by another core), do not clear the interrupt flag – this ++ * way the CPU-to-CPU isr is re-issued again until the HW ++ * semaphore is locked. Higher priority ISRs will be serviced ++ * while issued at the time we are waiting for the unlocked ++ * gate. To prevent trylog failure due to core mutex currently ++ * locked by our own core(a task), the cpu-to-cpu isr is ++ * temporarily disabled when mcc_get_semaphore() is called and ++ * re-enabled again when mcc_release_semaphore() is issued. ++ */ ++ MCC_SIGNAL serviced_signal; ++ if (SEMA4_A9_LOCK == imx_sema4_mutex_trylock(mcc_shm_ptr)) { ++ while (MCC_SUCCESS == mcc_dequeue_signal( ++ MCC_CORE_NUMBER, &serviced_signal)) { ++ if ((serviced_signal.type == BUFFER_QUEUED) && ++ (serviced_signal.destination.core == ++ MCC_CORE_NUMBER)) { ++ /* ++ * Unblock receiver, in case of ++ * asynchronous communication ++ */ ++ imx_mcc_buffer_queued = 1; ++ wake_up(&buffer_queued_wait_queue); ++ } else if (serviced_signal.type == ++ BUFFER_FREED) { ++ /* ++ * Unblock sender, in case of ++ * asynchronous communication ++ */ ++ imx_mcc_buffer_freed = 1; ++ wake_up(&buffer_freed_wait_queue); ++ } ++ } ++ ++ /* Clear the interrupt flag */ ++ mcc_clear_cpu_to_cpu_interrupt(); ++ ++ /* Unlocks the core mutex */ ++ imx_sema4_mutex_unlock(mcc_shm_ptr); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int imx_mu_probe(struct platform_device *pdev) ++{ ++ int ret; ++ u32 irq; ++ struct device_node *np; ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu"); ++ mu_base = of_iomap(np, 0); ++ WARN_ON(!mu_base); ++ ++ irq = platform_get_irq(pdev, 0); ++ ++ ret = request_irq(irq, imx_mu_isr, ++ IRQF_EARLY_RESUME, "imx-mu", NULL); ++ if (ret) { ++ pr_err("%s: register interrupt %d failed, rc %d\n", ++ __func__, irq, ret); ++ return ret; ++ } ++ INIT_DELAYED_WORK(&mu_work, mu_work_handler); ++ ++ /* enable the bit27(RIE3) of MU_ACR */ ++ writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(27), ++ mu_base + MU_ACR); ++ /* enable the bit31(GIE3) of MU_ACR, used for MCC */ ++ writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(31), ++ mu_base + MU_ACR); ++ ++ /* MU always as a wakeup source for low power mode */ ++ imx_gpc_add_m4_wake_up_irq(irq, true); ++ ++ pr_info("MU is ready for cross core communication!\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id imx_mu_ids[] = { ++ { .compatible = "fsl,imx6sx-mu" }, ++ { } ++}; ++ ++static struct platform_driver imx_mu_driver = { ++ .driver = { ++ .name = "imx-mu", ++ .owner = THIS_MODULE, ++ .of_match_table = imx_mu_ids, ++ }, ++ .probe = imx_mu_probe, ++}; ++ ++static int __init imx6_mu_init(void) ++{ ++ return platform_driver_register(&imx_mu_driver); ++} ++subsys_initcall(imx6_mu_init); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mx6.h linux-3.14.72/arch/arm/mach-imx/mx6.h +--- linux-3.14.72.orig/arch/arm/mach-imx/mx6.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/mx6.h 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,51 @@ ++/* ++ * Copyright 2004-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 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_SEMA4_BASE_ADDR 0x02290000 ++#define MX6Q_SEMA4_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 MX6Q_AIPS1_BASE_ADDR 0x02000000 ++#define MX6Q_AIPS1_SIZE 0x100000 ++#define MX6Q_AIPS2_BASE_ADDR 0x02100000 ++#define MX6Q_AIPS2_SIZE 0x100000 ++#define MX6Q_AIPS3_BASE_ADDR 0x02200000 ++#define MX6Q_AIPS3_SIZE 0x100000 ++ ++#define MX6SX_IRAM_TLB_BASE_ADDR 0x008f8000 ++#define MX6Q_IRAM_TLB_BASE_ADDR 0x00900000 ++#define MX6Q_IRAM_TLB_SIZE 0x4000 ++#define TT_ATTRIB_NON_CACHEABLE_1M 0x802 ++#define MX6_SUSPEND_IRAM_DATA_SIZE 256 ++#define MX6SL_WFI_IRAM_DATA_SIZE 100 ++ ++#define MX6_SUSPEND_IRAM_ADDR_OFFSET 0 ++#define MX6_CPUIDLE_IRAM_ADDR_OFFSET 0x1000 ++#endif +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/mxc.h linux-3.14.72/arch/arm/mach-imx/mxc.h +--- linux-3.14.72.orig/arch/arm/mach-imx/mxc.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/mxc.h 2016-06-19 22:11:55.053156547 +0200 +@@ -36,12 +36,15 @@ + #define MXC_CPU_MX53 53 + #define MXC_CPU_IMX6SL 0x60 + #define MXC_CPU_IMX6DL 0x61 ++#define MXC_CPU_IMX6SX 0x62 + #define MXC_CPU_IMX6Q 0x63 + + #define IMX_CHIP_REVISION_1_0 0x10 + #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 +@@ -52,6 +55,8 @@ + #define IMX_CHIP_REVISION_3_3 0x33 + #define IMX_CHIP_REVISION_UNKNOWN 0xff + ++#define IMX_DDR_TYPE_LPDDR2 1 ++ + #ifndef __ASSEMBLY__ + extern unsigned int __mxc_cpu_type; + #endif +@@ -153,16 +158,25 @@ + #endif + + #ifndef __ASSEMBLY__ ++#ifdef CONFIG_SOC_IMX6SL + static inline bool cpu_is_imx6sl(void) + { + return __mxc_cpu_type == MXC_CPU_IMX6SL; + } ++#else ++# define cpu_is_imx6sl() (0) ++#endif + + static inline bool cpu_is_imx6dl(void) + { + return __mxc_cpu_type == MXC_CPU_IMX6DL; + } + ++static inline bool cpu_is_imx6sx(void) ++{ ++ return __mxc_cpu_type == MXC_CPU_IMX6SX; ++} ++ + static inline bool cpu_is_imx6q(void) + { + return __mxc_cpu_type == MXC_CPU_IMX6Q; +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/platsmp.c linux-3.14.72/arch/arm/mach-imx/platsmp.c +--- linux-3.14.72.orig/arch/arm/mach-imx/platsmp.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/platsmp.c 2016-06-19 22:11:55.053156547 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -23,7 +23,7 @@ + #define SCU_STANDBY_ENABLE (1 << 5) + + u32 g_diag_reg; +-static void __iomem *scu_base; ++void __iomem *imx_scu_base; + + static struct map_desc scu_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ +@@ -42,18 +42,18 @@ + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); + +- scu_base = IMX_IO_ADDRESS(base); ++ imx_scu_base = IMX_IO_ADDRESS(base); + } + + void imx_scu_standby_enable(void) + { +- u32 val = readl_relaxed(scu_base); ++ u32 val = readl_relaxed(imx_scu_base); + + val |= SCU_STANDBY_ENABLE; +- writel_relaxed(val, scu_base); ++ writel_relaxed(val, imx_scu_base); + } + +-static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle) ++static int __cpuinit imx_boot_secondary(unsigned int cpu, struct task_struct *idle) + { + imx_set_cpu_jump(cpu, v7_secondary_startup); + imx_enable_cpu(cpu, true); +@@ -66,17 +66,27 @@ + */ + static void __init imx_smp_init_cpus(void) + { +- int i, ncores; ++ int i, ncores = scu_get_core_count(imx_scu_base); ++ u32 me = smp_processor_id(); + +- ncores = scu_get_core_count(scu_base); ++ if (setup_max_cpus < ncores) ++ ncores = (setup_max_cpus) ? setup_max_cpus : 1; + + for (i = ncores; i < NR_CPUS; i++) + set_cpu_possible(i, false); ++ ++ /* Set the SCU CPU Power status for each inactive core. */ ++ for (i = 0; i < NR_CPUS; i++) { ++ if (i != me) ++ __raw_writeb(SCU_PM_POWEROFF, imx_scu_base + 0x08 + i); ++ } + } + + void imx_smp_prepare(void) + { +- scu_enable(scu_base); ++ scu_enable(imx_scu_base); ++ /* Need to enable SCU standby for entering WAIT mode */ ++ imx_scu_standby_enable(); + } + + static void __init imx_smp_prepare_cpus(unsigned int max_cpus) +@@ -92,7 +102,8 @@ + * secondary cores when booting them. + */ + asm("mrc p15, 0, %0, c15, c0, 1" : "=r" (g_diag_reg) : : "cc"); +- sync_cache_w(&g_diag_reg); ++ __cpuc_flush_dcache_area(&g_diag_reg, sizeof(g_diag_reg)); ++ outer_clean_range(__pa(&g_diag_reg), __pa(&g_diag_reg + 1)); + } + + struct smp_operations imx_smp_ops __initdata = { +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/pm-imx6.c linux-3.14.72/arch/arm/mach-imx/pm-imx6.c +--- linux-3.14.72.orig/arch/arm/mach-imx/pm-imx6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/pm-imx6.c 2016-06-19 22:11:55.053156547 +0200 +@@ -0,0 +1,1129 @@ ++/* ++ * 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 ++#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 CCGR4 0x78 ++#define CCGR6 0x80 ++ ++#define MX6Q_SUSPEND_OCRAM_SIZE 0x1000 ++#define MX6_MAX_MMDC_IO_NUM 33 ++#define MX6_MAX_MMDC_NUM 34 ++ ++#define ROMC_ROMPATCH0D 0xf0 ++#define ROMC_ROMPATCHCNTL 0xf4 ++#define ROMC_ROMPATCHENL 0xfc ++#define ROMC_ROMPATCH0A 0x100 ++#define BM_ROMPATCHCNTL_0D (0x1 << 0) ++#define BM_ROMPATCHCNTL_DIS (0x1 << 29) ++#define BM_ROMPATCHENL_0D (0x1 << 0) ++#define ROM_ADDR_FOR_INTERNAL_RAM_BASE 0x10d7c ++ ++#define UART_UCR1 0x80 ++#define UART_UCR2 0x84 ++#define UART_UCR3 0x88 ++#define UART_UCR4 0x8c ++#define UART_UFCR 0x90 ++#define UART_UESC 0x9c ++#define UART_UTIM 0xa0 ++#define UART_UBIR 0xa4 ++#define UART_UBMR 0xa8 ++#define UART_UBRC 0xac ++#define UART_UTS 0xb4 ++ ++/* QSPI register layout */ ++#define QSPI_MCR 0x00 ++#define QSPI_IPCR 0x08 ++#define QSPI_BUF0CR 0x10 ++#define QSPI_BUF1CR 0x14 ++#define QSPI_BUF2CR 0x18 ++#define QSPI_BUF3CR 0x1c ++#define QSPI_BFGENCR 0x20 ++#define QSPI_BUF0IND 0x30 ++#define QSPI_BUF1IND 0x34 ++#define QSPI_BUF2IND 0x38 ++#define QSPI_SFAR 0x100 ++#define QSPI_SMPR 0x108 ++#define QSPI_RBSR 0x10c ++#define QSPI_RBCT 0x110 ++#define QSPI_TBSR 0x150 ++#define QSPI_TBDR 0x154 ++#define QSPI_SFA1AD 0x180 ++#define QSPI_SFA2AD 0x184 ++#define QSPI_SFB1AD 0x188 ++#define QSPI_SFB2AD 0x18c ++#define QSPI_RBDR_BASE 0x200 ++#define QSPI_LUTKEY 0x300 ++#define QSPI_LCKCR 0x304 ++#define QSPI_LUT_BASE 0x310 ++ ++#define QSPI_RBDR_(x) (QSPI_RBDR_BASE + (x) * 4) ++#define QSPI_LUT(x) (QSPI_LUT_BASE + (x) * 4) ++ ++#define QSPI_LUTKEY_VALUE 0x5AF05AF0 ++#define QSPI_LCKER_LOCK 0x1 ++#define QSPI_LCKER_UNLOCK 0x2 ++ ++enum qspi_regs_valuetype { ++ QSPI_PREDEFINED, ++ QSPI_RETRIEVED, ++}; ++ ++struct qspi_regs { ++ int offset; ++ unsigned int value; ++ enum qspi_regs_valuetype valuetype; ++}; ++ ++struct qspi_regs qspi_regs_imx6sx[] = { ++ {QSPI_IPCR, 0, QSPI_RETRIEVED}, ++ {QSPI_BUF0CR, 0, QSPI_RETRIEVED}, ++ {QSPI_BUF1CR, 0, QSPI_RETRIEVED}, ++ {QSPI_BUF2CR, 0, QSPI_RETRIEVED}, ++ {QSPI_BUF3CR, 0, QSPI_RETRIEVED}, ++ {QSPI_BFGENCR, 0, QSPI_RETRIEVED}, ++ {QSPI_BUF0IND, 0, QSPI_RETRIEVED}, ++ {QSPI_BUF1IND, 0, QSPI_RETRIEVED}, ++ {QSPI_BUF2IND, 0, QSPI_RETRIEVED}, ++ {QSPI_SFAR, 0, QSPI_RETRIEVED}, ++ {QSPI_SMPR, 0, QSPI_RETRIEVED}, ++ {QSPI_RBSR, 0, QSPI_RETRIEVED}, ++ {QSPI_RBCT, 0, QSPI_RETRIEVED}, ++ {QSPI_TBSR, 0, QSPI_RETRIEVED}, ++ {QSPI_TBDR, 0, QSPI_RETRIEVED}, ++ {QSPI_SFA1AD, 0, QSPI_RETRIEVED}, ++ {QSPI_SFA2AD, 0, QSPI_RETRIEVED}, ++ {QSPI_SFB1AD, 0, QSPI_RETRIEVED}, ++ {QSPI_SFB2AD, 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(0), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(1), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(2), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(3), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(4), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(5), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(6), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(7), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(8), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(9), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(10), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(11), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(12), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(13), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(14), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(15), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(16), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(17), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(18), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(19), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(20), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(21), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(22), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(23), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(24), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(25), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(26), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(27), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(28), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(29), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(30), 0, QSPI_RETRIEVED}, ++ {QSPI_RBDR_(31), 0, QSPI_RETRIEVED}, ++ {QSPI_LUTKEY, QSPI_LUTKEY_VALUE, QSPI_PREDEFINED}, ++ {QSPI_LCKCR, QSPI_LCKER_UNLOCK, QSPI_PREDEFINED}, ++ {QSPI_LUT(0), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(1), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(2), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(3), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(4), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(5), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(6), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(7), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(8), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(9), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(10), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(11), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(12), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(13), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(14), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(15), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(16), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(17), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(18), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(19), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(20), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(21), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(22), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(23), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(24), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(25), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(26), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(27), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(28), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(29), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(30), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(31), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(32), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(33), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(34), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(35), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(36), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(37), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(38), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(39), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(40), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(41), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(42), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(43), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(44), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(45), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(46), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(47), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(48), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(49), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(50), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(51), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(52), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(53), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(54), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(55), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(56), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(57), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(58), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(59), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(60), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(61), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(62), 0, QSPI_RETRIEVED}, ++ {QSPI_LUT(63), 0, QSPI_RETRIEVED}, ++ {QSPI_LUTKEY, QSPI_LUTKEY_VALUE, QSPI_PREDEFINED}, ++ {QSPI_LCKCR, QSPI_LCKER_LOCK, QSPI_PREDEFINED}, ++ {QSPI_MCR, 0, QSPI_RETRIEVED}, ++}; ++ ++unsigned long iram_tlb_base_addr; ++unsigned long iram_tlb_phys_addr; ++ ++static unsigned int *ocram_saved_in_ddr; ++static void __iomem *ocram_base; ++static void __iomem *console_base; ++static void __iomem *qspi_base; ++static unsigned int ocram_size; ++static void __iomem *ccm_base; ++static void __iomem *suspend_ocram_base; ++static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase); ++struct regmap *romcp; ++/* ++ * 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 ddr_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; ++ const u32 mmdc_num; ++ const u32 *mmdc_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 u32 imx6dl_mmdc_io_offset[] __initconst = { ++ 0x470, 0x474, 0x478, 0x47c, /* DQM0 ~ DQM3 */ ++ 0x480, 0x484, 0x488, 0x48c, /* DQM4 ~ DQM7 */ ++ 0x464, 0x490, 0x4ac, 0x4b0, /* CAS, RAS, SDCLK_0, SDCLK_1 */ ++ 0x4bc, 0x4c0, 0x4c4, 0x4c8, /* DRAM_SDQS0 ~ DRAM_SDQS3 */ ++ 0x4cc, 0x4d0, 0x4d4, 0x4d8, /* DRAM_SDQS4 ~ DRAM_SDQS7 */ ++ 0x764, 0x770, 0x778, 0x77c, /* GPR_B0DS ~ GPR_B3DS */ ++ 0x780, 0x784, 0x78c, 0x748, /* GPR_B4DS ~ GPR_B7DS */ ++ 0x4b4, 0x4b8, 0x750, 0x760, /* SODT0, SODT1, MODE_CTL, MODE */ ++ 0x74c, /* GPR_ADDS */ ++}; ++ ++static const u32 imx6sl_mmdc_io_offset[] __initconst = { ++ 0x30c, 0x310, 0x314, 0x318, /* DQM0 ~ DQM3 */ ++ 0x5c4, 0x5cc, 0x5d4, 0x5d8, /* GPR_B0DS ~ GPR_B3DS */ ++ 0x300, 0x31c, 0x338, 0x5ac, /* CAS, RAS, SDCLK_0, GPR_ADDS */ ++ 0x33c, 0x340, 0x5b0, 0x5c0, /* SODT0, SODT1, MODE_CTL, MODE */ ++ 0x330, 0x334, 0x320, /* SDCKE0, SDCKE1, RESET */ ++}; ++ ++static const u32 imx6sx_mmdc_io_offset[] __initconst = { ++ 0x2ec, 0x2f0, 0x2f4, 0x2f8, /* DQM0 ~ DQM3 */ ++ 0x60c, 0x610, 0x61c, 0x620, /* GPR_B0DS ~ GPR_B3DS */ ++ 0x300, 0x2fc, 0x32c, 0x5f4, /* CAS, RAS, SDCLK_0, GPR_ADDS */ ++ 0x310, 0x314, 0x5f8, 0x608, /* SODT0, SODT1, MODE_CTL, MODE */ ++ 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */ ++}; ++ ++static const u32 imx6sx_mmdc_offset[] __initconst = { ++ 0x800, 0x80c, 0x810, 0x83c, ++ 0x840, 0x848, 0x850, 0x81c, ++ 0x820, 0x824, 0x828, 0x8b8, ++ 0x004, 0x008, 0x00c, 0x010, ++ 0x014, 0x018, 0x01c, 0x02c, ++ 0x030, 0x040, 0x000, 0x01c, ++ 0x020, 0x818, 0x01c, ++}; ++ ++static const struct imx6_pm_socdata imx6q_pm_data __initconst = { ++ .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, ++ .mmdc_num = 0, ++ .mmdc_offset = NULL, ++}; ++ ++static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { ++ .mmdc_compat = "fsl,imx6q-mmdc", ++ .src_compat = "fsl,imx6q-src", ++ .iomuxc_compat = "fsl,imx6dl-iomuxc", ++ .gpc_compat = "fsl,imx6q-gpc", ++ .mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset), ++ .mmdc_io_offset = imx6dl_mmdc_io_offset, ++ .mmdc_num = 0, ++ .mmdc_offset = NULL, ++}; ++ ++static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { ++ .mmdc_compat = "fsl,imx6sl-mmdc", ++ .src_compat = "fsl,imx6sl-src", ++ .iomuxc_compat = "fsl,imx6sl-iomuxc", ++ .gpc_compat = "fsl,imx6sl-gpc", ++ .mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset), ++ .mmdc_io_offset = imx6sl_mmdc_io_offset, ++ .mmdc_num = 0, ++ .mmdc_offset = NULL, ++}; ++ ++static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { ++ .mmdc_compat = "fsl,imx6sx-mmdc", ++ .src_compat = "fsl,imx6sx-src", ++ .iomuxc_compat = "fsl,imx6sx-iomuxc", ++ .gpc_compat = "fsl,imx6sx-gpc", ++ .mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset), ++ .mmdc_io_offset = imx6sx_mmdc_io_offset, ++ .mmdc_num = ARRAY_SIZE(imx6sx_mmdc_offset), ++ .mmdc_offset = imx6sx_mmdc_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 ddr_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; ++ struct imx6_pm_base anatop_base; ++ u32 ttbr1; /* Store TTBR1 */ ++ 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 */ ++ u32 mmdc_num; /* Number of MMDC registers which need saved/restored. */ ++ u32 mmdc_val[MX6_MAX_MMDC_NUM][2]; /* To save offset and value */ ++} __aligned(8); ++ ++unsigned long save_ttbr1(void) ++{ ++ unsigned long lttbr1; ++ asm volatile( ++ ".align 4\n" ++ "mrc p15, 0, %0, c2, c0, 1\n" ++ : "=r" (lttbr1) ++ ); ++ return lttbr1; ++} ++ ++void restore_ttbr1(unsigned long ttbr1) ++{ ++ asm volatile( ++ ".align 4\n" ++ "mcr p15, 0, %0, c2, c0, 1\n" ++ : : "r" (ttbr1) ++ ); ++} ++ ++void imx6q_set_int_mem_clk_lpm(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) || cpu_is_imx6sx()) { ++ 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); ++ } ++} ++ ++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; ++ val &= ~BM_CLPCR_VSTBY; ++ val &= ~BM_CLPCR_SBYOS; ++ if (cpu_is_imx6sl()) ++ val |= BM_CLPCR_BYPASS_PMIC_READY; ++ if (cpu_is_imx6sl() || cpu_is_imx6sx()) ++ val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; ++ else ++ val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; ++ break; ++ case WAIT_UNCLOCKED_POWER_OFF: ++ val |= 0x1 << BP_CLPCR_LPM; ++ val &= ~BM_CLPCR_VSTBY; ++ val &= ~BM_CLPCR_SBYOS; ++ break; ++ case STOP_POWER_OFF: ++ val |= 0x2 << BP_CLPCR_LPM; ++ val |= 0x3 << BP_CLPCR_STBY_COUNT; ++ val |= BM_CLPCR_VSTBY; ++ val |= BM_CLPCR_SBYOS; ++ if (cpu_is_imx6sl()) ++ val |= BM_CLPCR_BYPASS_PMIC_READY; ++ if (cpu_is_imx6sl() || cpu_is_imx6sx()) ++ 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 void imx6_console_save(unsigned int *regs) ++{ ++ if (!console_base) ++ return; ++ ++ regs[0] = readl_relaxed(console_base + UART_UCR1); ++ regs[1] = readl_relaxed(console_base + UART_UCR2); ++ regs[2] = readl_relaxed(console_base + UART_UCR3); ++ regs[3] = readl_relaxed(console_base + UART_UCR4); ++ regs[4] = readl_relaxed(console_base + UART_UFCR); ++ regs[5] = readl_relaxed(console_base + UART_UESC); ++ regs[6] = readl_relaxed(console_base + UART_UTIM); ++ regs[7] = readl_relaxed(console_base + UART_UBIR); ++ regs[8] = readl_relaxed(console_base + UART_UBMR); ++ regs[9] = readl_relaxed(console_base + UART_UBRC); ++ regs[10] = readl_relaxed(console_base + UART_UTS); ++} ++ ++static void imx6_console_restore(unsigned int *regs) ++{ ++ if (!console_base) ++ return; ++ ++ writel_relaxed(regs[4], console_base + UART_UFCR); ++ writel_relaxed(regs[5], console_base + UART_UESC); ++ writel_relaxed(regs[6], console_base + UART_UTIM); ++ writel_relaxed(regs[7], console_base + UART_UBIR); ++ writel_relaxed(regs[8], console_base + UART_UBMR); ++ writel_relaxed(regs[9], console_base + UART_UBRC); ++ writel_relaxed(regs[10], console_base + UART_UTS); ++ writel_relaxed(regs[0], console_base + UART_UCR1); ++ writel_relaxed(regs[1] | 0x1, console_base + UART_UCR2); ++ writel_relaxed(regs[2], console_base + UART_UCR3); ++ writel_relaxed(regs[3], console_base + UART_UCR4); ++} ++ ++static void imx6_qspi_save(struct qspi_regs *pregs, int reg_num) ++{ ++ int i; ++ ++ if (!qspi_base) ++ return; ++ ++ for (i = 0; i < reg_num; i++) { ++ if (QSPI_RETRIEVED == pregs[i].valuetype) ++ pregs[i].value = readl_relaxed(qspi_base + ++ pregs[i].offset); ++ } ++} ++ ++static void imx6_qspi_restore(struct qspi_regs *pregs, int reg_num) ++{ ++ int i; ++ ++ if (!qspi_base) ++ return; ++ ++ for (i = 0; i < reg_num; i++) ++ writel_relaxed(pregs[i].value, qspi_base + pregs[i].offset); ++} ++ ++static int imx6q_pm_enter(suspend_state_t state) ++{ ++ unsigned int console_saved_reg[11] = {0}; ++ static unsigned int ccm_ccgr4, ccm_ccgr6; ++ ++#ifdef CONFIG_SOC_IMX6SX ++ if (imx_src_is_m4_enabled()) { ++ if (imx_gpc_is_m4_sleeping() && imx_mu_is_m4_in_low_freq()) { ++ imx_gpc_hold_m4_in_sleep(); ++ imx_mu_enable_m4_irqs_in_gic(true); ++ } else { ++ pr_info("M4 is busy, enter WAIT mode instead of STOP!\n"); ++ imx6q_set_lpm(WAIT_UNCLOCKED); ++ imx6q_set_int_mem_clk_lpm(true); ++ imx_gpc_pre_suspend(false); ++ /* Zzz ... */ ++ cpu_do_idle(); ++ imx_gpc_post_resume(); ++ imx6q_set_lpm(WAIT_CLOCKED); ++ ++ return 0; ++ } ++ } ++#endif ++ ++ if (!iram_tlb_base_addr) { ++ pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \ ++ code. Please ensure device tree has an entry for \ ++ fsl,lpm-sram.\n"); ++ return -EINVAL; ++ } ++ ++ switch (state) { ++ case PM_SUSPEND_STANDBY: ++ imx6q_set_lpm(STOP_POWER_ON); ++ imx6q_set_int_mem_clk_lpm(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_lpm(STOP_POWER_OFF); ++ imx6q_set_int_mem_clk_lpm(false); ++ 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); ++ if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off()) { ++ ccm_ccgr4 = readl_relaxed(ccm_base + CCGR4); ++ ccm_ccgr6 = readl_relaxed(ccm_base + CCGR6); ++ /* ++ * i.MX6SX RDC needs PCIe and eim clk to be enabled ++ * if Mega/Fast off, it is better to check cpu type ++ * and whether Mega/Fast is off in this suspend flow, ++ * but we need to add cpu type check for 3 places which ++ * will increase code size, so here we just do it ++ * for all cases, as when STOP mode is entered, CCM ++ * hardware will gate all clocks, so it will NOT impact ++ * any function or power. ++ */ ++ writel_relaxed(ccm_ccgr4 | (0x3 << 0), ccm_base + ++ CCGR4); ++ writel_relaxed(ccm_ccgr6 | (0x3 << 10), ccm_base + ++ CCGR6); ++ memcpy(ocram_saved_in_ddr, ocram_base, ocram_size); ++ imx6_console_save(console_saved_reg); ++ if (imx_src_is_m4_enabled()) ++ imx6_qspi_save(qspi_regs_imx6sx, ++ sizeof(qspi_regs_imx6sx) / ++ sizeof(struct qspi_regs)); ++ } ++ ++ /* Zzz ... */ ++ cpu_suspend(0, imx6q_suspend_finish); ++ ++ if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off()) { ++ writel_relaxed(ccm_ccgr4, ccm_base + CCGR4); ++ writel_relaxed(ccm_ccgr6, ccm_base + CCGR6); ++ memcpy(ocram_base, ocram_saved_in_ddr, ocram_size); ++ imx6_console_restore(console_saved_reg); ++ if (imx_src_is_m4_enabled()) ++ imx6_qspi_restore(qspi_regs_imx6sx, ++ sizeof(qspi_regs_imx6sx) / ++ sizeof(struct qspi_regs)); ++ } ++ 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_int_mem_clk_lpm(true); ++ imx6q_set_lpm(WAIT_CLOCKED); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_SOC_IMX6SX ++ if (imx_src_is_m4_enabled()) { ++ imx_mu_enable_m4_irqs_in_gic(false); ++ imx_gpc_release_m4_in_sleep(); ++ } ++#endif ++ ++ 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 struct map_desc iram_tlb_io_desc __initdata = { ++ /* .virtual and .pfn are run-time assigned */ ++ .length = SZ_1M, ++ .type = MT_MEMORY_RWX_NONCACHED, ++}; ++ ++static const char * const low_power_ocram_match[] __initconst = { ++ "fsl,lpm-sram", ++ NULL ++}; ++ ++static int __init imx6_dt_find_lpsram(unsigned long node, const char *uname, ++ int depth, void *data) ++{ ++ unsigned long lpram_addr; ++ __be32 *prop; ++ ++ if (of_flat_dt_match(node, low_power_ocram_match)) { ++ prop = of_get_flat_dt_prop(node, "reg", NULL); ++ if (!prop) ++ return -EINVAL; ++ ++ lpram_addr = be32_to_cpup(prop); ++ ++ /* We need to create a 1M page table entry. */ ++ iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000); ++ iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000); ++ iram_tlb_phys_addr = lpram_addr; ++ iram_tlb_base_addr = IMX_IO_P2V(lpram_addr); ++ ++ iotable_init(&iram_tlb_io_desc, 1); ++ } ++ ++ return 0; ++} ++ ++/* ++ * AIPS1 and AIPS2 is not used, because it will trigger a BUG_ON if ++ * lowlevel debug and earlyprintk are configured. ++ * ++ * it is because there is a vm conflict because UART1 is mapped early if ++ * AIPS1 is mapped using 1M size. ++ * ++ * Thus no use AIPS1 and AIPS2 to avoid kernel BUG_ON. ++ */ ++static struct map_desc imx6_pm_io_desc[] __initdata = { ++ imx_map_entry(MX6Q, MMDC_P0, MT_DEVICE), ++ imx_map_entry(MX6Q, MMDC_P1, MT_DEVICE), ++ imx_map_entry(MX6Q, SRC, MT_DEVICE), ++ imx_map_entry(MX6Q, IOMUXC, MT_DEVICE), ++ imx_map_entry(MX6Q, CCM, MT_DEVICE), ++ imx_map_entry(MX6Q, ANATOP, MT_DEVICE), ++ imx_map_entry(MX6Q, GPC, MT_DEVICE), ++ imx_map_entry(MX6Q, L2, MT_DEVICE), ++ imx_map_entry(MX6Q, SEMA4, MT_DEVICE), ++}; ++ ++void __init imx6_pm_map_io(void) ++{ ++ unsigned long i; ++ ++ iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); ++ ++ /* ++ * Get the address of IRAM or OCRAM to be used by the low ++ * power code from the device tree. ++ */ ++ WARN_ON(of_scan_flat_dt(imx6_dt_find_lpsram, NULL)); ++ ++ /* Return if no IRAM space is allocated for suspend/resume code. */ ++ if (!iram_tlb_base_addr) { ++ pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \ ++ code. Please ensure device tree has an entry for \ ++ fsl,lpm-sram.\n"); ++ return; ++ } ++ ++ /* Set all entries to 0. */ ++ memset((void *)iram_tlb_base_addr, 0, MX6Q_IRAM_TLB_SIZE); ++ ++ /* ++ * Make sure the IRAM virtual address has a mapping in the IRAM ++ * page table. ++ * ++ * Only use the top 11 bits [31-20] when storing the physical ++ * address in the page table as only these bits are required ++ * for 1M mapping. ++ */ ++ i = ((iram_tlb_base_addr >> 20) << 2) / 4; ++ *((unsigned long *)iram_tlb_base_addr + i) = ++ (iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; ++ ++ /* ++ * Make sure the AIPS1 virtual address has a mapping in the ++ * IRAM page table. ++ */ ++ i = ((IMX_IO_P2V(MX6Q_AIPS1_BASE_ADDR) >> 20) << 2) / 4; ++ *((unsigned long *)iram_tlb_base_addr + i) = ++ (MX6Q_AIPS1_BASE_ADDR & 0xFFF00000) | ++ TT_ATTRIB_NON_CACHEABLE_1M; ++ ++ /* ++ * Make sure the AIPS2 virtual address has a mapping in the ++ * IRAM page table. ++ */ ++ i = ((IMX_IO_P2V(MX6Q_AIPS2_BASE_ADDR) >> 20) << 2) / 4; ++ *((unsigned long *)iram_tlb_base_addr + i) = ++ (MX6Q_AIPS2_BASE_ADDR & 0xFFF00000) | ++ TT_ATTRIB_NON_CACHEABLE_1M; ++ ++ /* ++ * Make sure the AIPS3 virtual address has a mapping ++ * in the IRAM page table. ++ */ ++ i = ((IMX_IO_P2V(MX6Q_AIPS3_BASE_ADDR) >> 20) << 2) / 4; ++ *((unsigned long *)iram_tlb_base_addr + i) = ++ (MX6Q_AIPS3_BASE_ADDR & 0xFFF00000) | ++ TT_ATTRIB_NON_CACHEABLE_1M; ++ ++ /* ++ * Make sure the L2 controller virtual address has a mapping ++ * in the IRAM page table. ++ */ ++ i = ((IMX_IO_P2V(MX6Q_L2_BASE_ADDR) >> 20) << 2) / 4; ++ *((unsigned long *)iram_tlb_base_addr + i) = ++ (MX6Q_L2_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; ++} ++ ++static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) ++{ ++ struct device_node *node; ++ struct imx6_cpu_pm_info *pm_info; ++ int i, ret = 0; ++ const u32 *mmdc_io_offset_array; ++ const u32 *mmdc_offset_array; ++ unsigned long iram_paddr; ++ ++ suspend_set_ops(&imx6q_pm_ops); ++ ++ if (!socdata) { ++ pr_warn("%s: invalid argument!\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* ++ * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB, ++ * The lower 8K is not used, so use the lower 8K for IRAM code and ++ * pm_info. ++ * ++ */ ++ iram_paddr = iram_tlb_phys_addr + MX6_SUSPEND_IRAM_ADDR_OFFSET; ++ ++ /* Make sure iram_paddr is 8 byte aligned. */ ++ if ((uintptr_t)(iram_paddr) & (FNCPY_ALIGN - 1)) ++ iram_paddr += FNCPY_ALIGN - iram_paddr % (FNCPY_ALIGN); ++ ++ /* Get the virtual address of the suspend code. */ ++ suspend_ocram_base = (void *)IMX_IO_P2V(iram_paddr); ++ ++ pm_info = suspend_ocram_base; ++ /* pbase points to iram_paddr. */ ++ pm_info->pbase = iram_paddr; ++ 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.pbase = MX6Q_CCM_BASE_ADDR; ++ pm_info->ccm_base.vbase = (void __iomem *) ++ IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); ++ ++ pm_info->mmdc_base.pbase = MX6Q_MMDC_P0_BASE_ADDR; ++ pm_info->mmdc_base.vbase = (void __iomem *) ++ IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); ++ ++ pm_info->src_base.pbase = MX6Q_SRC_BASE_ADDR; ++ pm_info->src_base.vbase = (void __iomem *) ++ IMX_IO_P2V(MX6Q_SRC_BASE_ADDR); ++ ++ pm_info->iomuxc_base.pbase = MX6Q_IOMUXC_BASE_ADDR; ++ pm_info->iomuxc_base.vbase = (void __iomem *) ++ IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); ++ ++ pm_info->gpc_base.pbase = MX6Q_GPC_BASE_ADDR; ++ pm_info->gpc_base.vbase = (void __iomem *) ++ IMX_IO_P2V(MX6Q_GPC_BASE_ADDR); ++ ++ pm_info->l2_base.pbase = MX6Q_L2_BASE_ADDR; ++ pm_info->l2_base.vbase = (void __iomem *) ++ IMX_IO_P2V(MX6Q_L2_BASE_ADDR); ++ ++ pm_info->anatop_base.pbase = MX6Q_ANATOP_BASE_ADDR; ++ pm_info->anatop_base.vbase = (void __iomem *) ++ IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); ++ ++ pm_info->ddr_type = imx_mmdc_get_ddr_type(); ++ pm_info->mmdc_io_num = socdata->mmdc_io_num; ++ mmdc_io_offset_array = socdata->mmdc_io_offset; ++ pm_info->mmdc_num = socdata->mmdc_num; ++ mmdc_offset_array = socdata->mmdc_offset; ++ ++ /* initialize MMDC IO settings */ ++ for (i = 0; i < pm_info->mmdc_io_num; i++) { ++ pm_info->mmdc_io_val[i][0] = ++ mmdc_io_offset_array[i]; ++ pm_info->mmdc_io_val[i][1] = ++ readl_relaxed(pm_info->iomuxc_base.vbase + ++ mmdc_io_offset_array[i]); ++ } ++ /* initialize MMDC settings */ ++ for (i = 0; i < pm_info->mmdc_num; i++) { ++ pm_info->mmdc_val[i][0] = ++ mmdc_offset_array[i]; ++ pm_info->mmdc_val[i][1] = ++ readl_relaxed(pm_info->mmdc_base.vbase + ++ mmdc_offset_array[i]); ++ } ++ ++ /* need to overwrite the value for some mmdc registers */ ++ if (cpu_is_imx6sx()) { ++ pm_info->mmdc_val[20][1] = (pm_info->mmdc_val[20][1] ++ & 0xffff0000) | 0x0202; ++ pm_info->mmdc_val[23][1] = 0x8033; ++ } ++ ++ imx6_suspend_in_ocram_fn = fncpy( ++ suspend_ocram_base + sizeof(*pm_info), ++ &imx6_suspend, ++ MX6Q_SUSPEND_OCRAM_SIZE - sizeof(*pm_info)); ++ ++ goto put_node; ++ ++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); ++ ++ if (IS_ENABLED(CONFIG_SUSPEND)) { ++ ret = imx6q_suspend_init(socdata); ++ if (ret) ++ pr_warn("%s: No DDR LPM support with 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, ++ IMX6Q_GPR1_GINT); ++} ++ ++void __init imx6q_pm_init(void) ++{ ++ imx6_pm_common_init(&imx6q_pm_data); ++} ++ ++void __init imx6dl_pm_init(void) ++{ ++ imx6_pm_common_init(&imx6dl_pm_data); ++} ++ ++void __init imx6sl_pm_init(void) ++{ ++ imx6_pm_common_init(&imx6sl_pm_data); ++} ++ ++void __init imx6sx_pm_init(void) ++{ ++ struct device_node *np; ++ struct resource res; ++ ++ imx6_pm_common_init(&imx6sx_pm_data); ++ if (imx_get_soc_revision() < IMX_CHIP_REVISION_1_2) { ++ /* ++ * As there is a 16K OCRAM(start from 0x8f8000) ++ * dedicated for low power function on i.MX6SX, ++ * but ROM did NOT do the ocram address change ++ * accordingly, so we need to add a data patch ++ * to workaround this issue, otherwise, system ++ * will fail to resume from DSM mode. TO1.2 fixes ++ * this issue. ++ */ ++ romcp = syscon_regmap_lookup_by_compatible( ++ "fsl,imx6sx-romcp"); ++ if (IS_ERR(romcp)) { ++ pr_err("failed to find fsl,imx6sx-romcp regmap\n"); ++ return; ++ } ++ regmap_write(romcp, ROMC_ROMPATCH0D, iram_tlb_phys_addr); ++ regmap_update_bits(romcp, ROMC_ROMPATCHCNTL, ++ BM_ROMPATCHCNTL_0D, BM_ROMPATCHCNTL_0D); ++ regmap_update_bits(romcp, ROMC_ROMPATCHENL, ++ BM_ROMPATCHENL_0D, BM_ROMPATCHENL_0D); ++ regmap_write(romcp, ROMC_ROMPATCH0A, ++ ROM_ADDR_FOR_INTERNAL_RAM_BASE); ++ regmap_update_bits(romcp, ROMC_ROMPATCHCNTL, ++ BM_ROMPATCHCNTL_DIS, ~BM_ROMPATCHCNTL_DIS); ++ } ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,mega-fast-sram"); ++ ocram_base = of_iomap(np, 0); ++ WARN_ON(!ocram_base); ++ WARN_ON(of_address_to_resource(np, 0, &res)); ++ ocram_size = resource_size(&res); ++ ocram_saved_in_ddr = kzalloc(ocram_size, GFP_KERNEL); ++ WARN_ON(!ocram_saved_in_ddr); ++ ++ np = of_find_node_by_path( ++ "/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000"); ++ if (np) ++ console_base = of_iomap(np, 0); ++ if (imx_src_is_m4_enabled()) { ++ np = of_find_compatible_node(NULL, NULL, ++ "fsl,imx6sx-qspi-m4-restore"); ++ if (np) ++ qspi_base = of_iomap(np, 0); ++ WARN_ON(!qspi_base); ++ } ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/pm-imx6q.c linux-3.14.72/arch/arm/mach-imx/pm-imx6q.c +--- linux-3.14.72.orig/arch/arm/mach-imx/pm-imx6q.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/pm-imx6q.c 1970-01-01 01:00:00.000000000 +0100 +@@ -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.72.orig/arch/arm/mach-imx/src.c linux-3.14.72/arch/arm/mach-imx/src.c +--- linux-3.14.72.orig/arch/arm/mach-imx/src.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/src.c 2016-06-19 22:11:55.057156252 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -18,6 +18,7 @@ + #include + #include + #include "common.h" ++#include "hardware.h" + + #define SRC_SCR 0x000 + #define SRC_GPR1 0x020 +@@ -32,6 +33,7 @@ + + static void __iomem *src_base; + static DEFINE_SPINLOCK(scr_lock); ++static bool m4_is_enabled; + + static const int sw_reset_bits[5] = { + BP_SRC_SCR_SW_GPU_RST, +@@ -41,6 +43,11 @@ + BP_SRC_SCR_SW_IPU2_RST + }; + ++bool imx_src_is_m4_enabled(void) ++{ ++ return m4_is_enabled; ++} ++ + static int imx_src_reset_module(struct reset_controller_dev *rcdev, + unsigned long sw_reset_idx) + { +@@ -136,6 +143,14 @@ + */ + spin_lock(&scr_lock); + val = readl_relaxed(src_base + SRC_SCR); ++ ++ /* bit 4 is m4c_non_sclr_rst on i.MX6SX */ ++ if (cpu_is_imx6sx() && ((val & ++ (1 << BP_SRC_SCR_SW_OPEN_VG_RST)) == 0)) ++ m4_is_enabled = true; ++ else ++ m4_is_enabled = false; ++ + val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); + writel_relaxed(val, src_base + SRC_SCR); + spin_unlock(&scr_lock); +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/suspend-imx6.S linux-3.14.72/arch/arm/mach-imx/suspend-imx6.S +--- linux-3.14.72.orig/arch/arm/mach-imx/suspend-imx6.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mach-imx/suspend-imx6.S 2016-06-19 22:11:55.057156252 +0200 +@@ -0,0 +1,661 @@ ++/* ++ * Copyright (C) 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_DDR_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_MX6Q_ANATOP_P_OFFSET 0x40 ++#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x44 ++#define PM_INFO_MX6Q_TTBR1_V_OFFSET 0x48 ++#define PM_INFO_MMDC_IO_NUM_OFFSET 0x4c ++#define PM_INFO_MMDC_IO_VAL_OFFSET 0x50 ++/* below offsets depends on MX6_MAX_MMDC_IO_NUM(33) definition */ ++#define PM_INFO_MMDC_NUM_OFFSET 0x158 ++#define PM_INFO_MMDC_VAL_OFFSET 0x15c ++ ++#define MX6Q_SRC_GPR1 0x20 ++#define MX6Q_SRC_GPR2 0x24 ++#define MX6Q_MMDC_MAPSR 0x404 ++#define MX6Q_MMDC_MPDGCTRL0 0x83c ++#define MX6Q_GPC_IMR1 0x08 ++#define MX6Q_GPC_IMR2 0x0c ++#define MX6Q_GPC_IMR3 0x10 ++#define MX6Q_GPC_IMR4 0x14 ++#define MX6Q_CCM_CCR 0x0 ++#define MX6Q_ANATOP_CORE 0x140 ++ ++#define MX6_MAX_MMDC_IO_NUM 33 ++#define MX6_MAX_MMDC_NUM 34 ++ ++ .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 ++ ++ /* r11 must be MMDC base address */ ++ .macro reset_read_fifo ++ ++ /* reset read FIFO, RST_RD_FIFO */ ++ ldr r7, =MX6Q_MMDC_MPDGCTRL0 ++ ldr r6, [r11, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r11, r7] ++2: ++ ldr r6, [r11, r7] ++ ands r6, r6, #(1 << 31) ++ bne 2b ++ ++ /* reset FIFO a second time */ ++ ldr r6, [r11, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r11, r7] ++3: ++ ldr r6, [r11, r7] ++ ands r6, r6, #(1 << 31) ++ bne 3b ++ ++ .endm ++ ++ /* r11 must be MMDC base address */ ++ .macro mmdc_out_and_auto_self_refresh ++ ++ /* let DDR out of self-refresh */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #(1 << 21) ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++4: ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ bne 4b ++ ++ /* enable DDR auto power saving */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #0x1 ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++ ++ .endm ++ ++ /* r10 must be iomuxc base address */ ++ .macro resume_iomuxc_gpr ++ ++ add r10, r10, #0x4000 ++ /* IOMUXC GPR DRAM_RESET_BYPASS */ ++ ldr r4, [r10, #0x8] ++ bic r4, r4, #(0x1 << 27) ++ str r4, [r10, #0x8] ++ /* IOMUXC GPR DRAM_CKE_BYPASS */ ++ ldr r4, [r10, #0x8] ++ bic r4, r4, #(0x1 << 31) ++ str r4, [r10, #0x8] ++ ++ .endm ++ ++ .macro resume_io ++ ++ /* restore MMDC IO */ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] ++ ldrne r10, [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 ++5: ++ ldr r8, [r7], #0x4 ++ ldr r9, [r7], #0x4 ++ str r9, [r10, r8] ++ subs r6, r6, #0x1 ++ bne 5b ++ ++ cmp r5, #0x0 ++ /* Here only MMDC0 is set */ ++ ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ++ ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] ++ ++ cmp r3, #IMX_DDR_TYPE_LPDDR2 ++ bne 6f ++ ++ reset_read_fifo ++6: ++ mmdc_out_and_auto_self_refresh ++ ++ .endm ++ ++ .macro resume_mmdc_io ++ ++ cmp r5, #0x0 ++ ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] ++ ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] ++ ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ++ ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] ++ ++ /* resume mmdc iomuxc settings */ ++ ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] ++ ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET ++ add r7, r7, r0 ++7: ++ ldr r8, [r7], #0x4 ++ ldr r9, [r7], #0x4 ++ str r9, [r10, r8] ++ subs r6, r6, #0x1 ++ bne 7b ++ ++ /* check whether we need to restore MMDC */ ++ cmp r5, #0x0 ++ beq 8f ++ ++ /* check whether last suspend is with M/F mix off */ ++ ldr r9, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET] ++ ldr r6, [r9, #0x220] ++ cmp r6, #0x0 ++ bne 9f ++8: ++ resume_iomuxc_gpr ++ ++ b 13f ++9: ++ /* restore MMDC settings */ ++ ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] ++ ldr r7, =PM_INFO_MMDC_VAL_OFFSET ++ add r7, r7, r0 ++10: ++ ldr r8, [r7], #0x4 ++ ldr r9, [r7], #0x4 ++ str r9, [r11, r8] ++ subs r6, r6, #0x1 ++ bne 10b ++ ++ /* let DDR enter self-refresh */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #(1 << 20) ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++11: ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 24) ++ beq 11b ++ ++ resume_iomuxc_gpr ++ ++ reset_read_fifo ++ ++ /* let DDR out of self-refresh */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #(1 << 20) ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++12: ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 24) ++ bne 12b ++ ++ /* kick off MMDC */ ++ ldr r4, =0x0 ++ str r4, [r11, #0x1c] ++13: ++ mmdc_out_and_auto_self_refresh ++ ++ .endm ++ ++ .macro store_ttbr1 ++ ++ /* Store TTBR1 to pm_info->ttbr1 */ ++ mrc p15, 0, r7, c2, c0, 1 ++ str r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET] ++ ++ /* Disable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the BTAC. */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ ldr r6, =iram_tlb_phys_addr ++ ldr r6, [r6] ++ dsb ++ isb ++ ++ /* Store the IRAM table in TTBR1 */ ++ mcr p15, 0, r6, c2, c0, 1 ++ /* Read TTBCR and set PD0=1, N = 1 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ orr r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ /* Disable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ bic r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ dsb ++ isb ++ ++#ifdef CONFIG_CACHE_L2X0 ++ ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] ++ mov r6, #0x0 ++ str r6, [r8, #0x100] ++ ++ dsb ++ isb ++#endif ++ ++ .endm ++ ++ .macro restore_ttbr1 ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* Enable L2. */ ++ ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] ++ ldr r7, =0x1 ++ str r7, [r8, #0x100] ++#endif ++ ++ /* Enable L1 data cache. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x4 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ dsb ++ isb ++ ++ /* Restore TTBCR */ ++ /* Read TTBCR and set PD0=0, N = 0 */ ++ mrc p15, 0, r6, c2, c0, 2 ++ bic r6, r6, #0x11 ++ mcr p15, 0, r6, c2, c0, 2 ++ dsb ++ isb ++ ++ /* flush the TLB */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c8, c3, 0 ++ ++ /* Enable Branch Prediction, Z bit in SCTLR. */ ++ mrc p15, 0, r6, c1, c0, 0 ++ orr r6, r6, #0x800 ++ mcr p15, 0, r6, c1, c0, 0 ++ ++ /* Flush the Branch Target Address Cache (BTAC) */ ++ ldr r6, =0x0 ++ mcr p15, 0, r6, c7, c1, 6 ++ ++ /* Restore TTBR1, get the origin ttbr1 from pm info */ ++ ldr r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET] ++ mcr p15, 0, r7, c2, c0, 1 ++ ++ .endm ++ ++ENTRY(imx6_suspend) ++ push {r4-r12} ++ /* ++ * The value of r0 is mapped the same in origin table and IRAM table, ++ * thus no need to care r0 here. ++ */ ++ ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ++ ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] ++ ldr r3, [r0, #PM_INFO_DDR_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_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 ++ ++ store_ttbr1 ++ ++ 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 ++ ++ /* use r11 to store the IO address */ ++ 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 ++ /* LPDDR2's last 3 IOs need special setting */ ++ cmp r3, #IMX_DDR_TYPE_LPDDR2 ++ subeq r7, r7, #0x3 ++set_mmdc_io_lpm: ++ ldr r9, [r8], #0x8 ++ str r6, [r11, r9] ++ subs r7, r7, #0x1 ++ bne set_mmdc_io_lpm ++ ++ cmp r3, #IMX_DDR_TYPE_LPDDR2 ++ bne set_mmdc_io_lpm_done ++ ldr r6, =0x1000 ++ ldr r9, [r8], #0x8 ++ str r6, [r11, r9] ++ ldr r9, [r8], #0x8 ++ str r6, [r11, r9] ++ ldr r6, =0x80000 ++ ldr r9, [r8] ++ str r6, [r11, r9] ++set_mmdc_io_lpm_done: ++ ++ /* check whether it supports Mega/Fast off */ ++ ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] ++ cmp r6, #0x0 ++ beq set_mmdc_lpm_done ++ ++ /* IOMUXC GPR DRAM_RESET */ ++ add r11, r11, #0x4000 ++ ldr r6, [r11, #0x8] ++ orr r6, r6, #(0x1 << 28) ++ str r6, [r11, #0x8] ++ ++ /* IOMUXC GPR DRAM_RESET_BYPASS */ ++ ldr r6, [r11, #0x8] ++ orr r6, r6, #(0x1 << 27) ++ str r6, [r11, #0x8] ++ ++ /* IOMUXC GPR DRAM_CKE_BYPASS */ ++ ldr r6, [r11, #0x8] ++ orr r6, r6, #(0x1 << 31) ++ str r6, [r11, #0x8] ++set_mmdc_lpm_done: ++ ++ /* ++ * 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 ++ ++ /* ++ * ERR005852 Analog: Transition from Deep Sleep Mode to ++ * LDO Bypass Mode may cause the slow response of the ++ * VDDARM_CAP output. ++ * ++ * Software workaround: ++ * if internal ldo(VDDARM) bypassed, switch to analog bypass ++ * mode (0x1E), prio to entering DSM, and then, revert to the ++ * normal bypass mode, when exiting from DSM. ++ */ ++ ldr r11, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET] ++ ldr r10, [r11, #MX6Q_ANATOP_CORE] ++ and r10, r10, #0x1f ++ cmp r10, #0x1f ++ bne ldo_check_done1 ++ldo_analog_bypass: ++ ldr r10, [r11, #MX6Q_ANATOP_CORE] ++ bic r10, r10, #0x1f ++ orr r10, r10, #0x1e ++ str r10, [r11, #MX6Q_ANATOP_CORE] ++ldo_check_done1: ++ /* Zzz, enter stop mode */ ++ wfi ++ nop ++ nop ++ nop ++ nop ++ ++ /* ++ * run to here means there is pending ++ * wakeup source, system should auto ++ * resume, we need to restore MMDC IO first ++ */ ++ /* restore it with 0x1f if use ldo bypass mode.*/ ++ ldr r10, [r11, #MX6Q_ANATOP_CORE] ++ and r10, r10, #0x1f ++ cmp r10, #0x1e ++ bne ldo_check_done2 ++ldo_bypass_restore: ++ ldr r10, [r11, #MX6Q_ANATOP_CORE] ++ orr r10, r10, #0x1f ++ str r10, [r11, #MX6Q_ANATOP_CORE] ++ldo_check_done2: ++ ++ mov r5, #0x0 ++ /* check whether it supports Mega/Fast off */ ++ ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] ++ cmp r6, #0x0 ++ beq only_resume_io ++ resume_mmdc_io ++ b resume_mmdc_done ++only_resume_io: ++ resume_io ++resume_mmdc_done: ++ restore_ttbr1 ++ ++ pop {r4-r12} ++ /* 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 ++ ++ /* restore it with 0x1f if use ldo bypass mode.*/ ++ ldr r11, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET] ++ ldr r7, [r11, #MX6Q_ANATOP_CORE] ++ and r7, r7, #0x1f ++ cmp r7, #0x1e ++ bne ldo_check_done3 ++ ldr r7, [r11, #MX6Q_ANATOP_CORE] ++ orr r7, r7, #0x1f ++ str r7, [r11, #MX6Q_ANATOP_CORE] ++ldo_check_done3: ++ /* 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 ++ /* check whether it supports Mega/Fast off */ ++ ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET] ++ cmp r6, #0x0 ++ beq dsm_only_resume_io ++ resume_mmdc_io ++ b dsm_resume_mmdc_done ++dsm_only_resume_io: ++ ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] ++ resume_io ++dsm_resume_mmdc_done: ++ ++ 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. ++ */ ++ ++#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) +diff -Nur linux-3.14.72.orig/arch/arm/mach-imx/system.c linux-3.14.72/arch/arm/mach-imx/system.c +--- linux-3.14.72.orig/arch/arm/mach-imx/system.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/system.c 2016-06-19 22:11:55.057156252 +0200 +@@ -1,7 +1,7 @@ + /* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd +- * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2006-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com + * +@@ -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,17 @@ + + 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. ++ * For i.MX6SX we have to trigger wdog-reset to reset QSPI-NOR flash to ++ * workaround qspi-nor reboot issue whatever ldo-bypass or not. ++ */ ++ else if ((wdog_source == 2 && (cpu_is_imx6q() || cpu_is_imx6dl() || ++ cpu_is_imx6sl())) || cpu_is_imx6sx()) ++ wcr_enable = 0x14; + else + wcr_enable = (1 << 2); + +@@ -90,12 +102,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 +153,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 +166,14 @@ + */ + 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); ++ val = L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN; ++ writel_relaxed(val, l2x0_base + L310_POWER_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.72.orig/arch/arm/mach-imx/time.c linux-3.14.72/arch/arm/mach-imx/time.c +--- linux-3.14.72.orig/arch/arm/mach-imx/time.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-imx/time.c 2016-06-19 22:11:55.057156252 +0200 +@@ -25,8 +25,12 @@ + #include + #include + #include ++#include + #include + #include ++#include ++#include ++#include + + #include + +@@ -56,11 +60,15 @@ + #define MX2_TSTAT_CAPT (1 << 1) + #define MX2_TSTAT_COMP (1 << 0) + +-/* MX31, MX35, MX25, MX5 */ ++/* MX31, MX35, MX25, MX5, MX6 */ + #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) +@@ -116,11 +124,22 @@ + return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0; + } + ++static struct delay_timer imx_delay_timer; ++ ++static unsigned long imx_read_current_timer(void) ++{ ++ return __raw_readl(sched_clock_reg); ++} ++ + static int __init mxc_clocksource_init(struct clk *timer_clk) + { + unsigned int c = clk_get_rate(timer_clk); + void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN); + ++ imx_delay_timer.read_current_timer = &imx_read_current_timer; ++ imx_delay_timer.freq = c; ++ register_current_timer_delay(&imx_delay_timer); ++ + sched_clock_reg = reg; + + sched_clock_register(mxc_read_sched_clock, 32, c); +@@ -277,11 +296,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() || cpu_is_imx6sx()) ++ 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 +330,25 @@ + __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() || ++ cpu_is_imx6sx()) { ++ tctl_val = V2_TCTL_CLK_OSC_DIV8 | V2_TCTL_FRR | ++ V2_TCTL_WAITEN | MXC_TCTL_TEN; ++ if (cpu_is_imx6dl() || cpu_is_imx6sx()) { ++ /* 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); + +@@ -316,3 +359,15 @@ + /* Make irqs happen */ + setup_irq(irq, &mxc_timer_irq); + } ++ ++void __init mxc_timer_init_dt(struct device_node *np) ++{ ++ void __iomem *base; ++ int irq; ++ ++ base = of_iomap(np, 0); ++ WARN_ON(!base); ++ irq = irq_of_parse_and_map(np, 0); ++ ++ mxc_timer_init(base, irq); ++} +diff -Nur linux-3.14.72.orig/arch/arm/mach-nomadik/cpu-8815.c linux-3.14.72/arch/arm/mach-nomadik/cpu-8815.c +--- linux-3.14.72.orig/arch/arm/mach-nomadik/cpu-8815.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-nomadik/cpu-8815.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-omap2/omap4-common.c linux-3.14.72/arch/arm/mach-omap2/omap4-common.c +--- linux-3.14.72.orig/arch/arm/mach-omap2/omap4-common.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-omap2/omap4-common.c 2016-06-19 22:11:55.057156252 +0200 +@@ -166,22 +166,38 @@ + 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) + { +- u32 aux_ctrl = 0; ++ u32 aux_ctrl; + + /* + * To avoid code running on other OMAPs in +@@ -195,42 +211,19 @@ + 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 = L310_AUX_CTRL_CACHE_REPLACE_RR | ++ L310_AUX_CTRL_NS_LOCKDOWN | ++ L310_AUX_CTRL_NS_INT_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, 0xc19fffff); + 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, 0xc19fffff); + + return 0; + } +diff -Nur linux-3.14.72.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c linux-3.14.72/arch/arm/mach-omap2/omap-mpuss-lowpower.c +--- linux-3.14.72.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2016-06-19 22:11:55.057156252 +0200 +@@ -194,7 +194,7 @@ + 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); ++ val = __raw_readl(l2x0_base + L310_PREFETCH_CTRL); + __raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET); + } + } +diff -Nur linux-3.14.72.orig/arch/arm/mach-prima2/l2x0.c linux-3.14.72/arch/arm/mach-prima2/l2x0.c +--- linux-3.14.72.orig/arch/arm/mach-prima2/l2x0.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-prima2/l2x0.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-prima2/pm.c linux-3.14.72/arch/arm/mach-prima2/pm.c +--- linux-3.14.72.orig/arch/arm/mach-prima2/pm.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-prima2/pm.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-realview/realview_eb.c linux-3.14.72/arch/arm/mach-realview/realview_eb.c +--- linux-3.14.72.orig/arch/arm/mach-realview/realview_eb.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-realview/realview_eb.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-realview/realview_pb1176.c linux-3.14.72/arch/arm/mach-realview/realview_pb1176.c +--- linux-3.14.72.orig/arch/arm/mach-realview/realview_pb1176.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-realview/realview_pb1176.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-realview/realview_pb11mp.c linux-3.14.72/arch/arm/mach-realview/realview_pb11mp.c +--- linux-3.14.72.orig/arch/arm/mach-realview/realview_pb11mp.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-realview/realview_pb11mp.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-realview/realview_pbx.c linux-3.14.72/arch/arm/mach-realview/realview_pbx.c +--- linux-3.14.72.orig/arch/arm/mach-realview/realview_pbx.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-realview/realview_pbx.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-rockchip/rockchip.c linux-3.14.72/arch/arm/mach-rockchip/rockchip.c +--- linux-3.14.72.orig/arch/arm/mach-rockchip/rockchip.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-rockchip/rockchip.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-shmobile/board-armadillo800eva.c linux-3.14.72/arch/arm/mach-shmobile/board-armadillo800eva.c +--- linux-3.14.72.orig/arch/arm/mach-shmobile/board-armadillo800eva.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-shmobile/board-armadillo800eva.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-shmobile/board-armadillo800eva-reference.c linux-3.14.72/arch/arm/mach-shmobile/board-armadillo800eva-reference.c +--- linux-3.14.72.orig/arch/arm/mach-shmobile/board-armadillo800eva-reference.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-shmobile/board-armadillo800eva-reference.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-shmobile/board-kzm9g.c linux-3.14.72/arch/arm/mach-shmobile/board-kzm9g.c +--- linux-3.14.72.orig/arch/arm/mach-shmobile/board-kzm9g.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-shmobile/board-kzm9g.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-shmobile/board-kzm9g-reference.c linux-3.14.72/arch/arm/mach-shmobile/board-kzm9g-reference.c +--- linux-3.14.72.orig/arch/arm/mach-shmobile/board-kzm9g-reference.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-shmobile/board-kzm9g-reference.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-shmobile/setup-r8a7778.c linux-3.14.72/arch/arm/mach-shmobile/setup-r8a7778.c +--- linux-3.14.72.orig/arch/arm/mach-shmobile/setup-r8a7778.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-shmobile/setup-r8a7778.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-shmobile/setup-r8a7779.c linux-3.14.72/arch/arm/mach-shmobile/setup-r8a7779.c +--- linux-3.14.72.orig/arch/arm/mach-shmobile/setup-r8a7779.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-shmobile/setup-r8a7779.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-socfpga/socfpga.c linux-3.14.72/arch/arm/mach-socfpga/socfpga.c +--- linux-3.14.72.orig/arch/arm/mach-socfpga/socfpga.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-socfpga/socfpga.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-spear/platsmp.c linux-3.14.72/arch/arm/mach-spear/platsmp.c +--- linux-3.14.72.orig/arch/arm/mach-spear/platsmp.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-spear/platsmp.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-spear/spear13xx.c linux-3.14.72/arch/arm/mach-spear/spear13xx.c +--- linux-3.14.72.orig/arch/arm/mach-spear/spear13xx.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-spear/spear13xx.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-sti/board-dt.c linux-3.14.72/arch/arm/mach-sti/board-dt.c +--- linux-3.14.72.orig/arch/arm/mach-sti/board-dt.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-sti/board-dt.c 2016-06-19 22:11:55.057156252 +0200 +@@ -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.72.orig/arch/arm/mach-tegra/sleep.h linux-3.14.72/arch/arm/mach-tegra/sleep.h +--- linux-3.14.72.orig/arch/arm/mach-tegra/sleep.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-tegra/sleep.h 2016-06-19 22:11:55.061155987 +0200 +@@ -134,13 +134,13 @@ + tst \tmp3, #L2X0_CTRL_EN + bne exit_l2_resume + ldr \tmp3, [\tmp1, #L2X0_R_TAG_LATENCY] +- str \tmp3, [\tmp2, #L2X0_TAG_LATENCY_CTRL] ++ str \tmp3, [\tmp2, #L310_TAG_LATENCY_CTRL] + ldr \tmp3, [\tmp1, #L2X0_R_DATA_LATENCY] +- str \tmp3, [\tmp2, #L2X0_DATA_LATENCY_CTRL] ++ str \tmp3, [\tmp2, #L310_DATA_LATENCY_CTRL] + ldr \tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL] +- str \tmp3, [\tmp2, #L2X0_PREFETCH_CTRL] ++ str \tmp3, [\tmp2, #L310_PREFETCH_CTRL] + ldr \tmp3, [\tmp1, #L2X0_R_PWR_CTRL] +- str \tmp3, [\tmp2, #L2X0_POWER_CTRL] ++ str \tmp3, [\tmp2, #L310_POWER_CTRL] + ldr \tmp3, [\tmp1, #L2X0_R_AUX_CTRL] + str \tmp3, [\tmp2, #L2X0_AUX_CTRL] + mov \tmp3, #L2X0_CTRL_EN +diff -Nur linux-3.14.72.orig/arch/arm/mach-tegra/tegra.c linux-3.14.72/arch/arm/mach-tegra/tegra.c +--- linux-3.14.72.orig/arch/arm/mach-tegra/tegra.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-tegra/tegra.c 2016-06-19 22:11:55.061155987 +0200 +@@ -73,25 +73,9 @@ + 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); ++ ret = l2x0_of_init(0x3c400001, 0xc20fc3fe); + if (!ret) + l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs); + #endif +diff -Nur linux-3.14.72.orig/arch/arm/mach-ux500/cache-l2x0.c linux-3.14.72/arch/arm/mach-ux500/cache-l2x0.c +--- linux-3.14.72.orig/arch/arm/mach-ux500/cache-l2x0.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-ux500/cache-l2x0.c 2016-06-19 22:11:55.061155987 +0200 +@@ -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.72.orig/arch/arm/mach-vexpress/ct-ca9x4.c linux-3.14.72/arch/arm/mach-vexpress/ct-ca9x4.c +--- linux-3.14.72.orig/arch/arm/mach-vexpress/ct-ca9x4.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-vexpress/ct-ca9x4.c 2016-06-19 22:11:55.061155987 +0200 +@@ -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.72.orig/arch/arm/mach-zynq/common.c linux-3.14.72/arch/arm/mach-zynq/common.c +--- linux-3.14.72.orig/arch/arm/mach-zynq/common.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mach-zynq/common.c 2016-06-19 22:11:55.061155987 +0200 +@@ -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.72.orig/arch/arm/mm/cache-feroceon-l2.c linux-3.14.72/arch/arm/mm/cache-feroceon-l2.c +--- linux-3.14.72.orig/arch/arm/mm/cache-feroceon-l2.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mm/cache-feroceon-l2.c 2016-06-19 22:11:55.061155987 +0200 +@@ -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.72.orig/arch/arm/mm/cache-l2x0.c linux-3.14.72/arch/arm/mm/cache-l2x0.c +--- linux-3.14.72.orig/arch/arm/mm/cache-l2x0.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mm/cache-l2x0.c 2016-06-19 22:11:55.061155987 +0200 +@@ -24,10 +24,22 @@ + #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 +48,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 +173,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,250 +188,610 @@ + 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) ++/* ++ * 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) + { +- unsigned long flags; ++ writel_relaxed(0, base + sync_reg_offset); ++} + +- /* 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); ++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 l2x0_inv_range(unsigned long start, unsigned long end) ++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, ++ .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 const struct l2c_init_data l2c220_data = { ++ .type = "L2C-220", ++ .way_size_0 = SZ_8K, ++ .num_lock = 1, ++ .enable = l2c_enable, ++ .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; +- break; +- default: +- /* L210 and unknown types */ +- lockregs = 1; +- break; ++ 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); + } ++} + +- 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; ++ } + } ++ ++ l2c_enable(base, aux, num_lock); + } + +-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; ++ ++ 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"; ++ } ++ } + +- 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_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 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 = l2c_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"); + ++ /* ++ * It is strange to save the register state before initialisation, ++ * but hey, this is what the DT implementations decided to do. ++ */ ++ if (data->save) ++ data->save(l2x0_base); ++ ++ 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 = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17; +- way_size = 1 << (way_size + way_size_shift); +- +- l2x0_size = ways * way_size * SZ_1K; ++ 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 you are booting from non-secure mode +- * accessing the below registers will fault. ++ * Check if l2x0 controller is already enabled. If we are booting ++ * in non-secure mode accessing the below registers will fault. + */ +- 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); +- +- /* l2x0 controller is disabled */ +- writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); +- +- l2x0_inv_all(); +- +- /* enable L2X0 */ +- writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); +- } ++ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) ++ data->enable(l2x0_base, aux, data->num_lock); + + /* Re-read it in case some bits are reserved. */ + aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); +@@ -408,23 +799,178 @@ + /* Save the value for resuming. */ + l2x0_saved_regs.aux_ctrl = aux; + +- 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; ++ outer_cache = fns; ++ ++ 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); ++} ++ ++void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) ++{ ++ const struct l2c_init_data *data; ++ u32 cache_id; ++ ++ l2x0_base = base; ++ ++ 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; + } + +- 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); ++ __l2c_init(data, aux_val, aux_mask, cache_id); + } + +-#ifdef CONFIG_OF +-static int l2_wt_override; ++#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; ++ } ++ ++ *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, ++ .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 = l2c_enable, ++ .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 }; ++ u32 val; ++ ++ 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); ++ ++ 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); ++ } ++ ++ val = 0; ++ if (of_property_read_bool(np, "arm,dynamic-clk-gating")) ++ val |= L310_DYNAMIC_CLK_GATING_EN; ++ if (of_property_read_bool(np, "arm,standby-mode")) ++ val |= L310_STNDBY_MODE_EN; ++ ++ if (val) ++ l2c_write_sec(val, l2x0_base, L310_POWER_CTRL); ++} ++ ++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 = l2c_disable, ++ .sync = l2c210_sync, ++ .resume = l2c310_resume, ++ }, ++}; + + /* + * Note that the end addresses passed to Linux primitives are +@@ -524,6 +1070,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 +1228,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 +1250,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 +1278,7 @@ + return; + + if ((end - start) >= l2x0_size) { +- l2x0_flush_all(); ++ outer_cache.flush_all(); + return; + } + +@@ -652,283 +1287,65 @@ + + /* 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); +- } +-} +- +-static void aurora_save(void) +-{ +- l2x0_saved_regs.ctrl = readl_relaxed(l2x0_base + L2X0_CTRL); +- l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_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 = l2c_disable, ++ .sync = l2c210_sync, ++ .resume = l2c310_resume, ++ }, ++}; + +-static void __init tauros3_save(void) ++static void __init tauros3_save(void __iomem *base) + { + 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 +1353,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 +1389,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.72.orig/arch/arm/mm/dma-mapping.c linux-3.14.72/arch/arm/mm/dma-mapping.c +--- linux-3.14.72.orig/arch/arm/mm/dma-mapping.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mm/dma-mapping.c 2016-06-19 22:11:55.061155987 +0200 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +diff -Nur linux-3.14.72.orig/arch/arm/mm/Kconfig linux-3.14.72/arch/arm/mm/Kconfig +--- linux-3.14.72.orig/arch/arm/mm/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mm/Kconfig 2016-06-19 22:11:55.061155987 +0200 +@@ -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.72.orig/arch/arm/mm/l2c-common.c linux-3.14.72/arch/arm/mm/l2c-common.c +--- linux-3.14.72.orig/arch/arm/mm/l2c-common.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/arch/arm/mm/l2c-common.c 2016-06-19 22:11:55.061155987 +0200 +@@ -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.72.orig/arch/arm/mm/Makefile linux-3.14.72/arch/arm/mm/Makefile +--- linux-3.14.72.orig/arch/arm/mm/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mm/Makefile 2016-06-19 22:11:55.061155987 +0200 +@@ -95,6 +95,7 @@ + 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_XSC3L2) += cache-xsc3l2.o +diff -Nur linux-3.14.72.orig/arch/arm/mm/proc-v7.S linux-3.14.72/arch/arm/mm/proc-v7.S +--- linux-3.14.72.orig/arch/arm/mm/proc-v7.S 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/arm/mm/proc-v7.S 2016-06-19 22:11:55.061155987 +0200 +@@ -152,6 +152,40 @@ + ENDPROC(cpu_v7_do_resume) + #endif + ++/* ++ * Cortex-A9 processor functions ++ */ ++ globl_equ cpu_ca9mp_proc_init, cpu_v7_proc_init ++ globl_equ cpu_ca9mp_proc_fin, cpu_v7_proc_fin ++ globl_equ cpu_ca9mp_reset, cpu_v7_reset ++ globl_equ cpu_ca9mp_do_idle, cpu_v7_do_idle ++ globl_equ cpu_ca9mp_dcache_clean_area, cpu_v7_dcache_clean_area ++ globl_equ cpu_ca9mp_switch_mm, cpu_v7_switch_mm ++ globl_equ cpu_ca9mp_set_pte_ext, cpu_v7_set_pte_ext ++.globl cpu_ca9mp_suspend_size ++.equ cpu_ca9mp_suspend_size, cpu_v7_suspend_size + 4 * 2 ++#ifdef CONFIG_ARM_CPU_SUSPEND ++ENTRY(cpu_ca9mp_do_suspend) ++ stmfd sp!, {r4 - r5} ++ mrc p15, 0, r4, c15, c0, 1 @ Diagnostic register ++ mrc p15, 0, r5, c15, c0, 0 @ Power register ++ stmia r0!, {r4 - r5} ++ ldmfd sp!, {r4 - r5} ++ b cpu_v7_do_suspend ++ENDPROC(cpu_ca9mp_do_suspend) ++ ++ENTRY(cpu_ca9mp_do_resume) ++ ldmia r0!, {r4 - r5} ++ mrc p15, 0, r10, c15, c0, 1 @ Read Diagnostic register ++ teq r4, r10 @ Already restored? ++ mcrne p15, 0, r4, c15, c0, 1 @ No, so restore it ++ mrc p15, 0, r10, c15, c0, 0 @ Read Power register ++ teq r5, r10 @ Already restored? ++ mcrne p15, 0, r5, c15, c0, 0 @ No, so restore it ++ b cpu_v7_do_resume ++ENDPROC(cpu_ca9mp_do_resume) ++#endif ++ + #ifdef CONFIG_CPU_PJ4B + globl_equ cpu_pj4b_switch_mm, cpu_v7_switch_mm + globl_equ cpu_pj4b_set_pte_ext, cpu_v7_set_pte_ext +@@ -392,6 +426,7 @@ + + @ define struct processor (see and proc-macros.S) + define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 ++ define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 + #ifdef CONFIG_CPU_PJ4B + define_processor_functions pj4b, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 + #endif +@@ -444,7 +479,7 @@ + __v7_ca9mp_proc_info: + .long 0x410fc090 + .long 0xff0ffff0 +- __v7_proc __v7_ca9mp_setup ++ __v7_proc __v7_ca9mp_setup, proc_fns = ca9mp_processor_functions + .size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info + + #endif /* CONFIG_ARM_LPAE */ +diff -Nur linux-3.14.72.orig/arch/x86/include/asm/idle.h linux-3.14.72/arch/x86/include/asm/idle.h +--- linux-3.14.72.orig/arch/x86/include/asm/idle.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/x86/include/asm/idle.h 2016-06-19 22:11:55.061155987 +0200 +@@ -1,13 +1,6 @@ + #ifndef _ASM_X86_IDLE_H + #define _ASM_X86_IDLE_H + +-#define IDLE_START 1 +-#define IDLE_END 2 +- +-struct notifier_block; +-void idle_notifier_register(struct notifier_block *n); +-void idle_notifier_unregister(struct notifier_block *n); +- + #ifdef CONFIG_X86_64 + void enter_idle(void); + void exit_idle(void); +diff -Nur linux-3.14.72.orig/arch/x86/kernel/process.c linux-3.14.72/arch/x86/kernel/process.c +--- linux-3.14.72.orig/arch/x86/kernel/process.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/x86/kernel/process.c 2016-06-19 22:11:55.061155987 +0200 +@@ -41,19 +41,6 @@ + + #ifdef CONFIG_X86_64 + static DEFINE_PER_CPU(unsigned char, is_idle); +-static ATOMIC_NOTIFIER_HEAD(idle_notifier); +- +-void idle_notifier_register(struct notifier_block *n) +-{ +- atomic_notifier_chain_register(&idle_notifier, n); +-} +-EXPORT_SYMBOL_GPL(idle_notifier_register); +- +-void idle_notifier_unregister(struct notifier_block *n) +-{ +- atomic_notifier_chain_unregister(&idle_notifier, n); +-} +-EXPORT_SYMBOL_GPL(idle_notifier_unregister); + #endif + + struct kmem_cache *task_xstate_cachep; +@@ -258,14 +245,14 @@ + void enter_idle(void) + { + this_cpu_write(is_idle, 1); +- atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); ++ idle_notifier_call_chain(IDLE_START); + } + + static void __exit_idle(void) + { + if (x86_test_and_clear_bit_percpu(0, is_idle) == 0) + return; +- atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); ++ idle_notifier_call_chain(IDLE_END); + } + + /* Called from interrupts to signify idle end */ +diff -Nur linux-3.14.72.orig/arch/x86/kernel/setup.c linux-3.14.72/arch/x86/kernel/setup.c +--- linux-3.14.72.orig/arch/x86/kernel/setup.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/arch/x86/kernel/setup.c 2016-06-19 22:11:55.061155987 +0200 +@@ -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.72.orig/block/bfq-cgroup.c linux-3.14.72/block/bfq-cgroup.c +--- linux-3.14.72.orig/block/bfq-cgroup.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/block/bfq-cgroup.c 2016-06-19 22:11:55.061155987 +0200 +@@ -0,0 +1,938 @@ ++/* ++ * 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 { ++ if (bgrp->weight < BFQ_MIN_WEIGHT || ++ bgrp->weight > BFQ_MAX_WEIGHT) { ++ printk(KERN_CRIT "bfq_group_init_entity: " ++ "bgrp->weight %d\n", bgrp->weight); ++ BUG(); ++ } ++ 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.72.orig/block/bfq.h linux-3.14.72/block/bfq.h +--- linux-3.14.72.orig/block/bfq.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/block/bfq.h 2016-06-19 22:11:55.065155743 +0200 +@@ -0,0 +1,807 @@ ++/* ++ * BFQ-v7r8 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_QUEUE_IOPRIO 4 ++ ++#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. ++ * @burst_list_node: node for the device's burst list. ++ * @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; ++ ++ struct hlist_node burst_list_node; ++ ++ 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 ++ * @saved_in_large_burst: same purpose as the previous fields for the ++ * value of the field keeping the queue's belonging ++ * to a large burst ++ * @was_in_burst_list: true if the queue belonged to a burst list ++ * before its merge with another cooperating 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; ++ bool saved_idle_window; ++ bool saved_IO_bound; ++ ++ bool saved_in_large_burst; ++ bool was_in_burst_list; ++ ++ 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_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). ++ * @last_ins_in_burst: last time at which a queue entered the current ++ * burst of queues being activated shortly after ++ * each other; for more details about this and the ++ * following parameters related to a burst of ++ * activations, see the comments to the function ++ * @bfq_handle_burst. ++ * @bfq_burst_interval: reference time interval used to decide whether a ++ * queue has been activated shortly after ++ * @last_ins_in_burst. ++ * @burst_size: number of queues in the current burst of queue activations. ++ * @bfq_large_burst_thresh: maximum burst size above which the current ++ * queue-activation burst is deemed as 'large'. ++ * @large_burst: true if a large queue-activation burst is in progress. ++ * @burst_list: head of the burst list (as for the above fields, more details ++ * in the comments to the function bfq_handle_burst). ++ * @low_latency: if set to true, low-latency heuristics are enabled. ++ * @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_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; ++ ++ unsigned long last_ins_in_burst; ++ unsigned long bfq_burst_interval; ++ int burst_size; ++ unsigned long bfq_large_burst_thresh; ++ bool large_burst; ++ struct hlist_head burst_list; ++ ++ 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_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_in_large_burst, /* ++ * bfqq activated in a large burst, ++ * see comments to bfq_handle_burst. ++ */ ++ 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(sync); ++BFQ_BFQQ_FNS(budget_new); ++BFQ_BFQQ_FNS(IO_bound); ++BFQ_BFQQ_FNS(in_large_burst); ++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, ++ bool is_sync) ++{ ++ return bic->bfqq[is_sync]; ++} ++ ++static inline void bic_set_bfqq(struct bfq_io_cq *bic, ++ struct bfq_queue *bfqq, bool 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_check_ioprio_change(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.72.orig/block/bfq-ioc.c linux-3.14.72/block/bfq-ioc.c +--- linux-3.14.72.orig/block/bfq-ioc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/block/bfq-ioc.c 2016-06-19 22:11:55.065155743 +0200 +@@ -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.72.orig/block/bfq-iosched.c linux-3.14.72/block/bfq-iosched.c +--- linux-3.14.72.orig/block/bfq-iosched.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/block/bfq-iosched.c 2016-06-19 22:11:55.065155743 +0200 +@@ -0,0 +1,4218 @@ ++/* ++ * 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" ++ ++/* 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) ++ ++/* ++ * The following macro groups conditions that need to be evaluated when ++ * checking if existing queues and groups form a symmetric scenario ++ * and therefore idling can be reduced or disabled for some of the ++ * queues. See the comment to the function bfq_bfqq_must_not_expire() ++ * for further details. ++ */ ++#ifdef CONFIG_CGROUP_BFQIO ++#define symmetric_scenario (!bfqd->active_numerous_groups && \ ++ !bfq_differentiated_weights(bfqd)) ++#else ++#define symmetric_scenario (!bfq_differentiated_weights(bfqd)) ++#endif ++ ++/* ++ * 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) ++{ ++ /* ++ * 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 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 (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) ++{ ++ 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); ++ /* Assuming that the flag in_large_burst is already correctly set */ ++ if (bic->wr_time_left && bfqq->bfqd->low_latency && ++ !bfq_bfqq_in_large_burst(bfqq) && ++ 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; ++} ++ ++/* Empty burst list and add just bfqq (see comments to bfq_handle_burst) */ ++static inline void bfq_reset_burst_list(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq) ++{ ++ struct bfq_queue *item; ++ struct hlist_node *n; ++ ++ hlist_for_each_entry_safe(item, n, &bfqd->burst_list, burst_list_node) ++ hlist_del_init(&item->burst_list_node); ++ hlist_add_head(&bfqq->burst_list_node, &bfqd->burst_list); ++ bfqd->burst_size = 1; ++} ++ ++/* Add bfqq to the list of queues in current burst (see bfq_handle_burst) */ ++static void bfq_add_to_burst(struct bfq_data *bfqd, struct bfq_queue *bfqq) ++{ ++ /* Increment burst size to take into account also bfqq */ ++ bfqd->burst_size++; ++ ++ if (bfqd->burst_size == bfqd->bfq_large_burst_thresh) { ++ struct bfq_queue *pos, *bfqq_item; ++ struct hlist_node *n; ++ ++ /* ++ * Enough queues have been activated shortly after each ++ * other to consider this burst as large. ++ */ ++ bfqd->large_burst = true; ++ ++ /* ++ * We can now mark all queues in the burst list as ++ * belonging to a large burst. ++ */ ++ hlist_for_each_entry(bfqq_item, &bfqd->burst_list, ++ burst_list_node) ++ bfq_mark_bfqq_in_large_burst(bfqq_item); ++ bfq_mark_bfqq_in_large_burst(bfqq); ++ ++ /* ++ * From now on, and until the current burst finishes, any ++ * new queue being activated shortly after the last queue ++ * was inserted in the burst can be immediately marked as ++ * belonging to a large burst. So the burst list is not ++ * needed any more. Remove it. ++ */ ++ hlist_for_each_entry_safe(pos, n, &bfqd->burst_list, ++ burst_list_node) ++ hlist_del_init(&pos->burst_list_node); ++ } else /* burst not yet large: add bfqq to the burst list */ ++ hlist_add_head(&bfqq->burst_list_node, &bfqd->burst_list); ++} ++ ++/* ++ * If many queues happen to become active shortly after each other, then, ++ * to help the processes associated to these queues get their job done as ++ * soon as possible, it is usually better to not grant either weight-raising ++ * or device idling to these queues. In this comment we describe, firstly, ++ * the reasons why this fact holds, and, secondly, the next function, which ++ * implements the main steps needed to properly mark these queues so that ++ * they can then be treated in a different way. ++ * ++ * As for the terminology, we say that a queue becomes active, i.e., ++ * switches from idle to backlogged, either when it is created (as a ++ * consequence of the arrival of an I/O request), or, if already existing, ++ * when a new request for the queue arrives while the queue is idle. ++ * Bursts of activations, i.e., activations of different queues occurring ++ * shortly after each other, are typically caused by services or applications ++ * that spawn or reactivate many parallel threads/processes. Examples are ++ * systemd during boot or git grep. ++ * ++ * These services or applications benefit mostly from a high throughput: ++ * the quicker the requests of the activated queues are cumulatively served, ++ * the sooner the target job of these queues gets completed. As a consequence, ++ * weight-raising any of these queues, which also implies idling the device ++ * for it, is almost always counterproductive: in most cases it just lowers ++ * throughput. ++ * ++ * On the other hand, a burst of activations may be also caused by the start ++ * of an application that does not consist in a lot of parallel I/O-bound ++ * threads. In fact, with a complex application, the burst may be just a ++ * consequence of the fact that several processes need to be executed to ++ * start-up the application. To start an application as quickly as possible, ++ * the best thing to do is to privilege the I/O related to the application ++ * with respect to all other I/O. Therefore, the best strategy to start as ++ * quickly as possible an application that causes a burst of activations is ++ * to weight-raise all the queues activated during the burst. This is the ++ * exact opposite of the best strategy for the other type of bursts. ++ * ++ * In the end, to take the best action for each of the two cases, the two ++ * types of bursts need to be distinguished. Fortunately, this seems ++ * relatively easy to do, by looking at the sizes of the bursts. In ++ * particular, we found a threshold such that bursts with a larger size ++ * than that threshold are apparently caused only by services or commands ++ * such as systemd or git grep. For brevity, hereafter we call just 'large' ++ * these bursts. BFQ *does not* weight-raise queues whose activations occur ++ * in a large burst. In addition, for each of these queues BFQ performs or ++ * does not perform idling depending on which choice boosts the throughput ++ * most. The exact choice depends on the device and request pattern at ++ * hand. ++ * ++ * Turning back to the next function, it implements all the steps needed ++ * to detect the occurrence of a large burst and to properly mark all the ++ * queues belonging to it (so that they can then be treated in a different ++ * way). This goal is achieved by maintaining a special "burst list" that ++ * holds, temporarily, the queues that belong to the burst in progress. The ++ * list is then used to mark these queues as belonging to a large burst if ++ * the burst does become large. The main steps are the following. ++ * ++ * . when the very first queue is activated, the queue is inserted into the ++ * list (as it could be the first queue in a possible burst) ++ * ++ * . if the current burst has not yet become large, and a queue Q that does ++ * not yet belong to the burst is activated shortly after the last time ++ * at which a new queue entered the burst list, then the function appends ++ * Q to the burst list ++ * ++ * . if, as a consequence of the previous step, the burst size reaches ++ * the large-burst threshold, then ++ * ++ * . all the queues in the burst list are marked as belonging to a ++ * large burst ++ * ++ * . the burst list is deleted; in fact, the burst list already served ++ * its purpose (keeping temporarily track of the queues in a burst, ++ * so as to be able to mark them as belonging to a large burst in the ++ * previous sub-step), and now is not needed any more ++ * ++ * . the device enters a large-burst mode ++ * ++ * . if a queue Q that does not belong to the burst is activated while ++ * the device is in large-burst mode and shortly after the last time ++ * at which a queue either entered the burst list or was marked as ++ * belonging to the current large burst, then Q is immediately marked ++ * as belonging to a large burst. ++ * ++ * . if a queue Q that does not belong to the burst is activated a while ++ * later, i.e., not shortly after, than the last time at which a queue ++ * either entered the burst list or was marked as belonging to the ++ * current large burst, then the current burst is deemed as finished and: ++ * ++ * . the large-burst mode is reset if set ++ * ++ * . the burst list is emptied ++ * ++ * . Q is inserted in the burst list, as Q may be the first queue ++ * in a possible new burst (then the burst list contains just Q ++ * after this step). ++ */ ++static void bfq_handle_burst(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ bool idle_for_long_time) ++{ ++ /* ++ * If bfqq happened to be activated in a burst, but has been idle ++ * for at least as long as an interactive queue, then we assume ++ * that, in the overall I/O initiated in the burst, the I/O ++ * associated to bfqq is finished. So bfqq does not need to be ++ * treated as a queue belonging to a burst anymore. Accordingly, ++ * we reset bfqq's in_large_burst flag if set, and remove bfqq ++ * from the burst list if it's there. We do not decrement instead ++ * burst_size, because the fact that bfqq does not need to belong ++ * to the burst list any more does not invalidate the fact that ++ * bfqq may have been activated during the current burst. ++ */ ++ if (idle_for_long_time) { ++ hlist_del_init(&bfqq->burst_list_node); ++ bfq_clear_bfqq_in_large_burst(bfqq); ++ } ++ ++ /* ++ * If bfqq is already in the burst list or is part of a large ++ * burst, then there is nothing else to do. ++ */ ++ if (!hlist_unhashed(&bfqq->burst_list_node) || ++ bfq_bfqq_in_large_burst(bfqq)) ++ return; ++ ++ /* ++ * If bfqq's activation happens late enough, then the current ++ * burst is finished, and related data structures must be reset. ++ * ++ * In this respect, consider the special case where bfqq is the very ++ * first queue being activated. In this case, last_ins_in_burst is ++ * not yet significant when we get here. But it is easy to verify ++ * that, whether or not the following condition is true, bfqq will ++ * end up being inserted into the burst list. In particular the ++ * list will happen to contain only bfqq. And this is exactly what ++ * has to happen, as bfqq may be the first queue in a possible ++ * burst. ++ */ ++ if (time_is_before_jiffies(bfqd->last_ins_in_burst + ++ bfqd->bfq_burst_interval)) { ++ bfqd->large_burst = false; ++ bfq_reset_burst_list(bfqd, bfqq); ++ return; ++ } ++ ++ /* ++ * If we get here, then bfqq is being activated shortly after the ++ * last queue. So, if the current burst is also large, we can mark ++ * bfqq as belonging to this large burst immediately. ++ */ ++ if (bfqd->large_burst) { ++ bfq_mark_bfqq_in_large_burst(bfqq); ++ return; ++ } ++ ++ /* ++ * If we get here, then a large-burst state has not yet been ++ * reached, but bfqq is being activated shortly after the last ++ * queue. Then we add bfqq to the burst. ++ */ ++ bfq_add_to_burst(bfqd, bfqq); ++} ++ ++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; ++ bool interactive = false; ++ ++ 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)) { ++ bool soft_rt, coop_or_in_burst, ++ idle_for_long_time = time_is_before_jiffies( ++ bfqq->budget_timeout + ++ bfqd->bfq_wr_min_idle_time); ++ ++ if (bfq_bfqq_sync(bfqq)) { ++ bool already_in_burst = ++ !hlist_unhashed(&bfqq->burst_list_node) || ++ bfq_bfqq_in_large_burst(bfqq); ++ bfq_handle_burst(bfqd, bfqq, idle_for_long_time); ++ /* ++ * If bfqq was not already in the current burst, ++ * then, at this point, bfqq either has been ++ * added to the current burst or has caused the ++ * current burst to terminate. In particular, in ++ * the second case, bfqq has become the first ++ * queue in a possible new burst. ++ * In both cases last_ins_in_burst needs to be ++ * moved forward. ++ */ ++ if (!already_in_burst) ++ bfqd->last_ins_in_burst = jiffies; ++ } ++ ++ coop_or_in_burst = bfq_bfqq_in_large_burst(bfqq) || ++ bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh; ++ soft_rt = bfqd->bfq_wr_max_softrt_rate > 0 && ++ !coop_or_in_burst && ++ time_is_before_jiffies(bfqq->soft_rt_next_start); ++ interactive = !coop_or_in_burst && idle_for_long_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 && (interactive || soft_rt) && ++ (!bfq_bfqq_sync(bfqq) || bfqq->bic != NULL)) { ++ bfqq->wr_coeff = bfqd->bfq_wr_coeff; ++ if (interactive) ++ 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 (interactive) ++ bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); ++ else if (coop_or_in_burst || ++ (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 || interactive)) ++ 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); ++ } ++ ++ if (rq->queuelist.prev != &rq->queuelist) ++ 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), *next_bfqq = RQ_BFQQ(next); ++ ++ /* ++ * If next and rq belong to the same bfq_queue and next is older ++ * than rq, then reposition rq in the fifo (by substituting next ++ * with rq). Otherwise, if next and rq belong to different ++ * bfq_queues, never reposition rq: in fact, we would have to ++ * reposition it with respect to next's position in its own fifo, ++ * which would most certainly be too expensive with respect to ++ * the benefits. ++ */ ++ if (bfqq == next_bfqq && ++ !list_empty(&rq->queuelist) && !list_empty(&next->queuelist) && ++ time_before(rq_fifo_time(next), rq_fifo_time(rq))) { ++ list_del_init(&rq->queuelist); ++ list_replace_init(&next->queuelist, &rq->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. ++ * ++ * The OOM queue is not allowed to participate to cooperation: in fact, since ++ * the requests temporarily redirected to the OOM queue could be redirected ++ * again to dedicated queues at any time, the state needed to correctly ++ * handle merging with the OOM queue would be quite complex and expensive ++ * to maintain. Besides, in such a critical condition as an out of memory, ++ * the benefits of queue merging may be little relevant, or even negligible. ++ */ ++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 || unlikely(bfqq == &bfqd->oom_bfqq)) ++ return NULL; ++ ++ in_service_bfqq = bfqd->in_service_queue; ++ ++ if (in_service_bfqq == NULL || in_service_bfqq == bfqq || ++ !bfqd->in_service_bic || ++ unlikely(in_service_bfqq == &bfqd->oom_bfqq)) ++ 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 && likely(new_bfqq != &bfqd->oom_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->saved_in_large_burst = bfq_bfqq_in_large_burst(bfqq); ++ bfqq->bic->was_in_burst_list = !hlist_unhashed(&bfqq->burst_list_node); ++ 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 or the scenario is ++ * asymmetric, 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 && ++ symmetric_scenario) ++ 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 is false if bfqq is not sync, or if: bfqq happened ++ * to become active during a large burst of queue activations, and the ++ * pattern of requests bfqq contains boosts the throughput if bfqq is ++ * expired. In fact, queues that became active during a large burst benefit ++ * only from throughput, as discussed in the comments to bfq_handle_burst. ++ * In this respect, expiring bfqq certainly boosts the throughput on NCQ- ++ * capable flash-based devices, whereas, on rotational devices, it boosts ++ * the throughput only if bfqq contains random requests. ++ * ++ * On the opposite end, if (a) bfqq is sync, (b) the above burst-related ++ * condition does not hold, and (c) bfqq is being weight-raised, then the ++ * expression always evaluates to true, as device idling is instrumental ++ * for preserving low-latency guarantees (see [1]). If, instead, conditions ++ * (a) and (b) do hold, but (c) does not, then the expression evaluates to ++ * true only if: (1) bfqq is I/O-bound and has a non-null idle window, and ++ * (2) 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 is I/O-bound and 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; ++#define cond_for_seeky_on_ncq_hdd (bfq_bfqq_constantly_seeky(bfqq) && \ ++ bfqd->busy_in_flight_queues == \ ++ bfqd->const_seeky_busy_in_flight_queues) ++ ++#define cond_for_expiring_in_burst (bfq_bfqq_in_large_burst(bfqq) && \ ++ bfqd->hw_tag && \ ++ (blk_queue_nonrot(bfqd->queue) || \ ++ bfq_bfqq_constantly_seeky(bfqq))) ++ ++/* ++ * 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 || \ ++ (blk_queue_nonrot(bfqd->queue) || \ ++ cond_for_seeky_on_ncq_hdd))) ++ ++ return bfq_bfqq_sync(bfqq) && ++ !cond_for_expiring_in_burst && ++ (bfqq->wr_coeff > 1 || !symmetric_scenario || ++ (bfq_bfqq_IO_bound(bfqq) && 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. However, if the in-service queue is idling ++ * for a new request, or has requests waiting for a completion and ++ * may idle after their completion, then keep it anyway. ++ */ ++ 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 the queue was activated in a burst, or ++ * too much time has elapsed from the beginning ++ * of this weight-raising period, or the queue has ++ * exceeded the acceptable number of cooperations, ++ * then end weight raising. ++ */ ++ if (bfq_bfqq_in_large_burst(bfqq) || ++ 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; ++ ++ if (bfq_class_idle(bfqq)) ++ max_dispatch = 1; ++ ++ if (!bfq_bfqq_sync(bfqq)) ++ max_dispatch = bfqd->bfq_max_budget_async_rq; ++ ++ if (!bfq_bfqq_sync(bfqq) && 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 %s request", ++ bfq_bfqq_sync(bfqq) ? "sync" : "async"); ++ ++ 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); ++ ++ if (bfq_bfqq_sync(bfqq)) ++ /* ++ * The fact that this queue is being destroyed does not ++ * invalidate the fact that this queue may have been ++ * activated during the current burst. As a consequence, ++ * although the queue does not exist anymore, and hence ++ * needs to be removed from the burst list if there, ++ * the burst size has not to be decremented. ++ */ ++ hlist_del_init(&bfqq->burst_list_node); ++ ++ 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_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic) ++{ ++ struct task_struct *tsk = current; ++ int ioprio_class; ++ ++ ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio); ++ switch (ioprio_class) { ++ default: ++ dev_err(bfqq->bfqd->queue->backing_dev_info.dev, ++ "bfq: bad prio class %d\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; ++ } ++ ++ if (bfqq->entity.new_ioprio < 0 || ++ bfqq->entity.new_ioprio >= IOPRIO_BE_NR) { ++ printk(KERN_CRIT "bfq_set_next_ioprio_data: new_ioprio %d\n", ++ bfqq->entity.new_ioprio); ++ BUG(); ++ } ++ ++ bfqq->entity.new_weight = bfq_ioprio_to_weight(bfqq->entity.new_ioprio); ++ bfqq->entity.ioprio_changed = 1; ++} ++ ++static void bfq_check_ioprio_change(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; ++ ++ bic->ioprio = ioprio; ++ ++ 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, ++ "check_ioprio_change: bfqq %p %d", ++ bfqq, atomic_read(&bfqq->ref)); ++ bfq_put_queue(bfqq); ++ } ++ } ++ ++ bfqq = bic->bfqq[BLK_RW_SYNC]; ++ if (bfqq != NULL) ++ bfq_set_next_ioprio_data(bfqq, bic); ++ ++out: ++ bfq_put_bfqd_unlock(bfqd, &flags); ++} ++ ++static void bfq_init_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ struct bfq_io_cq *bic, pid_t pid, int is_sync) ++{ ++ RB_CLEAR_NODE(&bfqq->entity.rb_node); ++ INIT_LIST_HEAD(&bfqq->fifo); ++ INIT_HLIST_NODE(&bfqq->burst_list_node); ++ ++ atomic_set(&bfqq->ref, 0); ++ bfqq->bfqd = bfqd; ++ ++ if (bic) ++ bfq_set_next_ioprio_data(bfqq, bic); ++ ++ 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, bic, current->pid, ++ is_sync); ++ bfq_init_entity(&bfqq->entity, bfqg); ++ bfq_log_bfqq(bfqd, bfqq, "allocated"); ++ } else { ++ bfqq = &bfqd->oom_bfqq; ++ bfq_log_bfqq(bfqd, bfqq, "using oom bfqq"); ++ } ++ } ++ ++ 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_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) ++ 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_check_ioprio_change(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); ++ if (split && is_sync) { ++ if ((bic->was_in_burst_list && bfqd->large_burst) || ++ bic->saved_in_large_burst) ++ bfq_mark_bfqq_in_large_burst(bfqq); ++ else { ++ bfq_clear_bfqq_in_large_burst(bfqq); ++ if (bic->was_in_burst_list) ++ hlist_add_head(&bfqq->burst_list_node, ++ &bfqd->burst_list); ++ } ++ } ++ } 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 (likely(bfqq != &bfqd->oom_bfqq) && 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, NULL, 1, 0); ++ atomic_inc(&bfqd->oom_bfqq.ref); ++ bfqd->oom_bfqq.entity.new_ioprio = BFQ_DEFAULT_QUEUE_IOPRIO; ++ bfqd->oom_bfqq.entity.new_ioprio_class = IOPRIO_CLASS_BE; ++ bfqd->oom_bfqq.entity.new_weight = ++ bfq_ioprio_to_weight(bfqd->oom_bfqq.entity.new_ioprio); ++ /* ++ * Trigger weight initialization, according to ioprio, at the ++ * oom_bfqq's first activation. The oom_bfqq's ioprio and ioprio ++ * class won't be changed any more. ++ */ ++ bfqd->oom_bfqq.entity.ioprio_changed = 1; ++ ++ 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; ++ bfq_init_entity(&bfqd->oom_bfqq.entity, bfqd->root_group); ++#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); ++ INIT_HLIST_HEAD(&bfqd->burst_list); ++ ++ bfqd->hw_tag = -1; ++ ++ bfqd->bfq_max_budget = bfq_default_max_budget; ++ ++ 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->bfq_large_burst_thresh = 11; ++ bfqd->bfq_burst_interval = msecs_to_jiffies(500); ++ ++ 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_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_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(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: v7r8"); ++ ++ 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.72.orig/block/bfq-sched.c linux-3.14.72/block/bfq-sched.c +--- linux-3.14.72.orig/block/bfq-sched.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/block/bfq-sched.c 2016-06-19 22:11:55.065155743 +0200 +@@ -0,0 +1,1180 @@ ++/* ++ * 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) { ++ if (entity->new_weight < BFQ_MIN_WEIGHT || ++ entity->new_weight > BFQ_MAX_WEIGHT) { ++ printk(KERN_CRIT "update_weight_prio: " ++ "new_weight %d\n", ++ entity->new_weight); ++ BUG(); ++ } ++ entity->orig_weight = entity->new_weight; ++ entity->ioprio = ++ bfq_weight_to_ioprio(entity->orig_weight); ++ } ++ ++ 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.72.orig/block/Kconfig.iosched linux-3.14.72/block/Kconfig.iosched +--- linux-3.14.72.orig/block/Kconfig.iosched 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/block/Kconfig.iosched 2016-06-19 22:11:55.065155743 +0200 +@@ -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.72.orig/block/Makefile linux-3.14.72/block/Makefile +--- linux-3.14.72.orig/block/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/block/Makefile 2016-06-19 22:11:55.065155743 +0200 +@@ -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.72.orig/crypto/cryptodev/authenc.c linux-3.14.72/crypto/cryptodev/authenc.c +--- linux-3.14.72.orig/crypto/cryptodev/authenc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/authenc.c 2016-06-19 22:11:55.065155743 +0200 +@@ -0,0 +1,758 @@ ++/* ++ * Driver for /dev/crypto device (aka CryptoDev) ++ * ++ * Copyright (c) 2011, 2012 OpenSSL Software Foundation, Inc. ++ * ++ * Author: Nikos Mavrogiannopoulos ++ * ++ * This file is part of linux cryptodev. ++ * ++ * 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. ++ */ ++ ++/* ++ * This file handles the AEAD part of /dev/crypto. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "cryptodev_int.h" ++#include "zc.h" ++#include "util.h" ++#include "cryptlib.h" ++#include "version.h" ++ ++ ++/* make caop->dst available in scatterlist. ++ * (caop->src is assumed to be equal to caop->dst) ++ */ ++static int get_userbuf_tls(struct csession *ses, struct kernel_crypt_auth_op *kcaop, ++ struct scatterlist **dst_sg) ++{ ++ int pagecount = 0; ++ struct crypt_auth_op *caop = &kcaop->caop; ++ int rc; ++ ++ if (caop->dst == NULL) ++ return -EINVAL; ++ ++ if (ses->alignmask) { ++ if (!IS_ALIGNED((unsigned long)caop->dst, ses->alignmask)) ++ dwarning(2, "careful - source address %p is not %d byte aligned", ++ caop->dst, ses->alignmask + 1); ++ } ++ ++ if (kcaop->dst_len == 0) { ++ dwarning(1, "Destination length cannot be zero"); ++ return -EINVAL; ++ } ++ ++ pagecount = PAGECOUNT(caop->dst, kcaop->dst_len); ++ ++ ses->used_pages = pagecount; ++ ses->readonly_pages = 0; ++ ++ rc = adjust_sg_array(ses, pagecount); ++ if (rc) ++ return rc; ++ ++ rc = __get_userbuf(caop->dst, kcaop->dst_len, 1, pagecount, ++ ses->pages, ses->sg, kcaop->task, kcaop->mm); ++ if (unlikely(rc)) { ++ derr(1, "failed to get user pages for data input"); ++ return -EINVAL; ++ } ++ ++ (*dst_sg) = ses->sg; ++ ++ return 0; ++} ++ ++ ++#define MAX_SRTP_AUTH_DATA_DIFF 256 ++ ++/* Makes caop->auth_src available as scatterlist. ++ * It also provides a pointer to caop->dst, which however, ++ * is assumed to be within the caop->auth_src buffer. If not ++ * (if their difference exceeds MAX_SRTP_AUTH_DATA_DIFF) it ++ * returns error. ++ */ ++static int get_userbuf_srtp(struct csession *ses, struct kernel_crypt_auth_op *kcaop, ++ struct scatterlist **auth_sg, struct scatterlist **dst_sg) ++{ ++ int pagecount, diff; ++ int auth_pagecount = 0; ++ struct crypt_auth_op *caop = &kcaop->caop; ++ int rc; ++ ++ if (caop->dst == NULL && caop->auth_src == NULL) { ++ derr(1, "dst and auth_src cannot be both null"); ++ return -EINVAL; ++ } ++ ++ if (ses->alignmask) { ++ if (!IS_ALIGNED((unsigned long)caop->dst, ses->alignmask)) ++ dwarning(2, "careful - source address %p is not %d byte aligned", ++ caop->dst, ses->alignmask + 1); ++ if (!IS_ALIGNED((unsigned long)caop->auth_src, ses->alignmask)) ++ dwarning(2, "careful - source address %p is not %d byte aligned", ++ caop->auth_src, ses->alignmask + 1); ++ } ++ ++ if (unlikely(kcaop->dst_len == 0 || caop->auth_len == 0)) { ++ dwarning(1, "Destination length cannot be zero"); ++ return -EINVAL; ++ } ++ ++ /* Note that in SRTP auth data overlap with data to be encrypted (dst) ++ */ ++ ++ auth_pagecount = PAGECOUNT(caop->auth_src, caop->auth_len); ++ diff = (int)(caop->src - caop->auth_src); ++ if (diff > MAX_SRTP_AUTH_DATA_DIFF || diff < 0) { ++ dwarning(1, "auth_src must overlap with src (diff: %d).", diff); ++ return -EINVAL; ++ } ++ ++ pagecount = auth_pagecount; ++ ++ rc = adjust_sg_array(ses, pagecount*2); /* double pages to have pages for dst(=auth_src) */ ++ if (rc) { ++ derr(1, "cannot adjust sg array"); ++ return rc; ++ } ++ ++ rc = __get_userbuf(caop->auth_src, caop->auth_len, 1, auth_pagecount, ++ ses->pages, ses->sg, kcaop->task, kcaop->mm); ++ if (unlikely(rc)) { ++ derr(1, "failed to get user pages for data input"); ++ return -EINVAL; ++ } ++ ++ ses->used_pages = pagecount; ++ ses->readonly_pages = 0; ++ ++ (*auth_sg) = ses->sg; ++ ++ (*dst_sg) = ses->sg + auth_pagecount; ++ sg_init_table(*dst_sg, auth_pagecount); ++ sg_copy(ses->sg, (*dst_sg), caop->auth_len); ++ (*dst_sg) = sg_advance(*dst_sg, diff); ++ if (*dst_sg == NULL) { ++ release_user_pages(ses); ++ derr(1, "failed to get enough pages for auth data"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Return tag (digest) length for authenticated encryption ++ * If the cipher and digest are separate, hdata.init is set - just return ++ * digest length. Otherwise return digest length for aead ciphers ++ */ ++static int cryptodev_get_tag_len(struct csession *ses_ptr) ++{ ++ if (ses_ptr->hdata.init) ++ return ses_ptr->hdata.digestsize; ++ else ++ return cryptodev_cipher_get_tag_size(&ses_ptr->cdata); ++} ++ ++/* ++ * Calculate destination buffer length for authenticated encryption. The ++ * expectation is that user-space code allocates exactly the same space for ++ * destination buffer before calling cryptodev. The result is cipher-dependent. ++ */ ++static int cryptodev_get_dst_len(struct crypt_auth_op *caop, struct csession *ses_ptr) ++{ ++ int dst_len = caop->len; ++ if (caop->op == COP_DECRYPT) ++ return dst_len; ++ ++ dst_len += caop->tag_len; ++ ++ /* for TLS always add some padding so the total length is rounded to ++ * cipher block size */ ++ if (caop->flags & COP_FLAG_AEAD_TLS_TYPE) { ++ int bs = ses_ptr->cdata.blocksize; ++ dst_len += bs - (dst_len % bs); ++ } ++ ++ return dst_len; ++} ++ ++static int fill_kcaop_from_caop(struct kernel_crypt_auth_op *kcaop, struct fcrypt *fcr) ++{ ++ struct crypt_auth_op *caop = &kcaop->caop; ++ struct csession *ses_ptr; ++ int ret; ++ ++ /* this also enters ses_ptr->sem */ ++ ses_ptr = crypto_get_session_by_sid(fcr, caop->ses); ++ if (unlikely(!ses_ptr)) { ++ derr(1, "invalid session ID=0x%08X", caop->ses); ++ return -EINVAL; ++ } ++ ++ if (caop->flags & COP_FLAG_AEAD_TLS_TYPE || caop->flags & COP_FLAG_AEAD_SRTP_TYPE) { ++ if (caop->src != caop->dst) { ++ derr(1, "Non-inplace encryption and decryption is not efficient and not implemented"); ++ ret = -EINVAL; ++ goto out_unlock; ++ } ++ } ++ ++ if (caop->tag_len == 0) ++ caop->tag_len = cryptodev_get_tag_len(ses_ptr); ++ ++ kcaop->ivlen = caop->iv ? ses_ptr->cdata.ivsize : 0; ++ kcaop->dst_len = cryptodev_get_dst_len(caop, ses_ptr); ++ kcaop->task = current; ++ kcaop->mm = current->mm; ++ ++ if (caop->iv) { ++ ret = copy_from_user(kcaop->iv, caop->iv, kcaop->ivlen); ++ if (unlikely(ret)) { ++ derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p", ++ kcaop->ivlen, ret, caop->iv); ++ ret = -EFAULT; ++ goto out_unlock; ++ } ++ } ++ ++ ret = 0; ++ ++out_unlock: ++ crypto_put_session(ses_ptr); ++ return ret; ++ ++} ++ ++static int fill_caop_from_kcaop(struct kernel_crypt_auth_op *kcaop, struct fcrypt *fcr) ++{ ++ int ret; ++ ++ kcaop->caop.len = kcaop->dst_len; ++ ++ if (kcaop->ivlen && kcaop->caop.flags & COP_FLAG_WRITE_IV) { ++ ret = copy_to_user(kcaop->caop.iv, ++ kcaop->iv, kcaop->ivlen); ++ if (unlikely(ret)) { ++ derr(1, "Error in copying to userspace"); ++ return -EFAULT; ++ } ++ } ++ return 0; ++} ++ ++ ++int kcaop_from_user(struct kernel_crypt_auth_op *kcaop, ++ struct fcrypt *fcr, void __user *arg) ++{ ++ if (unlikely(copy_from_user(&kcaop->caop, arg, sizeof(kcaop->caop)))) { ++ derr(1, "Error in copying from userspace"); ++ return -EFAULT; ++ } ++ ++ return fill_kcaop_from_caop(kcaop, fcr); ++} ++ ++int kcaop_to_user(struct kernel_crypt_auth_op *kcaop, ++ struct fcrypt *fcr, void __user *arg) ++{ ++ int ret; ++ ++ ret = fill_caop_from_kcaop(kcaop, fcr); ++ if (unlikely(ret)) { ++ derr(1, "fill_caop_from_kcaop"); ++ return ret; ++ } ++ ++ if (unlikely(copy_to_user(arg, &kcaop->caop, sizeof(kcaop->caop)))) { ++ derr(1, "Error in copying to userspace"); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static void copy_tls_hash(struct scatterlist *dst_sg, int len, void *hash, int hash_len) ++{ ++ scatterwalk_map_and_copy(hash, dst_sg, len, hash_len, 1); ++} ++ ++static void read_tls_hash(struct scatterlist *dst_sg, int len, void *hash, int hash_len) ++{ ++ scatterwalk_map_and_copy(hash, dst_sg, len - hash_len, hash_len, 0); ++} ++ ++static int pad_record(struct scatterlist *dst_sg, int len, int block_size) ++{ ++ uint8_t pad[block_size]; ++ int pad_size = block_size - (len % block_size); ++ ++ memset(pad, pad_size - 1, pad_size); ++ ++ scatterwalk_map_and_copy(pad, dst_sg, len, pad_size, 1); ++ ++ return pad_size; ++} ++ ++static int verify_tls_record_pad(struct scatterlist *dst_sg, int len, int block_size) ++{ ++ uint8_t pad[256]; /* the maximum allowed */ ++ uint8_t pad_size; ++ int i; ++ ++ scatterwalk_map_and_copy(&pad_size, dst_sg, len - 1, 1, 0); ++ ++ if (pad_size + 1 > len) { ++ derr(1, "Pad size: %d", pad_size); ++ return -EBADMSG; ++ } ++ ++ scatterwalk_map_and_copy(pad, dst_sg, len - pad_size - 1, pad_size + 1, 0); ++ ++ for (i = 0; i < pad_size; i++) ++ if (pad[i] != pad_size) { ++ derr(1, "Pad size: %u, pad: %d", pad_size, pad[i]); ++ return -EBADMSG; ++ } ++ ++ return pad_size + 1; ++} ++ ++/* Authenticate and encrypt the TLS way (also perform padding). ++ * During decryption it verifies the pad and tag and returns -EBADMSG on error. ++ */ ++static int ++tls_auth_n_crypt(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop, ++ struct scatterlist *auth_sg, uint32_t auth_len, ++ struct scatterlist *dst_sg, uint32_t len) ++{ ++ int ret, fail = 0; ++ struct crypt_auth_op *caop = &kcaop->caop; ++ uint8_t vhash[AALG_MAX_RESULT_LEN]; ++ uint8_t hash_output[AALG_MAX_RESULT_LEN]; ++ ++ /* TLS authenticates the plaintext except for the padding. ++ */ ++ if (caop->op == COP_ENCRYPT) { ++ if (ses_ptr->hdata.init != 0) { ++ if (auth_len > 0) { ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ auth_sg, auth_len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_update: %d", ret); ++ return ret; ++ } ++ } ++ ++ if (len > 0) { ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ dst_sg, len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_update: %d", ret); ++ return ret; ++ } ++ } ++ ++ ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_final: %d", ret); ++ return ret; ++ } ++ ++ copy_tls_hash(dst_sg, len, hash_output, caop->tag_len); ++ len += caop->tag_len; ++ } ++ ++ if (ses_ptr->cdata.init != 0) { ++ if (ses_ptr->cdata.blocksize > 1) { ++ ret = pad_record(dst_sg, len, ses_ptr->cdata.blocksize); ++ len += ret; ++ } ++ ++ ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, ++ dst_sg, dst_sg, len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_cipher_encrypt: %d", ret); ++ return ret; ++ } ++ } ++ } else { ++ if (ses_ptr->cdata.init != 0) { ++ ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, ++ dst_sg, dst_sg, len); ++ ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_cipher_decrypt: %d", ret); ++ return ret; ++ } ++ ++ if (ses_ptr->cdata.blocksize > 1) { ++ ret = verify_tls_record_pad(dst_sg, len, ses_ptr->cdata.blocksize); ++ if (unlikely(ret < 0)) { ++ derr(2, "verify_record_pad: %d", ret); ++ fail = 1; ++ } else { ++ len -= ret; ++ } ++ } ++ } ++ ++ if (ses_ptr->hdata.init != 0) { ++ if (unlikely(caop->tag_len > sizeof(vhash) || caop->tag_len > len)) { ++ derr(1, "Illegal tag len size"); ++ return -EINVAL; ++ } ++ ++ read_tls_hash(dst_sg, len, vhash, caop->tag_len); ++ len -= caop->tag_len; ++ ++ if (auth_len > 0) { ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ auth_sg, auth_len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_update: %d", ret); ++ return ret; ++ } ++ } ++ ++ if (len > 0) { ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ dst_sg, len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_update: %d", ret); ++ return ret; ++ } ++ } ++ ++ ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_final: %d", ret); ++ return ret; ++ } ++ ++ if (memcmp(vhash, hash_output, caop->tag_len) != 0 || fail != 0) { ++ derr(2, "MAC verification failed (tag_len: %d)", caop->tag_len); ++ return -EBADMSG; ++ } ++ } ++ } ++ kcaop->dst_len = len; ++ return 0; ++} ++ ++/* Authenticate and encrypt the SRTP way. During decryption ++ * it verifies the tag and returns -EBADMSG on error. ++ */ ++static int ++srtp_auth_n_crypt(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop, ++ struct scatterlist *auth_sg, uint32_t auth_len, ++ struct scatterlist *dst_sg, uint32_t len) ++{ ++ int ret, fail = 0; ++ struct crypt_auth_op *caop = &kcaop->caop; ++ uint8_t vhash[AALG_MAX_RESULT_LEN]; ++ uint8_t hash_output[AALG_MAX_RESULT_LEN]; ++ ++ /* SRTP authenticates the encrypted data. ++ */ ++ if (caop->op == COP_ENCRYPT) { ++ if (ses_ptr->cdata.init != 0) { ++ ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, ++ dst_sg, dst_sg, len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_cipher_encrypt: %d", ret); ++ return ret; ++ } ++ } ++ ++ if (ses_ptr->hdata.init != 0) { ++ if (auth_len > 0) { ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ auth_sg, auth_len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_update: %d", ret); ++ return ret; ++ } ++ } ++ ++ ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_final: %d", ret); ++ return ret; ++ } ++ ++ if (unlikely(copy_to_user(caop->tag, hash_output, caop->tag_len))) ++ return -EFAULT; ++ } ++ ++ } else { ++ if (ses_ptr->hdata.init != 0) { ++ if (unlikely(caop->tag_len > sizeof(vhash) || caop->tag_len > len)) { ++ derr(1, "Illegal tag len size"); ++ return -EINVAL; ++ } ++ ++ if (unlikely(copy_from_user(vhash, caop->tag, caop->tag_len))) ++ return -EFAULT; ++ ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ auth_sg, auth_len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_update: %d", ret); ++ return ret; ++ } ++ ++ ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_hash_final: %d", ret); ++ return ret; ++ } ++ ++ if (memcmp(vhash, hash_output, caop->tag_len) != 0 || fail != 0) { ++ derr(2, "MAC verification failed"); ++ return -EBADMSG; ++ } ++ } ++ ++ if (ses_ptr->cdata.init != 0) { ++ ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, ++ dst_sg, dst_sg, len); ++ ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_cipher_decrypt: %d", ret); ++ return ret; ++ } ++ } ++ ++ } ++ kcaop->dst_len = len; ++ return 0; ++} ++ ++/* Typical AEAD (i.e. GCM) encryption/decryption. ++ * During decryption the tag is verified. ++ */ ++static int ++auth_n_crypt(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop, ++ struct scatterlist *auth_sg, uint32_t auth_len, ++ struct scatterlist *src_sg, ++ struct scatterlist *dst_sg, uint32_t len) ++{ ++ int ret; ++ struct crypt_auth_op *caop = &kcaop->caop; ++ int max_tag_len; ++ ++ max_tag_len = cryptodev_cipher_get_tag_size(&ses_ptr->cdata); ++ if (unlikely(caop->tag_len > max_tag_len)) { ++ derr(0, "Illegal tag length: %d", caop->tag_len); ++ return -EINVAL; ++ } ++ ++ if (caop->tag_len) ++ cryptodev_cipher_set_tag_size(&ses_ptr->cdata, caop->tag_len); ++ else ++ caop->tag_len = max_tag_len; ++ ++ cryptodev_cipher_auth(&ses_ptr->cdata, auth_sg, auth_len); ++ ++ if (caop->op == COP_ENCRYPT) { ++ ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, ++ src_sg, dst_sg, len); ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_cipher_encrypt: %d", ret); ++ return ret; ++ } ++ kcaop->dst_len = len + caop->tag_len; ++ caop->tag = caop->dst + len; ++ } else { ++ ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, ++ src_sg, dst_sg, len); ++ ++ if (unlikely(ret)) { ++ derr(0, "cryptodev_cipher_decrypt: %d", ret); ++ return ret; ++ } ++ kcaop->dst_len = len - caop->tag_len; ++ caop->tag = caop->dst + len - caop->tag_len; ++ } ++ ++ return 0; ++} ++ ++/* This is the main crypto function - zero-copy edition */ ++static int ++__crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop) ++{ ++ struct scatterlist *dst_sg, *auth_sg, *src_sg; ++ struct crypt_auth_op *caop = &kcaop->caop; ++ int ret = 0; ++ ++ if (caop->flags & COP_FLAG_AEAD_SRTP_TYPE) { ++ if (unlikely(ses_ptr->cdata.init != 0 && ++ (ses_ptr->cdata.stream == 0 || ++ ses_ptr->cdata.aead != 0))) { ++ derr(0, "Only stream modes are allowed in SRTP mode (but not AEAD)"); ++ return -EINVAL; ++ } ++ ++ ret = get_userbuf_srtp(ses_ptr, kcaop, &auth_sg, &dst_sg); ++ if (unlikely(ret)) { ++ derr(1, "get_userbuf_srtp(): Error getting user pages."); ++ return ret; ++ } ++ ++ ret = srtp_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, ++ dst_sg, caop->len); ++ ++ release_user_pages(ses_ptr); ++ } else { /* TLS and normal cases. Here auth data are usually small ++ * so we just copy them to a free page, instead of trying ++ * to map them. ++ */ ++ unsigned char *auth_buf = NULL; ++ struct scatterlist tmp; ++ ++ if (unlikely(caop->auth_len > PAGE_SIZE)) { ++ derr(1, "auth data len is excessive."); ++ return -EINVAL; ++ } ++ ++ auth_buf = (char *)__get_free_page(GFP_KERNEL); ++ if (unlikely(!auth_buf)) { ++ derr(1, "unable to get a free page."); ++ return -ENOMEM; ++ } ++ ++ if (caop->auth_src && caop->auth_len > 0) { ++ if (unlikely(copy_from_user(auth_buf, caop->auth_src, caop->auth_len))) { ++ derr(1, "unable to copy auth data from userspace."); ++ ret = -EFAULT; ++ goto free_auth_buf; ++ } ++ ++ sg_init_one(&tmp, auth_buf, caop->auth_len); ++ auth_sg = &tmp; ++ } else { ++ auth_sg = NULL; ++ } ++ ++ if (caop->flags & COP_FLAG_AEAD_TLS_TYPE && ses_ptr->cdata.aead == 0) { ++ ret = get_userbuf_tls(ses_ptr, kcaop, &dst_sg); ++ if (unlikely(ret)) { ++ derr(1, "get_userbuf_tls(): Error getting user pages."); ++ goto free_auth_buf; ++ } ++ ++ ret = tls_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, ++ dst_sg, caop->len); ++ } else { ++ if (unlikely(ses_ptr->cdata.init == 0 || ++ (ses_ptr->cdata.stream == 0 && ++ ses_ptr->cdata.aead == 0))) { ++ derr(0, "Only stream and AEAD ciphers are allowed for authenc"); ++ ret = -EINVAL; ++ goto free_auth_buf; ++ } ++ ++ ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst, kcaop->dst_len, ++ kcaop->task, kcaop->mm, &src_sg, &dst_sg); ++ if (unlikely(ret)) { ++ derr(1, "get_userbuf(): Error getting user pages."); ++ goto free_auth_buf; ++ } ++ ++ ret = auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, ++ src_sg, dst_sg, caop->len); ++ } ++ ++ release_user_pages(ses_ptr); ++ ++free_auth_buf: ++ free_page((unsigned long)auth_buf); ++ } ++ ++ return ret; ++} ++ ++ ++int crypto_auth_run(struct fcrypt *fcr, struct kernel_crypt_auth_op *kcaop) ++{ ++ struct csession *ses_ptr; ++ struct crypt_auth_op *caop = &kcaop->caop; ++ int ret; ++ ++ if (unlikely(caop->op != COP_ENCRYPT && caop->op != COP_DECRYPT)) { ++ ddebug(1, "invalid operation op=%u", caop->op); ++ return -EINVAL; ++ } ++ ++ /* this also enters ses_ptr->sem */ ++ ses_ptr = crypto_get_session_by_sid(fcr, caop->ses); ++ if (unlikely(!ses_ptr)) { ++ derr(1, "invalid session ID=0x%08X", caop->ses); ++ return -EINVAL; ++ } ++ ++ if (unlikely(ses_ptr->cdata.init == 0)) { ++ derr(1, "cipher context not initialized"); ++ ret = -EINVAL; ++ goto out_unlock; ++ } ++ ++ /* If we have a hash/mac handle reset its state */ ++ if (ses_ptr->hdata.init != 0) { ++ ret = cryptodev_hash_reset(&ses_ptr->hdata); ++ if (unlikely(ret)) { ++ derr(1, "error in cryptodev_hash_reset()"); ++ goto out_unlock; ++ } ++ } ++ ++ cryptodev_cipher_set_iv(&ses_ptr->cdata, kcaop->iv, ++ min(ses_ptr->cdata.ivsize, kcaop->ivlen)); ++ ++ ret = __crypto_auth_run_zc(ses_ptr, kcaop); ++ if (unlikely(ret)) { ++ derr(1, "error in __crypto_auth_run_zc()"); ++ goto out_unlock; ++ } ++ ++ ret = 0; ++ ++ cryptodev_cipher_get_iv(&ses_ptr->cdata, kcaop->iv, ++ min(ses_ptr->cdata.ivsize, kcaop->ivlen)); ++ ++out_unlock: ++ crypto_put_session(ses_ptr); ++ return ret; ++} +diff -Nur linux-3.14.72.orig/crypto/cryptodev/cryptlib.c linux-3.14.72/crypto/cryptodev/cryptlib.c +--- linux-3.14.72.orig/crypto/cryptodev/cryptlib.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/cryptlib.c 2016-06-19 22:11:55.065155743 +0200 +@@ -0,0 +1,441 @@ ++/* ++ * Driver for /dev/crypto device (aka CryptoDev) ++ * ++ * Copyright (c) 2010,2011 Nikos Mavrogiannopoulos ++ * Portions Copyright (c) 2010 Michael Weiser ++ * Portions Copyright (c) 2010 Phil Sutter ++ * ++ * This file is part of linux cryptodev. ++ * ++ * 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 "cryptodev_int.h" ++ ++ ++struct cryptodev_result { ++ struct completion completion; ++ int err; ++}; ++ ++static void cryptodev_complete(struct crypto_async_request *req, int err) ++{ ++ struct cryptodev_result *res = req->data; ++ ++ if (err == -EINPROGRESS) ++ return; ++ ++ res->err = err; ++ complete(&res->completion); ++} ++ ++int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop, ++ int aead) ++{ ++ /* ++ * For blockciphers (AES-CBC) or non-composite aead ciphers (like AES-GCM), ++ * the key length is simply the cipher keylen obtained from userspace. If ++ * the cipher is composite aead, the keylen is the sum of cipher keylen, ++ * hmac keylen and a key header length. This key format is the one used in ++ * Linux kernel for composite aead ciphers (crypto/authenc.c) ++ */ ++ unsigned int klen = sop->keylen; ++ ++ if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) ++ return -EINVAL; ++ ++ if (aead && sop->mackeylen) { ++ if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) ++ return -EINVAL; ++ klen += sop->mackeylen; ++ klen += RTA_SPACE(sizeof(struct crypto_authenc_key_param)); ++ } ++ ++ *keylen = klen; ++ return 0; ++} ++ ++int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead) ++{ ++ /* ++ * Get cipher key from user-space. For blockciphers just copy it from ++ * user-space. For composite aead ciphers combine it with the hmac key in ++ * the format used by Linux kernel in crypto/authenc.c: ++ * ++ * [[AUTHENC_KEY_HEADER + CIPHER_KEYLEN] [AUTHENTICATION KEY] [CIPHER KEY]] ++ */ ++ struct crypto_authenc_key_param *param; ++ struct rtattr *rta; ++ int ret = 0; ++ ++ if (aead && sop->mackeylen) { ++ /* ++ * Composite aead ciphers. The first four bytes are the header type and ++ * header length for aead keys ++ */ ++ rta = (void *)key; ++ rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; ++ rta->rta_len = RTA_LENGTH(sizeof(*param)); ++ ++ /* ++ * The next four bytes hold the length of the encryption key ++ */ ++ param = RTA_DATA(rta); ++ param->enckeylen = cpu_to_be32(sop->keylen); ++ ++ /* Advance key pointer eight bytes and copy the hmac key */ ++ key += RTA_SPACE(sizeof(*param)); ++ if (unlikely(copy_from_user(key, sop->mackey, sop->mackeylen))) { ++ ret = -EFAULT; ++ goto error; ++ } ++ /* Advance key pointer past the hmac key */ ++ key += sop->mackeylen; ++ } ++ /* now copy the blockcipher key */ ++ if (unlikely(copy_from_user(key, sop->key, sop->keylen))) ++ ret = -EFAULT; ++ ++error: ++ return ret; ++} ++ ++ ++int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, ++ uint8_t *keyp, size_t keylen, int stream, int aead) ++{ ++ int ret; ++ ++ if (aead == 0) { ++ struct ablkcipher_alg *alg; ++ ++ out->async.s = crypto_alloc_ablkcipher(alg_name, 0, 0); ++ if (unlikely(IS_ERR(out->async.s))) { ++ ddebug(1, "Failed to load cipher %s", alg_name); ++ return -EINVAL; ++ } ++ ++ alg = crypto_ablkcipher_alg(out->async.s); ++ if (alg != NULL) { ++ /* Was correct key length supplied? */ ++ if (alg->max_keysize > 0 && ++ unlikely((keylen < alg->min_keysize) || ++ (keylen > alg->max_keysize))) { ++ ddebug(1, "Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.", ++ keylen, alg_name, alg->min_keysize, alg->max_keysize); ++ ret = -EINVAL; ++ goto error; ++ } ++ } ++ ++ out->blocksize = crypto_ablkcipher_blocksize(out->async.s); ++ out->ivsize = crypto_ablkcipher_ivsize(out->async.s); ++ out->alignmask = crypto_ablkcipher_alignmask(out->async.s); ++ ++ ret = crypto_ablkcipher_setkey(out->async.s, keyp, keylen); ++ } else { ++ out->async.as = crypto_alloc_aead(alg_name, 0, 0); ++ if (unlikely(IS_ERR(out->async.as))) { ++ ddebug(1, "Failed to load cipher %s", alg_name); ++ return -EINVAL; ++ } ++ ++ out->blocksize = crypto_aead_blocksize(out->async.as); ++ out->ivsize = crypto_aead_ivsize(out->async.as); ++ out->alignmask = crypto_aead_alignmask(out->async.as); ++ ++ ret = crypto_aead_setkey(out->async.as, keyp, keylen); ++ } ++ ++ if (unlikely(ret)) { ++ ddebug(1, "Setting key failed for %s-%zu.", alg_name, keylen*8); ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ out->stream = stream; ++ out->aead = aead; ++ ++ out->async.result = kzalloc(sizeof(*out->async.result), GFP_KERNEL); ++ if (unlikely(!out->async.result)) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ init_completion(&out->async.result->completion); ++ ++ if (aead == 0) { ++ out->async.request = ablkcipher_request_alloc(out->async.s, GFP_KERNEL); ++ if (unlikely(!out->async.request)) { ++ derr(1, "error allocating async crypto request"); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ ablkcipher_request_set_callback(out->async.request, ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ cryptodev_complete, out->async.result); ++ } else { ++ out->async.arequest = aead_request_alloc(out->async.as, GFP_KERNEL); ++ if (unlikely(!out->async.arequest)) { ++ derr(1, "error allocating async crypto request"); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ aead_request_set_callback(out->async.arequest, ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ cryptodev_complete, out->async.result); ++ } ++ ++ out->init = 1; ++ return 0; ++error: ++ if (aead == 0) { ++ if (out->async.request) ++ ablkcipher_request_free(out->async.request); ++ if (out->async.s) ++ crypto_free_ablkcipher(out->async.s); ++ } else { ++ if (out->async.arequest) ++ aead_request_free(out->async.arequest); ++ if (out->async.as) ++ crypto_free_aead(out->async.as); ++ } ++ kfree(out->async.result); ++ ++ return ret; ++} ++ ++void cryptodev_cipher_deinit(struct cipher_data *cdata) ++{ ++ if (cdata->init) { ++ if (cdata->aead == 0) { ++ if (cdata->async.request) ++ ablkcipher_request_free(cdata->async.request); ++ if (cdata->async.s) ++ crypto_free_ablkcipher(cdata->async.s); ++ } else { ++ if (cdata->async.arequest) ++ aead_request_free(cdata->async.arequest); ++ if (cdata->async.as) ++ crypto_free_aead(cdata->async.as); ++ } ++ ++ kfree(cdata->async.result); ++ cdata->init = 0; ++ } ++} ++ ++static inline int waitfor(struct cryptodev_result *cr, ssize_t ret) ++{ ++ switch (ret) { ++ case 0: ++ break; ++ case -EINPROGRESS: ++ case -EBUSY: ++ wait_for_completion(&cr->completion); ++ /* At this point we known for sure the request has finished, ++ * because wait_for_completion above was not interruptible. ++ * This is important because otherwise hardware or driver ++ * might try to access memory which will be freed or reused for ++ * another request. */ ++ ++ if (unlikely(cr->err)) { ++ derr(0, "error from async request: %d", cr->err); ++ return cr->err; ++ } ++ ++ break; ++ default: ++ return ret; ++ } ++ ++ return 0; ++} ++ ++ssize_t cryptodev_cipher_encrypt(struct cipher_data *cdata, ++ const struct scatterlist *src, struct scatterlist *dst, ++ size_t len) ++{ ++ int ret; ++ ++ reinit_completion(&cdata->async.result->completion); ++ ++ if (cdata->aead == 0) { ++ ablkcipher_request_set_crypt(cdata->async.request, ++ (struct scatterlist *)src, dst, ++ len, cdata->async.iv); ++ ret = crypto_ablkcipher_encrypt(cdata->async.request); ++ } else { ++ aead_request_set_crypt(cdata->async.arequest, ++ (struct scatterlist *)src, dst, ++ len, cdata->async.iv); ++ ret = crypto_aead_encrypt(cdata->async.arequest); ++ } ++ ++ return waitfor(cdata->async.result, ret); ++} ++ ++ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata, ++ const struct scatterlist *src, struct scatterlist *dst, ++ size_t len) ++{ ++ int ret; ++ ++ reinit_completion(&cdata->async.result->completion); ++ if (cdata->aead == 0) { ++ ablkcipher_request_set_crypt(cdata->async.request, ++ (struct scatterlist *)src, dst, ++ len, cdata->async.iv); ++ ret = crypto_ablkcipher_decrypt(cdata->async.request); ++ } else { ++ aead_request_set_crypt(cdata->async.arequest, ++ (struct scatterlist *)src, dst, ++ len, cdata->async.iv); ++ ret = crypto_aead_decrypt(cdata->async.arequest); ++ } ++ ++ return waitfor(cdata->async.result, ret); ++} ++ ++/* Hash functions */ ++ ++int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, ++ int hmac_mode, void *mackey, size_t mackeylen) ++{ ++ int ret; ++ ++ hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0); ++ if (unlikely(IS_ERR(hdata->async.s))) { ++ ddebug(1, "Failed to load transform for %s", alg_name); ++ return -EINVAL; ++ } ++ ++ /* Copy the key from user and set to TFM. */ ++ if (hmac_mode != 0) { ++ ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen); ++ if (unlikely(ret)) { ++ ddebug(1, "Setting hmac key failed for %s-%zu.", ++ alg_name, mackeylen*8); ++ ret = -EINVAL; ++ goto error; ++ } ++ } ++ ++ hdata->digestsize = crypto_ahash_digestsize(hdata->async.s); ++ hdata->alignmask = crypto_ahash_alignmask(hdata->async.s); ++ ++ hdata->async.result = kzalloc(sizeof(*hdata->async.result), GFP_KERNEL); ++ if (unlikely(!hdata->async.result)) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ init_completion(&hdata->async.result->completion); ++ ++ hdata->async.request = ahash_request_alloc(hdata->async.s, GFP_KERNEL); ++ if (unlikely(!hdata->async.request)) { ++ derr(0, "error allocating async crypto request"); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ ahash_request_set_callback(hdata->async.request, ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ cryptodev_complete, hdata->async.result); ++ ++ ret = crypto_ahash_init(hdata->async.request); ++ if (unlikely(ret)) { ++ derr(0, "error in crypto_hash_init()"); ++ goto error_request; ++ } ++ ++ hdata->init = 1; ++ return 0; ++ ++error_request: ++ ahash_request_free(hdata->async.request); ++error: ++ kfree(hdata->async.result); ++ crypto_free_ahash(hdata->async.s); ++ return ret; ++} ++ ++void cryptodev_hash_deinit(struct hash_data *hdata) ++{ ++ if (hdata->init) { ++ if (hdata->async.request) ++ ahash_request_free(hdata->async.request); ++ kfree(hdata->async.result); ++ if (hdata->async.s) ++ crypto_free_ahash(hdata->async.s); ++ hdata->init = 0; ++ } ++} ++ ++int cryptodev_hash_reset(struct hash_data *hdata) ++{ ++ int ret; ++ ++ ret = crypto_ahash_init(hdata->async.request); ++ if (unlikely(ret)) { ++ derr(0, "error in crypto_hash_init()"); ++ return ret; ++ } ++ ++ return 0; ++ ++} ++ ++ssize_t cryptodev_hash_update(struct hash_data *hdata, ++ struct scatterlist *sg, size_t len) ++{ ++ int ret; ++ ++ reinit_completion(&hdata->async.result->completion); ++ ahash_request_set_crypt(hdata->async.request, sg, NULL, len); ++ ++ ret = crypto_ahash_update(hdata->async.request); ++ ++ return waitfor(hdata->async.result, ret); ++} ++ ++int cryptodev_hash_final(struct hash_data *hdata, void *output) ++{ ++ int ret; ++ ++ reinit_completion(&hdata->async.result->completion); ++ ahash_request_set_crypt(hdata->async.request, NULL, output, 0); ++ ++ ret = crypto_ahash_final(hdata->async.request); ++ ++ return waitfor(hdata->async.result, ret); ++} ++ +diff -Nur linux-3.14.72.orig/crypto/cryptodev/cryptlib.h linux-3.14.72/crypto/cryptodev/cryptlib.h +--- linux-3.14.72.orig/crypto/cryptodev/cryptlib.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/cryptlib.h 2016-06-19 22:11:55.065155743 +0200 +@@ -0,0 +1,93 @@ ++#ifndef CRYPTLIB_H ++# define CRYPTLIB_H ++ ++struct cipher_data { ++ int init; /* 0 uninitialized */ ++ int blocksize; ++ int aead; ++ int stream; ++ int ivsize; ++ int alignmask; ++ struct { ++ /* block ciphers */ ++ struct crypto_ablkcipher *s; ++ struct ablkcipher_request *request; ++ ++ /* AEAD ciphers */ ++ struct crypto_aead *as; ++ struct aead_request *arequest; ++ ++ struct cryptodev_result *result; ++ uint8_t iv[EALG_MAX_BLOCK_LEN]; ++ } async; ++}; ++ ++int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, ++ uint8_t *key, size_t keylen, int stream, int aead); ++void cryptodev_cipher_deinit(struct cipher_data *cdata); ++int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead); ++int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop, ++ int aead); ++ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata, ++ const struct scatterlist *sg1, ++ struct scatterlist *sg2, size_t len); ++ssize_t cryptodev_cipher_encrypt(struct cipher_data *cdata, ++ const struct scatterlist *sg1, ++ struct scatterlist *sg2, size_t len); ++ ++/* AEAD */ ++static inline void cryptodev_cipher_auth(struct cipher_data *cdata, ++ struct scatterlist *sg1, size_t len) ++{ ++ /* for some reason we _have_ to call that even for zero length sgs */ ++ aead_request_set_assoc(cdata->async.arequest, len ? sg1 : NULL, len); ++} ++ ++static inline void cryptodev_cipher_set_tag_size(struct cipher_data *cdata, int size) ++{ ++ if (likely(cdata->aead != 0)) ++ crypto_aead_setauthsize(cdata->async.as, size); ++} ++ ++static inline int cryptodev_cipher_get_tag_size(struct cipher_data *cdata) ++{ ++ if (likely(cdata->init && cdata->aead != 0)) ++ return crypto_aead_authsize(cdata->async.as); ++ else ++ return 0; ++} ++ ++static inline void cryptodev_cipher_set_iv(struct cipher_data *cdata, ++ void *iv, size_t iv_size) ++{ ++ memcpy(cdata->async.iv, iv, min(iv_size, sizeof(cdata->async.iv))); ++} ++ ++static inline void cryptodev_cipher_get_iv(struct cipher_data *cdata, ++ void *iv, size_t iv_size) ++{ ++ memcpy(iv, cdata->async.iv, min(iv_size, sizeof(cdata->async.iv))); ++} ++ ++/* Hash */ ++struct hash_data { ++ int init; /* 0 uninitialized */ ++ int digestsize; ++ int alignmask; ++ struct { ++ struct crypto_ahash *s; ++ struct cryptodev_result *result; ++ struct ahash_request *request; ++ } async; ++}; ++ ++int cryptodev_hash_final(struct hash_data *hdata, void *output); ++ssize_t cryptodev_hash_update(struct hash_data *hdata, ++ struct scatterlist *sg, size_t len); ++int cryptodev_hash_reset(struct hash_data *hdata); ++void cryptodev_hash_deinit(struct hash_data *hdata); ++int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, ++ int hmac_mode, void *mackey, size_t mackeylen); ++ ++ ++#endif +diff -Nur linux-3.14.72.orig/crypto/cryptodev/cryptodev_int.h linux-3.14.72/crypto/cryptodev/cryptodev_int.h +--- linux-3.14.72.orig/crypto/cryptodev/cryptodev_int.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/cryptodev_int.h 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,145 @@ ++/* cipher stuff */ ++#ifndef CRYPTODEV_INT_H ++# define CRYPTODEV_INT_H ++ ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) ++# define reinit_completion(x) INIT_COMPLETION(*(x)) ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PFX "cryptodev: " ++#define dprintk(level, severity, format, a...) \ ++ do { \ ++ if (level <= cryptodev_verbosity) \ ++ printk(severity PFX "%s[%u] (%s:%u): " format "\n", \ ++ current->comm, current->pid, \ ++ __func__, __LINE__, \ ++ ##a); \ ++ } while (0) ++#define derr(level, format, a...) dprintk(level, KERN_ERR, format, ##a) ++#define dwarning(level, format, a...) dprintk(level, KERN_WARNING, format, ##a) ++#define dinfo(level, format, a...) dprintk(level, KERN_INFO, format, ##a) ++#define ddebug(level, format, a...) dprintk(level, KERN_DEBUG, format, ##a) ++ ++ ++extern int cryptodev_verbosity; ++ ++struct fcrypt { ++ struct list_head list; ++ struct mutex sem; ++}; ++ ++/* compatibility stuff */ ++#ifdef CONFIG_COMPAT ++#include ++ ++/* input of CIOCGSESSION */ ++struct compat_session_op { ++ /* Specify either cipher or mac ++ */ ++ uint32_t cipher; /* cryptodev_crypto_op_t */ ++ uint32_t mac; /* cryptodev_crypto_op_t */ ++ ++ uint32_t keylen; ++ compat_uptr_t key; /* pointer to key data */ ++ uint32_t mackeylen; ++ compat_uptr_t mackey; /* pointer to mac key data */ ++ ++ uint32_t ses; /* session identifier */ ++}; ++ ++/* input of CIOCCRYPT */ ++struct compat_crypt_op { ++ uint32_t ses; /* session identifier */ ++ uint16_t op; /* COP_ENCRYPT or COP_DECRYPT */ ++ uint16_t flags; /* see COP_FLAG_* */ ++ uint32_t len; /* length of source data */ ++ compat_uptr_t src; /* source data */ ++ compat_uptr_t dst; /* pointer to output data */ ++ compat_uptr_t mac;/* pointer to output data for hash/MAC operations */ ++ compat_uptr_t iv;/* initialization vector for encryption operations */ ++}; ++ ++/* compat ioctls, defined for the above structs */ ++#define COMPAT_CIOCGSESSION _IOWR('c', 102, struct compat_session_op) ++#define COMPAT_CIOCCRYPT _IOWR('c', 104, struct compat_crypt_op) ++#define COMPAT_CIOCASYNCCRYPT _IOW('c', 107, struct compat_crypt_op) ++#define COMPAT_CIOCASYNCFETCH _IOR('c', 108, struct compat_crypt_op) ++ ++#endif /* CONFIG_COMPAT */ ++ ++/* kernel-internal extension to struct crypt_op */ ++struct kernel_crypt_op { ++ struct crypt_op cop; ++ ++ int ivlen; ++ __u8 iv[EALG_MAX_BLOCK_LEN]; ++ ++ int digestsize; ++ uint8_t hash_output[AALG_MAX_RESULT_LEN]; ++ ++ struct task_struct *task; ++ struct mm_struct *mm; ++}; ++ ++struct kernel_crypt_auth_op { ++ struct crypt_auth_op caop; ++ ++ int dst_len; /* based on src_len + pad + tag */ ++ int ivlen; ++ __u8 iv[EALG_MAX_BLOCK_LEN]; ++ ++ struct task_struct *task; ++ struct mm_struct *mm; ++}; ++ ++/* auth */ ++ ++int kcaop_from_user(struct kernel_crypt_auth_op *kcop, ++ struct fcrypt *fcr, void __user *arg); ++int kcaop_to_user(struct kernel_crypt_auth_op *kcaop, ++ struct fcrypt *fcr, void __user *arg); ++int crypto_auth_run(struct fcrypt *fcr, struct kernel_crypt_auth_op *kcaop); ++int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop); ++ ++#include ++ ++/* other internal structs */ ++struct csession { ++ struct list_head entry; ++ struct mutex sem; ++ struct cipher_data cdata; ++ struct hash_data hdata; ++ uint32_t sid; ++ uint32_t alignmask; ++ ++ unsigned int array_size; ++ unsigned int used_pages; /* the number of pages that are used */ ++ /* the number of pages marked as NOT-writable; they preceed writeables */ ++ unsigned int readonly_pages; ++ struct page **pages; ++ struct scatterlist *sg; ++}; ++ ++struct csession *crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid); ++ ++static inline void crypto_put_session(struct csession *ses_ptr) ++{ ++ mutex_unlock(&ses_ptr->sem); ++} ++int adjust_sg_array(struct csession *ses, int pagecount); ++ ++#endif /* CRYPTODEV_INT_H */ +diff -Nur linux-3.14.72.orig/crypto/cryptodev/ioctl.c linux-3.14.72/crypto/cryptodev/ioctl.c +--- linux-3.14.72.orig/crypto/cryptodev/ioctl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/ioctl.c 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,1169 @@ ++/* ++ * Driver for /dev/crypto device (aka CryptoDev) ++ * ++ * Copyright (c) 2004 Michal Ludvig , SuSE Labs ++ * Copyright (c) 2009,2010,2011 Nikos Mavrogiannopoulos ++ * Copyright (c) 2010 Phil Sutter ++ * ++ * This file is part of linux cryptodev. ++ * ++ * 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. ++ */ ++ ++/* ++ * Device /dev/crypto provides an interface for ++ * accessing kernel CryptoAPI algorithms (ciphers, ++ * hashes) from userspace programs. ++ * ++ * /dev/crypto interface was originally introduced in ++ * OpenBSD and this module attempts to keep the API. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "cryptodev_int.h" ++#include "zc.h" ++#include "version.h" ++ ++MODULE_AUTHOR("Nikos Mavrogiannopoulos "); ++MODULE_DESCRIPTION("CryptoDev driver"); ++MODULE_LICENSE("GPL"); ++ ++/* ====== Compile-time config ====== */ ++ ++/* Default (pre-allocated) and maximum size of the job queue. ++ * These are free, pending and done items all together. */ ++#define DEF_COP_RINGSIZE 16 ++#define MAX_COP_RINGSIZE 64 ++ ++/* ====== Module parameters ====== */ ++ ++int cryptodev_verbosity; ++module_param(cryptodev_verbosity, int, 0644); ++MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug"); ++ ++/* ====== CryptoAPI ====== */ ++struct todo_list_item { ++ struct list_head __hook; ++ struct kernel_crypt_op kcop; ++ int result; ++}; ++ ++struct locked_list { ++ struct list_head list; ++ struct mutex lock; ++}; ++ ++struct crypt_priv { ++ struct fcrypt fcrypt; ++ struct locked_list free, todo, done; ++ int itemcount; ++ struct work_struct cryptask; ++ wait_queue_head_t user_waiter; ++}; ++ ++#define FILL_SG(sg, ptr, len) \ ++ do { \ ++ (sg)->page = virt_to_page(ptr); \ ++ (sg)->offset = offset_in_page(ptr); \ ++ (sg)->length = len; \ ++ (sg)->dma_address = 0; \ ++ } while (0) ++ ++/* cryptodev's own workqueue, keeps crypto tasks from disturbing the force */ ++static struct workqueue_struct *cryptodev_wq; ++ ++/* Prepare session for future use. */ ++static int ++crypto_create_session(struct fcrypt *fcr, struct session_op *sop) ++{ ++ struct csession *ses_new = NULL, *ses_ptr; ++ int ret = 0; ++ const char *alg_name = NULL; ++ const char *hash_name = NULL; ++ int hmac_mode = 1, stream = 0, aead = 0; ++ /* ++ * With composite aead ciphers, only ckey is used and it can cover all the ++ * structure space; otherwise both keys may be used simultaneously but they ++ * are confined to their spaces ++ */ ++ struct { ++ uint8_t ckey[CRYPTO_CIPHER_MAX_KEY_LEN]; ++ uint8_t mkey[CRYPTO_HMAC_MAX_KEY_LEN]; ++ /* padding space for aead keys */ ++ uint8_t pad[RTA_SPACE(sizeof(struct crypto_authenc_key_param))]; ++ } keys; ++ ++ /* Does the request make sense? */ ++ if (unlikely(!sop->cipher && !sop->mac)) { ++ ddebug(1, "Both 'cipher' and 'mac' unset."); ++ return -EINVAL; ++ } ++ ++ switch (sop->cipher) { ++ case 0: ++ break; ++ case CRYPTO_DES_CBC: ++ alg_name = "cbc(des)"; ++ break; ++ case CRYPTO_3DES_CBC: ++ alg_name = "cbc(des3_ede)"; ++ break; ++ case CRYPTO_BLF_CBC: ++ alg_name = "cbc(blowfish)"; ++ break; ++ case CRYPTO_AES_CBC: ++ alg_name = "cbc(aes)"; ++ break; ++ case CRYPTO_AES_ECB: ++ alg_name = "ecb(aes)"; ++ break; ++ case CRYPTO_CAMELLIA_CBC: ++ alg_name = "cbc(camellia)"; ++ break; ++ case CRYPTO_AES_CTR: ++ alg_name = "ctr(aes)"; ++ stream = 1; ++ break; ++ case CRYPTO_AES_GCM: ++ alg_name = "gcm(aes)"; ++ stream = 1; ++ aead = 1; ++ break; ++ case CRYPTO_NULL: ++ alg_name = "ecb(cipher_null)"; ++ stream = 1; ++ break; ++ default: ++ ddebug(1, "bad cipher: %d", sop->cipher); ++ return -EINVAL; ++ } ++ ++ switch (sop->mac) { ++ case 0: ++ break; ++ case CRYPTO_MD5_HMAC: ++ hash_name = "hmac(md5)"; ++ break; ++ case CRYPTO_RIPEMD160_HMAC: ++ hash_name = "hmac(rmd160)"; ++ break; ++ case CRYPTO_SHA1_HMAC: ++ hash_name = "hmac(sha1)"; ++ break; ++ case CRYPTO_SHA2_224_HMAC: ++ hash_name = "hmac(sha224)"; ++ break; ++ ++ case CRYPTO_SHA2_256_HMAC: ++ hash_name = "hmac(sha256)"; ++ break; ++ case CRYPTO_SHA2_384_HMAC: ++ hash_name = "hmac(sha384)"; ++ break; ++ case CRYPTO_SHA2_512_HMAC: ++ hash_name = "hmac(sha512)"; ++ break; ++ ++ /* non-hmac cases */ ++ case CRYPTO_MD5: ++ hash_name = "md5"; ++ hmac_mode = 0; ++ break; ++ case CRYPTO_RIPEMD160: ++ hash_name = "rmd160"; ++ hmac_mode = 0; ++ break; ++ case CRYPTO_SHA1: ++ hash_name = "sha1"; ++ hmac_mode = 0; ++ break; ++ case CRYPTO_SHA2_224: ++ hash_name = "sha224"; ++ hmac_mode = 0; ++ break; ++ case CRYPTO_SHA2_256: ++ hash_name = "sha256"; ++ hmac_mode = 0; ++ break; ++ case CRYPTO_SHA2_384: ++ hash_name = "sha384"; ++ hmac_mode = 0; ++ break; ++ case CRYPTO_SHA2_512: ++ hash_name = "sha512"; ++ hmac_mode = 0; ++ break; ++ default: ++ ddebug(1, "bad mac: %d", sop->mac); ++ return -EINVAL; ++ } ++ ++ /* Create a session and put it to the list. */ ++ ses_new = kzalloc(sizeof(*ses_new), GFP_KERNEL); ++ if (!ses_new) ++ return -ENOMEM; ++ ++ /* Set-up crypto transform. */ ++ if (alg_name) { ++ unsigned int keylen; ++ ret = cryptodev_get_cipher_keylen(&keylen, sop, aead); ++ if (unlikely(ret < 0)) { ++ ddebug(1, "Setting key failed for %s-%zu.", ++ alg_name, (size_t)sop->keylen*8); ++ goto error_cipher; ++ } ++ ++ ret = cryptodev_get_cipher_key(keys.ckey, sop, aead); ++ if (unlikely(ret < 0)) ++ goto error_cipher; ++ ++ ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keys.ckey, ++ keylen, stream, aead); ++ if (ret < 0) { ++ ddebug(1, "Failed to load cipher for %s", alg_name); ++ ret = -EINVAL; ++ goto error_cipher; ++ } ++ } ++ ++ if (hash_name && aead == 0) { ++ if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) { ++ ddebug(1, "Setting key failed for %s-%zu.", ++ hash_name, (size_t)sop->mackeylen*8); ++ ret = -EINVAL; ++ goto error_hash; ++ } ++ ++ if (sop->mackey && unlikely(copy_from_user(keys.mkey, sop->mackey, ++ sop->mackeylen))) { ++ ret = -EFAULT; ++ goto error_hash; ++ } ++ ++ ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode, ++ keys.mkey, sop->mackeylen); ++ if (ret != 0) { ++ ddebug(1, "Failed to load hash for %s", hash_name); ++ ret = -EINVAL; ++ goto error_hash; ++ } ++ } ++ ++ ses_new->alignmask = max(ses_new->cdata.alignmask, ++ ses_new->hdata.alignmask); ++ ddebug(2, "got alignmask %d", ses_new->alignmask); ++ ++ ses_new->array_size = DEFAULT_PREALLOC_PAGES; ++ ddebug(2, "preallocating for %d user pages", ses_new->array_size); ++ ses_new->pages = kzalloc(ses_new->array_size * ++ sizeof(struct page *), GFP_KERNEL); ++ ses_new->sg = kzalloc(ses_new->array_size * ++ sizeof(struct scatterlist), GFP_KERNEL); ++ if (ses_new->sg == NULL || ses_new->pages == NULL) { ++ ddebug(0, "Memory error"); ++ ret = -ENOMEM; ++ goto error_hash; ++ } ++ ++ /* put the new session to the list */ ++ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid)); ++ mutex_init(&ses_new->sem); ++ ++ mutex_lock(&fcr->sem); ++restart: ++ list_for_each_entry(ses_ptr, &fcr->list, entry) { ++ /* Check for duplicate SID */ ++ if (unlikely(ses_new->sid == ses_ptr->sid)) { ++ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid)); ++ /* Unless we have a broken RNG this ++ shouldn't loop forever... ;-) */ ++ goto restart; ++ } ++ } ++ ++ list_add(&ses_new->entry, &fcr->list); ++ mutex_unlock(&fcr->sem); ++ ++ /* Fill in some values for the user. */ ++ sop->ses = ses_new->sid; ++ ++ return 0; ++ ++error_hash: ++ cryptodev_cipher_deinit(&ses_new->cdata); ++ kfree(ses_new->sg); ++ kfree(ses_new->pages); ++error_cipher: ++ kfree(ses_new); ++ ++ return ret; ++ ++} ++ ++/* Everything that needs to be done when remowing a session. */ ++static inline void ++crypto_destroy_session(struct csession *ses_ptr) ++{ ++ if (!mutex_trylock(&ses_ptr->sem)) { ++ ddebug(2, "Waiting for semaphore of sid=0x%08X", ses_ptr->sid); ++ mutex_lock(&ses_ptr->sem); ++ } ++ ddebug(2, "Removed session 0x%08X", ses_ptr->sid); ++ cryptodev_cipher_deinit(&ses_ptr->cdata); ++ cryptodev_hash_deinit(&ses_ptr->hdata); ++ ddebug(2, "freeing space for %d user pages", ses_ptr->array_size); ++ kfree(ses_ptr->pages); ++ kfree(ses_ptr->sg); ++ mutex_unlock(&ses_ptr->sem); ++ mutex_destroy(&ses_ptr->sem); ++ kfree(ses_ptr); ++} ++ ++/* Look up a session by ID and remove. */ ++static int ++crypto_finish_session(struct fcrypt *fcr, uint32_t sid) ++{ ++ struct csession *tmp, *ses_ptr; ++ struct list_head *head; ++ int ret = 0; ++ ++ mutex_lock(&fcr->sem); ++ head = &fcr->list; ++ list_for_each_entry_safe(ses_ptr, tmp, head, entry) { ++ if (ses_ptr->sid == sid) { ++ list_del(&ses_ptr->entry); ++ crypto_destroy_session(ses_ptr); ++ break; ++ } ++ } ++ ++ if (unlikely(!ses_ptr)) { ++ derr(1, "Session with sid=0x%08X not found!", sid); ++ ret = -ENOENT; ++ } ++ mutex_unlock(&fcr->sem); ++ ++ return ret; ++} ++ ++/* Remove all sessions when closing the file */ ++static int ++crypto_finish_all_sessions(struct fcrypt *fcr) ++{ ++ struct csession *tmp, *ses_ptr; ++ struct list_head *head; ++ ++ mutex_lock(&fcr->sem); ++ ++ head = &fcr->list; ++ list_for_each_entry_safe(ses_ptr, tmp, head, entry) { ++ list_del(&ses_ptr->entry); ++ crypto_destroy_session(ses_ptr); ++ } ++ mutex_unlock(&fcr->sem); ++ ++ return 0; ++} ++ ++/* Look up session by session ID. The returned session is locked. */ ++struct csession * ++crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid) ++{ ++ struct csession *ses_ptr, *retval = NULL; ++ ++ if (unlikely(fcr == NULL)) ++ return NULL; ++ ++ mutex_lock(&fcr->sem); ++ list_for_each_entry(ses_ptr, &fcr->list, entry) { ++ if (ses_ptr->sid == sid) { ++ mutex_lock(&ses_ptr->sem); ++ retval = ses_ptr; ++ break; ++ } ++ } ++ mutex_unlock(&fcr->sem); ++ ++ return retval; ++} ++ ++static void cryptask_routine(struct work_struct *work) ++{ ++ struct crypt_priv *pcr = container_of(work, struct crypt_priv, cryptask); ++ struct todo_list_item *item; ++ LIST_HEAD(tmp); ++ ++ /* fetch all pending jobs into the temporary list */ ++ mutex_lock(&pcr->todo.lock); ++ list_cut_position(&tmp, &pcr->todo.list, pcr->todo.list.prev); ++ mutex_unlock(&pcr->todo.lock); ++ ++ /* handle each job locklessly */ ++ list_for_each_entry(item, &tmp, __hook) { ++ item->result = crypto_run(&pcr->fcrypt, &item->kcop); ++ if (unlikely(item->result)) ++ derr(0, "crypto_run() failed: %d", item->result); ++ } ++ ++ /* push all handled jobs to the done list at once */ ++ mutex_lock(&pcr->done.lock); ++ list_splice_tail(&tmp, &pcr->done.list); ++ mutex_unlock(&pcr->done.lock); ++ ++ /* wake for POLLIN */ ++ wake_up_interruptible(&pcr->user_waiter); ++} ++ ++/* ====== /dev/crypto ====== */ ++ ++static int ++cryptodev_open(struct inode *inode, struct file *filp) ++{ ++ struct todo_list_item *tmp, *tmp_next; ++ struct crypt_priv *pcr; ++ int i; ++ ++ pcr = kzalloc(sizeof(*pcr), GFP_KERNEL); ++ if (!pcr) ++ return -ENOMEM; ++ filp->private_data = pcr; ++ ++ mutex_init(&pcr->fcrypt.sem); ++ mutex_init(&pcr->free.lock); ++ mutex_init(&pcr->todo.lock); ++ mutex_init(&pcr->done.lock); ++ ++ INIT_LIST_HEAD(&pcr->fcrypt.list); ++ INIT_LIST_HEAD(&pcr->free.list); ++ INIT_LIST_HEAD(&pcr->todo.list); ++ INIT_LIST_HEAD(&pcr->done.list); ++ ++ INIT_WORK(&pcr->cryptask, cryptask_routine); ++ ++ init_waitqueue_head(&pcr->user_waiter); ++ ++ for (i = 0; i < DEF_COP_RINGSIZE; i++) { ++ tmp = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL); ++ if (!tmp) ++ goto err_ringalloc; ++ pcr->itemcount++; ++ ddebug(2, "allocated new item at %p", tmp); ++ list_add(&tmp->__hook, &pcr->free.list); ++ } ++ ++ ddebug(2, "Cryptodev handle initialised, %d elements in queue", ++ DEF_COP_RINGSIZE); ++ return 0; ++ ++/* In case of errors, free any memory allocated so far */ ++err_ringalloc: ++ list_for_each_entry_safe(tmp, tmp_next, &pcr->free.list, __hook) { ++ list_del(&tmp->__hook); ++ kfree(tmp); ++ } ++ mutex_destroy(&pcr->done.lock); ++ mutex_destroy(&pcr->todo.lock); ++ mutex_destroy(&pcr->free.lock); ++ mutex_destroy(&pcr->fcrypt.sem); ++ kfree(pcr); ++ filp->private_data = NULL; ++ return -ENOMEM; ++} ++ ++static int ++cryptodev_release(struct inode *inode, struct file *filp) ++{ ++ struct crypt_priv *pcr = filp->private_data; ++ struct todo_list_item *item, *item_safe; ++ int items_freed = 0; ++ ++ if (!pcr) ++ return 0; ++ ++ cancel_work_sync(&pcr->cryptask); ++ ++ list_splice_tail(&pcr->todo.list, &pcr->free.list); ++ list_splice_tail(&pcr->done.list, &pcr->free.list); ++ ++ list_for_each_entry_safe(item, item_safe, &pcr->free.list, __hook) { ++ ddebug(2, "freeing item at %p", item); ++ list_del(&item->__hook); ++ kfree(item); ++ items_freed++; ++ } ++ ++ if (items_freed != pcr->itemcount) { ++ derr(0, "freed %d items, but %d should exist!", ++ items_freed, pcr->itemcount); ++ } ++ ++ crypto_finish_all_sessions(&pcr->fcrypt); ++ ++ mutex_destroy(&pcr->done.lock); ++ mutex_destroy(&pcr->todo.lock); ++ mutex_destroy(&pcr->free.lock); ++ mutex_destroy(&pcr->fcrypt.sem); ++ ++ kfree(pcr); ++ filp->private_data = NULL; ++ ++ ddebug(2, "Cryptodev handle deinitialised, %d elements freed", ++ items_freed); ++ return 0; ++} ++ ++static int ++clonefd(struct file *filp) ++{ ++ int ret; ++ ret = get_unused_fd_flags(0); ++ if (ret >= 0) { ++ get_file(filp); ++ fd_install(ret, filp); ++ } ++ ++ return ret; ++} ++ ++#ifdef ENABLE_ASYNC ++/* enqueue a job for asynchronous completion ++ * ++ * returns: ++ * -EBUSY when there are no free queue slots left ++ * (and the number of slots has reached it MAX_COP_RINGSIZE) ++ * -EFAULT when there was a memory allocation error ++ * 0 on success */ ++static int crypto_async_run(struct crypt_priv *pcr, struct kernel_crypt_op *kcop) ++{ ++ struct todo_list_item *item = NULL; ++ ++ if (unlikely(kcop->cop.flags & COP_FLAG_NO_ZC)) ++ return -EINVAL; ++ ++ mutex_lock(&pcr->free.lock); ++ if (likely(!list_empty(&pcr->free.list))) { ++ item = list_first_entry(&pcr->free.list, ++ struct todo_list_item, __hook); ++ list_del(&item->__hook); ++ } else if (pcr->itemcount < MAX_COP_RINGSIZE) { ++ pcr->itemcount++; ++ } else { ++ mutex_unlock(&pcr->free.lock); ++ return -EBUSY; ++ } ++ mutex_unlock(&pcr->free.lock); ++ ++ if (unlikely(!item)) { ++ item = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL); ++ if (unlikely(!item)) ++ return -EFAULT; ++ dinfo(1, "increased item count to %d", pcr->itemcount); ++ } ++ ++ memcpy(&item->kcop, kcop, sizeof(struct kernel_crypt_op)); ++ ++ mutex_lock(&pcr->todo.lock); ++ list_add_tail(&item->__hook, &pcr->todo.list); ++ mutex_unlock(&pcr->todo.lock); ++ ++ queue_work(cryptodev_wq, &pcr->cryptask); ++ return 0; ++} ++ ++/* get the first completed job from the "done" queue ++ * ++ * returns: ++ * -EBUSY if no completed jobs are ready (yet) ++ * the return value of crypto_run() otherwise */ ++static int crypto_async_fetch(struct crypt_priv *pcr, ++ struct kernel_crypt_op *kcop) ++{ ++ struct todo_list_item *item; ++ int retval; ++ ++ mutex_lock(&pcr->done.lock); ++ if (list_empty(&pcr->done.list)) { ++ mutex_unlock(&pcr->done.lock); ++ return -EBUSY; ++ } ++ item = list_first_entry(&pcr->done.list, struct todo_list_item, __hook); ++ list_del(&item->__hook); ++ mutex_unlock(&pcr->done.lock); ++ ++ memcpy(kcop, &item->kcop, sizeof(struct kernel_crypt_op)); ++ retval = item->result; ++ ++ mutex_lock(&pcr->free.lock); ++ list_add_tail(&item->__hook, &pcr->free.list); ++ mutex_unlock(&pcr->free.lock); ++ ++ /* wake for POLLOUT */ ++ wake_up_interruptible(&pcr->user_waiter); ++ ++ return retval; ++} ++#endif ++ ++/* this function has to be called from process context */ ++static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr) ++{ ++ struct crypt_op *cop = &kcop->cop; ++ struct csession *ses_ptr; ++ int rc; ++ ++ /* this also enters ses_ptr->sem */ ++ ses_ptr = crypto_get_session_by_sid(fcr, cop->ses); ++ if (unlikely(!ses_ptr)) { ++ derr(1, "invalid session ID=0x%08X", cop->ses); ++ return -EINVAL; ++ } ++ kcop->ivlen = cop->iv ? ses_ptr->cdata.ivsize : 0; ++ kcop->digestsize = 0; /* will be updated during operation */ ++ ++ crypto_put_session(ses_ptr); ++ ++ kcop->task = current; ++ kcop->mm = current->mm; ++ ++ if (cop->iv) { ++ rc = copy_from_user(kcop->iv, cop->iv, kcop->ivlen); ++ if (unlikely(rc)) { ++ derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p", ++ kcop->ivlen, rc, cop->iv); ++ return -EFAULT; ++ } ++ } ++ ++ return 0; ++} ++ ++/* this function has to be called from process context */ ++static int fill_cop_from_kcop(struct kernel_crypt_op *kcop, struct fcrypt *fcr) ++{ ++ int ret; ++ ++ if (kcop->digestsize) { ++ ret = copy_to_user(kcop->cop.mac, ++ kcop->hash_output, kcop->digestsize); ++ if (unlikely(ret)) ++ return -EFAULT; ++ } ++ if (kcop->ivlen && kcop->cop.flags & COP_FLAG_WRITE_IV) { ++ ret = copy_to_user(kcop->cop.iv, ++ kcop->iv, kcop->ivlen); ++ if (unlikely(ret)) ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int kcop_from_user(struct kernel_crypt_op *kcop, ++ struct fcrypt *fcr, void __user *arg) ++{ ++ if (unlikely(copy_from_user(&kcop->cop, arg, sizeof(kcop->cop)))) ++ return -EFAULT; ++ ++ return fill_kcop_from_cop(kcop, fcr); ++} ++ ++static int kcop_to_user(struct kernel_crypt_op *kcop, ++ struct fcrypt *fcr, void __user *arg) ++{ ++ int ret; ++ ++ ret = fill_cop_from_kcop(kcop, fcr); ++ if (unlikely(ret)) { ++ derr(1, "Error in fill_cop_from_kcop"); ++ return ret; ++ } ++ ++ if (unlikely(copy_to_user(arg, &kcop->cop, sizeof(kcop->cop)))) { ++ derr(1, "Cannot copy to userspace"); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static inline void tfm_info_to_alg_info(struct alg_info *dst, struct crypto_tfm *tfm) ++{ ++ snprintf(dst->cra_name, CRYPTODEV_MAX_ALG_NAME, ++ "%s", crypto_tfm_alg_name(tfm)); ++ snprintf(dst->cra_driver_name, CRYPTODEV_MAX_ALG_NAME, ++ "%s", crypto_tfm_alg_driver_name(tfm)); ++} ++ ++#ifndef CRYPTO_ALG_KERN_DRIVER_ONLY ++static unsigned int is_known_accelerated(struct crypto_tfm *tfm) ++{ ++ const char *name = crypto_tfm_alg_driver_name(tfm); ++ ++ if (name == NULL) ++ return 1; /* assume accelerated */ ++ ++ /* look for known crypto engine names */ ++ if (strstr(name, "-talitos") || ++ !strncmp(name, "mv-", 3) || ++ !strncmp(name, "atmel-", 6) || ++ strstr(name, "geode") || ++ strstr(name, "hifn") || ++ strstr(name, "-ixp4xx") || ++ strstr(name, "-omap") || ++ strstr(name, "-picoxcell") || ++ strstr(name, "-s5p") || ++ strstr(name, "-ppc4xx") || ++ strstr(name, "-caam") || ++ strstr(name, "-n2")) ++ return 1; ++ ++ return 0; ++} ++#endif ++ ++static int get_session_info(struct fcrypt *fcr, struct session_info_op *siop) ++{ ++ struct csession *ses_ptr; ++ struct crypto_tfm *tfm; ++ ++ /* this also enters ses_ptr->sem */ ++ ses_ptr = crypto_get_session_by_sid(fcr, siop->ses); ++ if (unlikely(!ses_ptr)) { ++ derr(1, "invalid session ID=0x%08X", siop->ses); ++ return -EINVAL; ++ } ++ ++ siop->flags = 0; ++ ++ if (ses_ptr->cdata.init) { ++ if (ses_ptr->cdata.aead == 0) ++ tfm = crypto_ablkcipher_tfm(ses_ptr->cdata.async.s); ++ else ++ tfm = crypto_aead_tfm(ses_ptr->cdata.async.as); ++ tfm_info_to_alg_info(&siop->cipher_info, tfm); ++#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY ++ if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY) ++ siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; ++#else ++ if (is_known_accelerated(tfm)) ++ siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; ++#endif ++ } ++ if (ses_ptr->hdata.init) { ++ tfm = crypto_ahash_tfm(ses_ptr->hdata.async.s); ++ tfm_info_to_alg_info(&siop->hash_info, tfm); ++#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY ++ if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY) ++ siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; ++#else ++ if (is_known_accelerated(tfm)) ++ siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; ++#endif ++ } ++ ++ siop->alignmask = ses_ptr->alignmask; ++ ++ crypto_put_session(ses_ptr); ++ return 0; ++} ++ ++static long ++cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_) ++{ ++ void __user *arg = (void __user *)arg_; ++ int __user *p = arg; ++ struct session_op sop; ++ struct kernel_crypt_op kcop; ++ struct kernel_crypt_auth_op kcaop; ++ struct crypt_priv *pcr = filp->private_data; ++ struct fcrypt *fcr; ++ struct session_info_op siop; ++ uint32_t ses; ++ int ret, fd; ++ ++ if (unlikely(!pcr)) ++ BUG(); ++ ++ fcr = &pcr->fcrypt; ++ ++ switch (cmd) { ++ case CIOCASYMFEAT: ++ return put_user(0, p); ++ case CRIOGET: ++ fd = clonefd(filp); ++ ret = put_user(fd, p); ++ if (unlikely(ret)) { ++ sys_close(fd); ++ return ret; ++ } ++ return ret; ++ case CIOCGSESSION: ++ if (unlikely(copy_from_user(&sop, arg, sizeof(sop)))) ++ return -EFAULT; ++ ++ ret = crypto_create_session(fcr, &sop); ++ if (unlikely(ret)) ++ return ret; ++ ret = copy_to_user(arg, &sop, sizeof(sop)); ++ if (unlikely(ret)) { ++ crypto_finish_session(fcr, sop.ses); ++ return -EFAULT; ++ } ++ return ret; ++ case CIOCFSESSION: ++ ret = get_user(ses, (uint32_t __user *)arg); ++ if (unlikely(ret)) ++ return ret; ++ ret = crypto_finish_session(fcr, ses); ++ return ret; ++ case CIOCGSESSINFO: ++ if (unlikely(copy_from_user(&siop, arg, sizeof(siop)))) ++ return -EFAULT; ++ ++ ret = get_session_info(fcr, &siop); ++ if (unlikely(ret)) ++ return ret; ++ return copy_to_user(arg, &siop, sizeof(siop)); ++ case CIOCCRYPT: ++ if (unlikely(ret = kcop_from_user(&kcop, fcr, arg))) { ++ dwarning(1, "Error copying from user"); ++ return ret; ++ } ++ ++ ret = crypto_run(fcr, &kcop); ++ if (unlikely(ret)) { ++ dwarning(1, "Error in crypto_run"); ++ return ret; ++ } ++ ++ return kcop_to_user(&kcop, fcr, arg); ++ case CIOCAUTHCRYPT: ++ if (unlikely(ret = kcaop_from_user(&kcaop, fcr, arg))) { ++ dwarning(1, "Error copying from user"); ++ return ret; ++ } ++ ++ ret = crypto_auth_run(fcr, &kcaop); ++ if (unlikely(ret)) { ++ dwarning(1, "Error in crypto_auth_run"); ++ return ret; ++ } ++ return kcaop_to_user(&kcaop, fcr, arg); ++#ifdef ENABLE_ASYNC ++ case CIOCASYNCCRYPT: ++ if (unlikely(ret = kcop_from_user(&kcop, fcr, arg))) ++ return ret; ++ ++ return crypto_async_run(pcr, &kcop); ++ case CIOCASYNCFETCH: ++ ret = crypto_async_fetch(pcr, &kcop); ++ if (unlikely(ret)) ++ return ret; ++ ++ return kcop_to_user(&kcop, fcr, arg); ++#endif ++ default: ++ return -EINVAL; ++ } ++} ++ ++/* compatibility code for 32bit userlands */ ++#ifdef CONFIG_COMPAT ++ ++static inline void ++compat_to_session_op(struct compat_session_op *compat, struct session_op *sop) ++{ ++ sop->cipher = compat->cipher; ++ sop->mac = compat->mac; ++ sop->keylen = compat->keylen; ++ ++ sop->key = compat_ptr(compat->key); ++ sop->mackeylen = compat->mackeylen; ++ sop->mackey = compat_ptr(compat->mackey); ++ sop->ses = compat->ses; ++} ++ ++static inline void ++session_op_to_compat(struct session_op *sop, struct compat_session_op *compat) ++{ ++ compat->cipher = sop->cipher; ++ compat->mac = sop->mac; ++ compat->keylen = sop->keylen; ++ ++ compat->key = ptr_to_compat(sop->key); ++ compat->mackeylen = sop->mackeylen; ++ compat->mackey = ptr_to_compat(sop->mackey); ++ compat->ses = sop->ses; ++} ++ ++static inline void ++compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop) ++{ ++ cop->ses = compat->ses; ++ cop->op = compat->op; ++ cop->flags = compat->flags; ++ cop->len = compat->len; ++ ++ cop->src = compat_ptr(compat->src); ++ cop->dst = compat_ptr(compat->dst); ++ cop->mac = compat_ptr(compat->mac); ++ cop->iv = compat_ptr(compat->iv); ++} ++ ++static inline void ++crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat) ++{ ++ compat->ses = cop->ses; ++ compat->op = cop->op; ++ compat->flags = cop->flags; ++ compat->len = cop->len; ++ ++ compat->src = ptr_to_compat(cop->src); ++ compat->dst = ptr_to_compat(cop->dst); ++ compat->mac = ptr_to_compat(cop->mac); ++ compat->iv = ptr_to_compat(cop->iv); ++} ++ ++static int compat_kcop_from_user(struct kernel_crypt_op *kcop, ++ struct fcrypt *fcr, void __user *arg) ++{ ++ struct compat_crypt_op compat_cop; ++ ++ if (unlikely(copy_from_user(&compat_cop, arg, sizeof(compat_cop)))) ++ return -EFAULT; ++ compat_to_crypt_op(&compat_cop, &kcop->cop); ++ ++ return fill_kcop_from_cop(kcop, fcr); ++} ++ ++static int compat_kcop_to_user(struct kernel_crypt_op *kcop, ++ struct fcrypt *fcr, void __user *arg) ++{ ++ int ret; ++ struct compat_crypt_op compat_cop; ++ ++ ret = fill_cop_from_kcop(kcop, fcr); ++ if (unlikely(ret)) { ++ dwarning(1, "Error in fill_cop_from_kcop"); ++ return ret; ++ } ++ crypt_op_to_compat(&kcop->cop, &compat_cop); ++ ++ if (unlikely(copy_to_user(arg, &compat_cop, sizeof(compat_cop)))) { ++ dwarning(1, "Error copying to user"); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static long ++cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_) ++{ ++ void __user *arg = (void __user *)arg_; ++ struct crypt_priv *pcr = file->private_data; ++ struct fcrypt *fcr; ++ struct session_op sop; ++ struct compat_session_op compat_sop; ++ struct kernel_crypt_op kcop; ++ int ret; ++ ++ if (unlikely(!pcr)) ++ BUG(); ++ ++ fcr = &pcr->fcrypt; ++ ++ switch (cmd) { ++ case CIOCASYMFEAT: ++ case CRIOGET: ++ case CIOCFSESSION: ++ case CIOCGSESSINFO: ++ return cryptodev_ioctl(file, cmd, arg_); ++ ++ case COMPAT_CIOCGSESSION: ++ if (unlikely(copy_from_user(&compat_sop, arg, ++ sizeof(compat_sop)))) ++ return -EFAULT; ++ compat_to_session_op(&compat_sop, &sop); ++ ++ ret = crypto_create_session(fcr, &sop); ++ if (unlikely(ret)) ++ return ret; ++ ++ session_op_to_compat(&sop, &compat_sop); ++ ret = copy_to_user(arg, &compat_sop, sizeof(compat_sop)); ++ if (unlikely(ret)) { ++ crypto_finish_session(fcr, sop.ses); ++ return -EFAULT; ++ } ++ return ret; ++ ++ case COMPAT_CIOCCRYPT: ++ ret = compat_kcop_from_user(&kcop, fcr, arg); ++ if (unlikely(ret)) ++ return ret; ++ ++ ret = crypto_run(fcr, &kcop); ++ if (unlikely(ret)) ++ return ret; ++ ++ return compat_kcop_to_user(&kcop, fcr, arg); ++#ifdef ENABLE_ASYNC ++ case COMPAT_CIOCASYNCCRYPT: ++ if (unlikely(ret = compat_kcop_from_user(&kcop, fcr, arg))) ++ return ret; ++ ++ return crypto_async_run(pcr, &kcop); ++ case COMPAT_CIOCASYNCFETCH: ++ ret = crypto_async_fetch(pcr, &kcop); ++ if (unlikely(ret)) ++ return ret; ++ ++ return compat_kcop_to_user(&kcop, fcr, arg); ++#endif ++ default: ++ return -EINVAL; ++ } ++} ++ ++#endif /* CONFIG_COMPAT */ ++ ++static unsigned int cryptodev_poll(struct file *file, poll_table *wait) ++{ ++ struct crypt_priv *pcr = file->private_data; ++ int ret = 0; ++ ++ poll_wait(file, &pcr->user_waiter, wait); ++ ++ if (!list_empty_careful(&pcr->done.list)) ++ ret |= POLLIN | POLLRDNORM; ++ if (!list_empty_careful(&pcr->free.list) || pcr->itemcount < MAX_COP_RINGSIZE) ++ ret |= POLLOUT | POLLWRNORM; ++ ++ return ret; ++} ++ ++static const struct file_operations cryptodev_fops = { ++ .owner = THIS_MODULE, ++ .open = cryptodev_open, ++ .release = cryptodev_release, ++ .unlocked_ioctl = cryptodev_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = cryptodev_compat_ioctl, ++#endif /* CONFIG_COMPAT */ ++ .poll = cryptodev_poll, ++}; ++ ++static struct miscdevice cryptodev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "crypto", ++ .fops = &cryptodev_fops, ++ .mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, ++}; ++ ++static int __init ++cryptodev_register(void) ++{ ++ int rc; ++ ++ rc = misc_register(&cryptodev); ++ if (unlikely(rc)) { ++ pr_err(PFX "registration of /dev/crypto failed\n"); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static void __exit ++cryptodev_deregister(void) ++{ ++ misc_deregister(&cryptodev); ++} ++ ++/* ====== Module init/exit ====== */ ++static struct ctl_table verbosity_ctl_dir[] = { ++ { ++ .procname = "cryptodev_verbosity", ++ .data = &cryptodev_verbosity, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ {0, }, ++}; ++ ++static struct ctl_table verbosity_ctl_root[] = { ++ { ++ .procname = "ioctl", ++ .mode = 0555, ++ .child = verbosity_ctl_dir, ++ }, ++ {0, }, ++}; ++static struct ctl_table_header *verbosity_sysctl_header; ++static int __init init_cryptodev(void) ++{ ++ int rc; ++ ++ cryptodev_wq = create_workqueue("cryptodev_queue"); ++ if (unlikely(!cryptodev_wq)) { ++ pr_err(PFX "failed to allocate the cryptodev workqueue\n"); ++ return -EFAULT; ++ } ++ ++ rc = cryptodev_register(); ++ if (unlikely(rc)) { ++ destroy_workqueue(cryptodev_wq); ++ return rc; ++ } ++ ++ verbosity_sysctl_header = register_sysctl_table(verbosity_ctl_root); ++ ++ pr_info(PFX "driver %s loaded.\n", VERSION); ++ ++ return 0; ++} ++ ++static void __exit exit_cryptodev(void) ++{ ++ flush_workqueue(cryptodev_wq); ++ destroy_workqueue(cryptodev_wq); ++ ++ if (verbosity_sysctl_header) ++ unregister_sysctl_table(verbosity_sysctl_header); ++ ++ cryptodev_deregister(); ++ pr_info(PFX "driver unloaded.\n"); ++} ++ ++module_init(init_cryptodev); ++module_exit(exit_cryptodev); ++ +diff -Nur linux-3.14.72.orig/crypto/cryptodev/main.c linux-3.14.72/crypto/cryptodev/main.c +--- linux-3.14.72.orig/crypto/cryptodev/main.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/main.c 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,267 @@ ++/* ++ * Driver for /dev/crypto device (aka CryptoDev) ++ * ++ * Copyright (c) 2004 Michal Ludvig , SuSE Labs ++ * Copyright (c) 2009-2013 Nikos Mavrogiannopoulos ++ * ++ * This file is part of linux cryptodev. ++ * ++ * 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. ++ */ ++ ++/* ++ * Device /dev/crypto provides an interface for ++ * accessing kernel CryptoAPI algorithms (ciphers, ++ * hashes) from userspace programs. ++ * ++ * /dev/crypto interface was originally introduced in ++ * OpenBSD and this module attempts to keep the API. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "cryptodev_int.h" ++#include "zc.h" ++#include "cryptlib.h" ++#include "version.h" ++ ++/* This file contains the traditional operations of encryption ++ * and hashing of /dev/crypto. ++ */ ++ ++static int ++hash_n_crypt(struct csession *ses_ptr, struct crypt_op *cop, ++ struct scatterlist *src_sg, struct scatterlist *dst_sg, ++ uint32_t len) ++{ ++ int ret; ++ ++ /* Always hash before encryption and after decryption. Maybe ++ * we should introduce a flag to switch... TBD later on. ++ */ ++ if (cop->op == COP_ENCRYPT) { ++ if (ses_ptr->hdata.init != 0) { ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ src_sg, len); ++ if (unlikely(ret)) ++ goto out_err; ++ } ++ if (ses_ptr->cdata.init != 0) { ++ ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, ++ src_sg, dst_sg, len); ++ ++ if (unlikely(ret)) ++ goto out_err; ++ } ++ } else { ++ if (ses_ptr->cdata.init != 0) { ++ ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, ++ src_sg, dst_sg, len); ++ ++ if (unlikely(ret)) ++ goto out_err; ++ } ++ ++ if (ses_ptr->hdata.init != 0) { ++ ret = cryptodev_hash_update(&ses_ptr->hdata, ++ dst_sg, len); ++ if (unlikely(ret)) ++ goto out_err; ++ } ++ } ++ return 0; ++out_err: ++ derr(0, "CryptoAPI failure: %d", ret); ++ return ret; ++} ++ ++/* This is the main crypto function - feed it with plaintext ++ and get a ciphertext (or vice versa :-) */ ++static int ++__crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop) ++{ ++ char *data; ++ char __user *src, *dst; ++ struct scatterlist sg; ++ size_t nbytes, bufsize; ++ int ret = 0; ++ ++ nbytes = cop->len; ++ data = (char *)__get_free_page(GFP_KERNEL); ++ ++ if (unlikely(!data)) { ++ derr(1, "Error getting free page."); ++ return -ENOMEM; ++ } ++ ++ bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; ++ ++ src = cop->src; ++ dst = cop->dst; ++ ++ while (nbytes > 0) { ++ size_t current_len = nbytes > bufsize ? bufsize : nbytes; ++ ++ if (unlikely(copy_from_user(data, src, current_len))) { ++ derr(1, "Error copying %zu bytes from user address %p.", current_len, src); ++ ret = -EFAULT; ++ break; ++ } ++ ++ sg_init_one(&sg, data, current_len); ++ ++ ret = hash_n_crypt(ses_ptr, cop, &sg, &sg, current_len); ++ ++ if (unlikely(ret)) { ++ derr(1, "hash_n_crypt failed."); ++ break; ++ } ++ ++ if (ses_ptr->cdata.init != 0) { ++ if (unlikely(copy_to_user(dst, data, current_len))) { ++ derr(1, "could not copy to user."); ++ ret = -EFAULT; ++ break; ++ } ++ } ++ ++ dst += current_len; ++ nbytes -= current_len; ++ src += current_len; ++ } ++ ++ free_page((unsigned long)data); ++ return ret; ++} ++ ++ ++ ++/* This is the main crypto function - zero-copy edition */ ++static int ++__crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop) ++{ ++ struct scatterlist *src_sg, *dst_sg; ++ struct crypt_op *cop = &kcop->cop; ++ int ret = 0; ++ ++ ret = get_userbuf(ses_ptr, cop->src, cop->len, cop->dst, cop->len, ++ kcop->task, kcop->mm, &src_sg, &dst_sg); ++ if (unlikely(ret)) { ++ derr(1, "Error getting user pages. Falling back to non zero copy."); ++ return __crypto_run_std(ses_ptr, cop); ++ } ++ ++ ret = hash_n_crypt(ses_ptr, cop, src_sg, dst_sg, cop->len); ++ ++ release_user_pages(ses_ptr); ++ return ret; ++} ++ ++int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop) ++{ ++ struct csession *ses_ptr; ++ struct crypt_op *cop = &kcop->cop; ++ int ret; ++ ++ if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) { ++ ddebug(1, "invalid operation op=%u", cop->op); ++ return -EINVAL; ++ } ++ ++ /* this also enters ses_ptr->sem */ ++ ses_ptr = crypto_get_session_by_sid(fcr, cop->ses); ++ if (unlikely(!ses_ptr)) { ++ derr(1, "invalid session ID=0x%08X", cop->ses); ++ return -EINVAL; ++ } ++ ++ if (ses_ptr->hdata.init != 0 && (cop->flags == 0 || cop->flags & COP_FLAG_RESET)) { ++ ret = cryptodev_hash_reset(&ses_ptr->hdata); ++ if (unlikely(ret)) { ++ derr(1, "error in cryptodev_hash_reset()"); ++ goto out_unlock; ++ } ++ } ++ ++ if (ses_ptr->cdata.init != 0) { ++ int blocksize = ses_ptr->cdata.blocksize; ++ ++ if (unlikely(cop->len % blocksize)) { ++ derr(1, "data size (%u) isn't a multiple of block size (%u)", ++ cop->len, blocksize); ++ ret = -EINVAL; ++ goto out_unlock; ++ } ++ ++ cryptodev_cipher_set_iv(&ses_ptr->cdata, kcop->iv, ++ min(ses_ptr->cdata.ivsize, kcop->ivlen)); ++ } ++ ++ if (likely(cop->len)) { ++ if (cop->flags & COP_FLAG_NO_ZC) { ++ if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->src, ses_ptr->alignmask))) { ++ dwarning(2, "source address %p is not %d byte aligned - disabling zero copy", ++ cop->src, ses_ptr->alignmask + 1); ++ cop->flags &= ~COP_FLAG_NO_ZC; ++ } ++ ++ if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->dst, ses_ptr->alignmask))) { ++ dwarning(2, "destination address %p is not %d byte aligned - disabling zero copy", ++ cop->dst, ses_ptr->alignmask + 1); ++ cop->flags &= ~COP_FLAG_NO_ZC; ++ } ++ } ++ ++ if (cop->flags & COP_FLAG_NO_ZC) ++ ret = __crypto_run_std(ses_ptr, &kcop->cop); ++ else ++ ret = __crypto_run_zc(ses_ptr, kcop); ++ if (unlikely(ret)) ++ goto out_unlock; ++ } ++ ++ if (ses_ptr->cdata.init != 0) { ++ cryptodev_cipher_get_iv(&ses_ptr->cdata, kcop->iv, ++ min(ses_ptr->cdata.ivsize, kcop->ivlen)); ++ } ++ ++ if (ses_ptr->hdata.init != 0 && ++ ((cop->flags & COP_FLAG_FINAL) || ++ (!(cop->flags & COP_FLAG_UPDATE) || cop->len == 0))) { ++ ++ ret = cryptodev_hash_final(&ses_ptr->hdata, kcop->hash_output); ++ if (unlikely(ret)) { ++ derr(0, "CryptoAPI failure: %d", ret); ++ goto out_unlock; ++ } ++ kcop->digestsize = ses_ptr->hdata.digestsize; ++ } ++ ++out_unlock: ++ crypto_put_session(ses_ptr); ++ return ret; ++} +diff -Nur linux-3.14.72.orig/crypto/cryptodev/Makefile linux-3.14.72/crypto/cryptodev/Makefile +--- linux-3.14.72.orig/crypto/cryptodev/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/Makefile 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,8 @@ ++ccflags-y := -Icrypto/cryptodev -Iinclude/uapi/linux/ ++obj-$(CONFIG_CRYPTO_CRYPTODEV) += cryptodev.o ++cryptodev-objs := ioctl.o \ ++ main.o \ ++ cryptlib.o \ ++ authenc.o \ ++ zc.o \ ++ util.o +diff -Nur linux-3.14.72.orig/crypto/cryptodev/util.c linux-3.14.72/crypto/cryptodev/util.c +--- linux-3.14.72.orig/crypto/cryptodev/util.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/util.c 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (c) 2011 Maxim Levitsky ++ * ++ * This file is part of linux cryptodev. ++ * ++ * 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 "util.h" ++ ++/* These were taken from Maxim Levitsky's patch to lkml. ++ */ ++struct scatterlist *sg_advance(struct scatterlist *sg, int consumed) ++{ ++ while (consumed >= sg->length) { ++ consumed -= sg->length; ++ ++ sg = sg_next(sg); ++ if (!sg) ++ break; ++ } ++ ++ WARN_ON(!sg && consumed); ++ ++ if (!sg) ++ return NULL; ++ ++ sg->offset += consumed; ++ sg->length -= consumed; ++ ++ if (sg->offset >= PAGE_SIZE) { ++ struct page *page = ++ nth_page(sg_page(sg), sg->offset / PAGE_SIZE); ++ sg_set_page(sg, page, sg->length, sg->offset % PAGE_SIZE); ++ } ++ ++ return sg; ++} ++ ++/** ++ * sg_copy - copies sg entries from sg_from to sg_to, such ++ * as sg_to covers first 'len' bytes from sg_from. ++ */ ++int sg_copy(struct scatterlist *sg_from, struct scatterlist *sg_to, int len) ++{ ++ while (len > sg_from->length) { ++ len -= sg_from->length; ++ ++ sg_set_page(sg_to, sg_page(sg_from), ++ sg_from->length, sg_from->offset); ++ ++ sg_to = sg_next(sg_to); ++ sg_from = sg_next(sg_from); ++ ++ if (len && (!sg_from || !sg_to)) ++ return -ENOMEM; ++ } ++ ++ if (len) ++ sg_set_page(sg_to, sg_page(sg_from), ++ len, sg_from->offset); ++ sg_mark_end(sg_to); ++ return 0; ++} ++ +diff -Nur linux-3.14.72.orig/crypto/cryptodev/util.h linux-3.14.72/crypto/cryptodev/util.h +--- linux-3.14.72.orig/crypto/cryptodev/util.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/util.h 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,2 @@ ++int sg_copy(struct scatterlist *sg_from, struct scatterlist *sg_to, int len); ++struct scatterlist *sg_advance(struct scatterlist *sg, int consumed); +diff -Nur linux-3.14.72.orig/crypto/cryptodev/version.h linux-3.14.72/crypto/cryptodev/version.h +--- linux-3.14.72.orig/crypto/cryptodev/version.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/version.h 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1 @@ ++#define VERSION "1.7" +diff -Nur linux-3.14.72.orig/crypto/cryptodev/zc.c linux-3.14.72/crypto/cryptodev/zc.c +--- linux-3.14.72.orig/crypto/cryptodev/zc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/zc.c 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,208 @@ ++/* ++ * Driver for /dev/crypto device (aka CryptoDev) ++ * ++ * Copyright (c) 2009-2013 Nikos Mavrogiannopoulos ++ * Copyright (c) 2010 Phil Sutter ++ * Copyright (c) 2011, 2012 OpenSSL Software Foundation, Inc. ++ * ++ * This file is part of linux cryptodev. ++ * ++ * 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 "cryptodev_int.h" ++#include "zc.h" ++#include "version.h" ++ ++/* Helper functions to assist zero copy. ++ * This needs to be redesigned and moved out of the session. --nmav ++ */ ++ ++/* offset of buf in it's first page */ ++#define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK) ++ ++/* fetch the pages addr resides in into pg and initialise sg with them */ ++int __get_userbuf(uint8_t __user *addr, uint32_t len, int write, ++ unsigned int pgcount, struct page **pg, struct scatterlist *sg, ++ struct task_struct *task, struct mm_struct *mm) ++{ ++ int ret, pglen, i = 0; ++ struct scatterlist *sgp; ++ ++ if (unlikely(!pgcount || !len || !addr)) { ++ sg_mark_end(sg); ++ return 0; ++ } ++ ++ down_read(&mm->mmap_sem); ++ ret = get_user_pages(task, mm, ++ (unsigned long)addr, pgcount, write, 0, pg, NULL); ++ up_read(&mm->mmap_sem); ++ if (ret != pgcount) ++ return -EINVAL; ++ ++ sg_init_table(sg, pgcount); ++ ++ pglen = min((ptrdiff_t)(PAGE_SIZE - PAGEOFFSET(addr)), (ptrdiff_t)len); ++ sg_set_page(sg, pg[i++], pglen, PAGEOFFSET(addr)); ++ ++ len -= pglen; ++ for (sgp = sg_next(sg); len; sgp = sg_next(sgp)) { ++ pglen = min((uint32_t)PAGE_SIZE, len); ++ sg_set_page(sgp, pg[i++], pglen, 0); ++ len -= pglen; ++ } ++ sg_mark_end(sg_last(sg, pgcount)); ++ return 0; ++} ++ ++int adjust_sg_array(struct csession *ses, int pagecount) ++{ ++ struct scatterlist *sg; ++ struct page **pages; ++ int array_size; ++ ++ for (array_size = ses->array_size; array_size < pagecount; ++ array_size *= 2) ++ ; ++ ddebug(0, "reallocating from %d to %d pages", ++ ses->array_size, array_size); ++ pages = krealloc(ses->pages, array_size * sizeof(struct page *), ++ GFP_KERNEL); ++ if (unlikely(!pages)) ++ return -ENOMEM; ++ ses->pages = pages; ++ sg = krealloc(ses->sg, array_size * sizeof(struct scatterlist), ++ GFP_KERNEL); ++ if (unlikely(!sg)) ++ return -ENOMEM; ++ ses->sg = sg; ++ ses->array_size = array_size; ++ ++ return 0; ++} ++ ++void release_user_pages(struct csession *ses) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ses->used_pages; i++) { ++ if (!PageReserved(ses->pages[i])) ++ SetPageDirty(ses->pages[i]); ++ ++ if (ses->readonly_pages == 0) ++ flush_dcache_page(ses->pages[i]); ++ else ++ ses->readonly_pages--; ++ ++ page_cache_release(ses->pages[i]); ++ } ++ ses->used_pages = 0; ++} ++ ++/* make src and dst available in scatterlists. ++ * dst might be the same as src. ++ */ ++int get_userbuf(struct csession *ses, ++ void *__user src, unsigned int src_len, ++ void *__user dst, unsigned int dst_len, ++ struct task_struct *task, struct mm_struct *mm, ++ struct scatterlist **src_sg, ++ struct scatterlist **dst_sg) ++{ ++ int src_pagecount, dst_pagecount; ++ int rc; ++ ++ /* Empty input is a valid option to many algorithms & is tested by NIST/FIPS */ ++ /* Make sure NULL input has 0 length */ ++ if (!src && src_len) ++ src_len = 0; ++ ++ /* I don't know that null output is ever useful, but we can handle it gracefully */ ++ /* Make sure NULL output has 0 length */ ++ if (!dst && dst_len) ++ dst_len = 0; ++ ++ src_pagecount = PAGECOUNT(src, src_len); ++ dst_pagecount = PAGECOUNT(dst, dst_len); ++ ++ ses->used_pages = (src == dst) ? max(src_pagecount, dst_pagecount) ++ : src_pagecount + dst_pagecount; ++ ++ ses->readonly_pages = (src == dst) ? 0 : src_pagecount; ++ ++ if (ses->used_pages > ses->array_size) { ++ rc = adjust_sg_array(ses, ses->used_pages); ++ if (rc) ++ return rc; ++ } ++ ++ if (src == dst) { /* inplace operation */ ++ /* When we encrypt for authenc modes we need to write ++ * more data than the ones we read. */ ++ if (src_len < dst_len) ++ src_len = dst_len; ++ rc = __get_userbuf(src, src_len, 1, ses->used_pages, ++ ses->pages, ses->sg, task, mm); ++ if (unlikely(rc)) { ++ derr(1, "failed to get user pages for data IO"); ++ return rc; ++ } ++ (*src_sg) = (*dst_sg) = ses->sg; ++ return 0; ++ } ++ ++ *src_sg = NULL; /* default to no input */ ++ *dst_sg = NULL; /* default to ignore output */ ++ ++ if (likely(src)) { ++ rc = __get_userbuf(src, src_len, 0, ses->readonly_pages, ++ ses->pages, ses->sg, task, mm); ++ if (unlikely(rc)) { ++ derr(1, "failed to get user pages for data input"); ++ return rc; ++ } ++ *src_sg = ses->sg; ++ } ++ ++ if (likely(dst)) { ++ const unsigned int writable_pages = ++ ses->used_pages - ses->readonly_pages; ++ struct page **dst_pages = ses->pages + ses->readonly_pages; ++ *dst_sg = ses->sg + ses->readonly_pages; ++ ++ rc = __get_userbuf(dst, dst_len, 1, writable_pages, ++ dst_pages, *dst_sg, task, mm); ++ if (unlikely(rc)) { ++ derr(1, "failed to get user pages for data output"); ++ release_user_pages(ses); /* FIXME: use __release_userbuf(src, ...) */ ++ return rc; ++ } ++ } ++ return 0; ++} ++ +diff -Nur linux-3.14.72.orig/crypto/cryptodev/zc.h linux-3.14.72/crypto/cryptodev/zc.h +--- linux-3.14.72.orig/crypto/cryptodev/zc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/crypto/cryptodev/zc.h 2016-06-19 22:11:55.069155494 +0200 +@@ -0,0 +1,27 @@ ++#ifndef ZC_H ++# define ZC_H ++ ++#include "cryptodev_int.h" ++ ++/* For zero copy */ ++int __get_userbuf(uint8_t __user *addr, uint32_t len, int write, ++ unsigned int pgcount, struct page **pg, struct scatterlist *sg, ++ struct task_struct *task, struct mm_struct *mm); ++void release_user_pages(struct csession *ses); ++ ++int get_userbuf(struct csession *ses, ++ void *__user src, unsigned int src_len, ++ void *__user dst, unsigned int dst_len, ++ struct task_struct *task, struct mm_struct *mm, ++ struct scatterlist **src_sg, ++ struct scatterlist **dst_sg); ++ ++/* buflen ? (last page - first page + 1) : 0 */ ++#define PAGECOUNT(buf, buflen) ((buflen) \ ++ ? ((((unsigned long)(buf + buflen - 1)) >> PAGE_SHIFT) - \ ++ (((unsigned long)(buf )) >> PAGE_SHIFT) + 1) \ ++ : 0) ++ ++#define DEFAULT_PREALLOC_PAGES 32 ++ ++#endif +diff -Nur linux-3.14.72.orig/crypto/Kconfig linux-3.14.72/crypto/Kconfig +--- linux-3.14.72.orig/crypto/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/crypto/Kconfig 2016-06-19 22:11:55.069155494 +0200 +@@ -86,6 +86,13 @@ + tristate + select CRYPTO_ALGAPI2 + ++config CRYPTO_CRYPTODEV ++ tristate "Cryptodev (/dev/crypto) interface" ++ depends on CRYPTO ++ help ++ Device /dev/crypto gives userspace programs access to ++ kernel crypto algorithms. ++ + config CRYPTO_MANAGER + tristate "Cryptographic algorithm manager" + select CRYPTO_MANAGER2 +diff -Nur linux-3.14.72.orig/crypto/Makefile linux-3.14.72/crypto/Makefile +--- linux-3.14.72.orig/crypto/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/crypto/Makefile 2016-06-19 22:11:55.069155494 +0200 +@@ -30,6 +30,7 @@ + + cryptomgr-y := algboss.o testmgr.o + ++obj-$(CONFIG_CRYPTO_CRYPTODEV) += cryptodev/ + obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o + obj-$(CONFIG_CRYPTO_USER) += crypto_user.o + obj-$(CONFIG_CRYPTO_CMAC) += cmac.o +diff -Nur linux-3.14.72.orig/crypto/tcrypt.c linux-3.14.72/crypto/tcrypt.c +--- linux-3.14.72.orig/crypto/tcrypt.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/crypto/tcrypt.c 2016-06-19 22:11:55.069155494 +0200 +@@ -917,21 +917,28 @@ + struct tcrypt_result tresult; + struct ahash_request *req; + struct crypto_ahash *tfm; +- static char output[1024]; ++ const int output_size = 1024; ++ char *output = kmalloc(output_size, GFP_KERNEL); + int i, ret; + ++ if (!output) { ++ printk(KERN_INFO "\nUnable to allocate output buffer memory\n"); ++ return; ++ } ++ + printk(KERN_INFO "\ntesting speed of async %s\n", algo); + + tfm = crypto_alloc_ahash(algo, 0, 0); + if (IS_ERR(tfm)) { + pr_err("failed to load transform for %s: %ld\n", + algo, PTR_ERR(tfm)); ++ kfree(output); + return; + } + +- if (crypto_ahash_digestsize(tfm) > sizeof(output)) { ++ if (crypto_ahash_digestsize(tfm) > output_size) { + pr_err("digestsize(%u) > outputbuffer(%zu)\n", +- crypto_ahash_digestsize(tfm), sizeof(output)); ++ crypto_ahash_digestsize(tfm), output_size); + goto out; + } + +@@ -975,6 +982,7 @@ + ahash_request_free(req); + + out: ++ kfree(output); + crypto_free_ahash(tfm); + } + +diff -Nur linux-3.14.72.orig/crypto/testmgr.c linux-3.14.72/crypto/testmgr.c +--- linux-3.14.72.orig/crypto/testmgr.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/crypto/testmgr.c 2016-06-19 22:11:55.069155494 +0200 +@@ -191,13 +191,20 @@ + const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); + unsigned int i, j, k, temp; + struct scatterlist sg[8]; +- char result[64]; ++ char *result; ++ char *key; + struct ahash_request *req; + struct tcrypt_result tresult; + void *hash_buff; + char *xbuf[XBUFSIZE]; + int ret = -ENOMEM; + ++ result = kmalloc(MAX_DIGEST_SIZE, GFP_KERNEL); ++ if (!result) ++ return ret; ++ key = kmalloc(MAX_KEYLEN, GFP_KERNEL); ++ if (!key) ++ goto out_nobuf; + if (testmgr_alloc_buf(xbuf)) + goto out_nobuf; + +@@ -222,7 +229,7 @@ + goto out; + + j++; +- memset(result, 0, 64); ++ memset(result, 0, MAX_DIGEST_SIZE); + + hash_buff = xbuf[0]; + hash_buff += align_offset; +@@ -232,8 +239,14 @@ + + if (template[i].ksize) { + crypto_ahash_clear_flags(tfm, ~0); +- ret = crypto_ahash_setkey(tfm, template[i].key, +- template[i].ksize); ++ if (template[i].ksize > MAX_KEYLEN) { ++ pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", ++ j, algo, template[i].ksize, MAX_KEYLEN); ++ ret = -EINVAL; ++ goto out; ++ } ++ memcpy(key, template[i].key, template[i].ksize); ++ ret = crypto_ahash_setkey(tfm, key, template[i].ksize); + if (ret) { + printk(KERN_ERR "alg: hash: setkey failed on " + "test %d for %s: ret=%d\n", j, algo, +@@ -293,7 +306,7 @@ + + if (template[i].np) { + j++; +- memset(result, 0, 64); ++ memset(result, 0, MAX_DIGEST_SIZE); + + temp = 0; + sg_init_table(sg, template[i].np); +@@ -312,8 +325,16 @@ + } + + if (template[i].ksize) { ++ if (template[i].ksize > MAX_KEYLEN) { ++ pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", ++ j, algo, template[i].ksize, ++ MAX_KEYLEN); ++ ret = -EINVAL; ++ goto out; ++ } + crypto_ahash_clear_flags(tfm, ~0); +- ret = crypto_ahash_setkey(tfm, template[i].key, ++ memcpy(key, template[i].key, template[i].ksize); ++ ret = crypto_ahash_setkey(tfm, key, + template[i].ksize); + + if (ret) { +@@ -365,6 +386,8 @@ + out_noreq: + testmgr_free_buf(xbuf); + out_nobuf: ++ kfree(key); ++ kfree(result); + return ret; + } + +@@ -414,16 +437,21 @@ + void *input; + void *output; + void *assoc; +- char iv[MAX_IVLEN]; ++ char *iv; + char *xbuf[XBUFSIZE]; + char *xoutbuf[XBUFSIZE]; + char *axbuf[XBUFSIZE]; + ++ iv = kzalloc(MAX_IVLEN, GFP_KERNEL); ++ if (!iv) ++ return ret; ++ key = kmalloc(MAX_KEYLEN, GFP_KERNEL); ++ if (!key) ++ goto out_noxbuf; + if (testmgr_alloc_buf(xbuf)) + goto out_noxbuf; + if (testmgr_alloc_buf(axbuf)) + goto out_noaxbuf; +- + if (diff_dst && testmgr_alloc_buf(xoutbuf)) + goto out_nooutbuf; + +@@ -484,7 +512,14 @@ + crypto_aead_set_flags( + tfm, CRYPTO_TFM_REQ_WEAK_KEY); + +- key = template[i].key; ++ if (template[i].klen > MAX_KEYLEN) { ++ pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", ++ d, j, algo, template[i].klen, ++ MAX_KEYLEN); ++ ret = -EINVAL; ++ goto out; ++ } ++ memcpy(key, template[i].key, template[i].klen); + + ret = crypto_aead_setkey(tfm, key, + template[i].klen); +@@ -585,7 +620,14 @@ + if (template[i].wk) + crypto_aead_set_flags( + tfm, CRYPTO_TFM_REQ_WEAK_KEY); +- key = template[i].key; ++ if (template[i].klen > MAX_KEYLEN) { ++ pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", ++ d, j, algo, template[i].klen, ++ MAX_KEYLEN); ++ ret = -EINVAL; ++ goto out; ++ } ++ memcpy(key, template[i].key, template[i].klen); + + ret = crypto_aead_setkey(tfm, key, template[i].klen); + if (!ret == template[i].fail) { +@@ -767,6 +809,8 @@ + out_noaxbuf: + testmgr_free_buf(xbuf); + out_noxbuf: ++ kfree(key); ++ kfree(iv); + return ret; + } + +@@ -1809,6 +1853,18 @@ + } + } + }, { ++ .alg = "authenc(hmac(md5),cbc(aes))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_md5_aes_cbc_enc_tv_template, ++ .count = HMAC_MD5_AES_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { + .alg = "authenc(hmac(sha1),cbc(aes))", + .test = alg_test_aead, + .fips_allowed = 1, +@@ -1821,6 +1877,54 @@ + } + } + }, { ++ .alg = "authenc(hmac(sha1),cbc(des))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha1_des_cbc_enc_tv_template, ++ .count = HMAC_SHA1_DES_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { ++ .alg = "authenc(hmac(sha1),cbc(des3_ede))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha1_des3_ede_cbc_enc_tv_template, ++ .count = HMAC_SHA1_DES3_EDE_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { ++ .alg = "authenc(hmac(sha224),cbc(des))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha224_des_cbc_enc_tv_template, ++ .count = HMAC_SHA224_DES_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { ++ .alg = "authenc(hmac(sha224),cbc(des3_ede))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha224_des3_ede_cbc_enc_tv_template, ++ .count = HMAC_SHA224_DES3_EDE_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { + .alg = "authenc(hmac(sha256),cbc(aes))", + .test = alg_test_aead, + .fips_allowed = 1, +@@ -1833,6 +1937,54 @@ + } + } + }, { ++ .alg = "authenc(hmac(sha256),cbc(des))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha256_des_cbc_enc_tv_template, ++ .count = HMAC_SHA256_DES_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { ++ .alg = "authenc(hmac(sha256),cbc(des3_ede))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha256_des3_ede_cbc_enc_tv_template, ++ .count = HMAC_SHA256_DES3_EDE_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { ++ .alg = "authenc(hmac(sha384),cbc(des))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha384_des_cbc_enc_tv_template, ++ .count = HMAC_SHA384_DES_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { ++ .alg = "authenc(hmac(sha384),cbc(des3_ede))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha384_des3_ede_cbc_enc_tv_template, ++ .count = HMAC_SHA384_DES3_EDE_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { + .alg = "authenc(hmac(sha512),cbc(aes))", + .test = alg_test_aead, + .fips_allowed = 1, +@@ -1845,6 +1997,30 @@ + } + } + }, { ++ .alg = "authenc(hmac(sha512),cbc(des))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha512_des_cbc_enc_tv_template, ++ .count = HMAC_SHA512_DES_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { ++ .alg = "authenc(hmac(sha512),cbc(des3_ede))", ++ .test = alg_test_aead, ++ .fips_allowed = 1, ++ .suite = { ++ .aead = { ++ .enc = { ++ .vecs = hmac_sha512_des3_ede_cbc_enc_tv_template, ++ .count = HMAC_SHA512_DES3_EDE_CBC_ENC_TEST_VECTORS ++ } ++ } ++ } ++ }, { + .alg = "cbc(aes)", + .test = alg_test_skcipher, + .fips_allowed = 1, +diff -Nur linux-3.14.72.orig/crypto/testmgr.h linux-3.14.72/crypto/testmgr.h +--- linux-3.14.72.orig/crypto/testmgr.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/crypto/testmgr.h 2016-06-19 22:11:55.073155238 +0200 +@@ -32,7 +32,7 @@ + #define MAX_DIGEST_SIZE 64 + #define MAX_TAP 8 + +-#define MAX_KEYLEN 56 ++#define MAX_KEYLEN 160 + #define MAX_IVLEN 32 + + struct hash_testvec { +@@ -94,6 +94,684 @@ + + static char zeroed_string[48]; + ++#define HMAC_MD5_AES_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_md5_aes_cbc_enc_tv_template[] = { ++ { ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x10" /* enc key length */ ++ "\x00\x00\x00\x00\x00\x00\x00\x00" ++ "\x00\x00\x00\x00\x00\x00\x00\x00" ++ "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" ++ "\x51\x2e\x03\xd5\x34\x12\x00\x06", ++ .klen = 8 + 16 + 16, ++ .iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30" ++ "\xb4\x22\xda\x80\x2c\x9f\xac\x41", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "Single block msg", ++ .ilen = 16, ++ .result = "\xe3\x53\x77\x9c\x10\x79\xae\xb8" ++ "\x27\x08\x94\x2d\xbe\x77\x18\x1a" ++ "\x76\xa8\x43\x89\xbd\xfe\xf9\x79" ++ "\x96\x64\x77\x02\x95\x21\x08\x4c", ++ .rlen = 16 + 16, ++ }, ++}; ++ ++#define HMAC_SHA1_DES_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha1_des_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x08" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24", ++ .klen = 8 + 20 + 8, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x70\xd6\xde\x64\x87\x17\xf1\xe8" ++ "\x54\x31\x85\x37\xed\x6b\x01\x8d" ++ "\xe3\xcc\xe0\x1d\x5e\xf3\xfe\xf1" ++ "\x41\xaa\x33\x91\xa7\x7d\x99\x88" ++ "\x4d\x85\x6e\x2f\xa3\x69\xf5\x82" ++ "\x3a\x6f\x25\xcb\x7d\x58\x1f\x9b" ++ "\xaa\x9c\x11\xd5\x76\x67\xce\xde" ++ "\x56\xd7\x5a\x80\x69\xea\x3a\x02" ++ "\xf0\xc7\x7c\xe3\xcb\x40\xe5\x52" ++ "\xd1\x10\x92\x78\x0b\x8e\x5b\xf1" ++ "\xe3\x26\x1f\xe1\x15\x41\xc7\xba" ++ "\x99\xdb\x08\x51\x1c\xd3\x01\xf4" ++ "\x87\x47\x39\xb8\xd2\xdd\xbd\xfb" ++ "\x66\x13\xdf\x1c\x01\x44\xf0\x7a" ++ "\x1a\x6b\x13\xf5\xd5\x0b\xb8\xba" ++ "\x53\xba\xe1\x76\xe3\x82\x07\x86" ++ "\x95\x16\x20\x09\xf5\x95\x19\xfd" ++ "\x3c\xc7\xe0\x42\xc0\x14\x69\xfa" ++ "\x5c\x44\xa9\x37", ++ .rlen = 128 + 20, ++ }, ++}; ++ ++#define HMAC_SHA224_DES_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha224_des_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x08" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24", ++ .klen = 8 + 24 + 8, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x70\xd6\xde\x64\x87\x17\xf1\xe8" ++ "\x54\x31\x85\x37\xed\x6b\x01\x8d" ++ "\xe3\xcc\xe0\x1d\x5e\xf3\xfe\xf1" ++ "\x41\xaa\x33\x91\xa7\x7d\x99\x88" ++ "\x4d\x85\x6e\x2f\xa3\x69\xf5\x82" ++ "\x3a\x6f\x25\xcb\x7d\x58\x1f\x9b" ++ "\xaa\x9c\x11\xd5\x76\x67\xce\xde" ++ "\x56\xd7\x5a\x80\x69\xea\x3a\x02" ++ "\xf0\xc7\x7c\xe3\xcb\x40\xe5\x52" ++ "\xd1\x10\x92\x78\x0b\x8e\x5b\xf1" ++ "\xe3\x26\x1f\xe1\x15\x41\xc7\xba" ++ "\x99\xdb\x08\x51\x1c\xd3\x01\xf4" ++ "\x87\x47\x39\xb8\xd2\xdd\xbd\xfb" ++ "\x66\x13\xdf\x1c\x01\x44\xf0\x7a" ++ "\x1a\x6b\x13\xf5\xd5\x0b\xb8\xba" ++ "\x53\xba\xe1\x76\xe3\x82\x07\x86" ++ "\x9c\x2d\x7e\xee\x20\x34\x55\x0a" ++ "\xce\xb5\x4e\x64\x53\xe7\xbf\x91" ++ "\xab\xd4\xd9\xda\xc9\x12\xae\xf7", ++ .rlen = 128 + 24, ++ }, ++}; ++ ++#define HMAC_SHA256_DES_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha256_des_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x08" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24", ++ .klen = 8 + 32 + 8, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x70\xd6\xde\x64\x87\x17\xf1\xe8" ++ "\x54\x31\x85\x37\xed\x6b\x01\x8d" ++ "\xe3\xcc\xe0\x1d\x5e\xf3\xfe\xf1" ++ "\x41\xaa\x33\x91\xa7\x7d\x99\x88" ++ "\x4d\x85\x6e\x2f\xa3\x69\xf5\x82" ++ "\x3a\x6f\x25\xcb\x7d\x58\x1f\x9b" ++ "\xaa\x9c\x11\xd5\x76\x67\xce\xde" ++ "\x56\xd7\x5a\x80\x69\xea\x3a\x02" ++ "\xf0\xc7\x7c\xe3\xcb\x40\xe5\x52" ++ "\xd1\x10\x92\x78\x0b\x8e\x5b\xf1" ++ "\xe3\x26\x1f\xe1\x15\x41\xc7\xba" ++ "\x99\xdb\x08\x51\x1c\xd3\x01\xf4" ++ "\x87\x47\x39\xb8\xd2\xdd\xbd\xfb" ++ "\x66\x13\xdf\x1c\x01\x44\xf0\x7a" ++ "\x1a\x6b\x13\xf5\xd5\x0b\xb8\xba" ++ "\x53\xba\xe1\x76\xe3\x82\x07\x86" ++ "\xc6\x58\xa1\x60\x70\x91\x39\x36" ++ "\x50\xf6\x5d\xab\x4b\x51\x4e\x5e" ++ "\xde\x63\xde\x76\x52\xde\x9f\xba" ++ "\x90\xcf\x15\xf2\xbb\x6e\x84\x00", ++ .rlen = 128 + 32, ++ }, ++}; ++ ++#define HMAC_SHA384_DES_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha384_des_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x08" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" ++ "\x33\x44\x55\x66\x77\x88\x99\xaa" ++ "\xbb\xcc\xdd\xee\xff\x11\x22\x33" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24", ++ .klen = 8 + 48 + 8, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x70\xd6\xde\x64\x87\x17\xf1\xe8" ++ "\x54\x31\x85\x37\xed\x6b\x01\x8d" ++ "\xe3\xcc\xe0\x1d\x5e\xf3\xfe\xf1" ++ "\x41\xaa\x33\x91\xa7\x7d\x99\x88" ++ "\x4d\x85\x6e\x2f\xa3\x69\xf5\x82" ++ "\x3a\x6f\x25\xcb\x7d\x58\x1f\x9b" ++ "\xaa\x9c\x11\xd5\x76\x67\xce\xde" ++ "\x56\xd7\x5a\x80\x69\xea\x3a\x02" ++ "\xf0\xc7\x7c\xe3\xcb\x40\xe5\x52" ++ "\xd1\x10\x92\x78\x0b\x8e\x5b\xf1" ++ "\xe3\x26\x1f\xe1\x15\x41\xc7\xba" ++ "\x99\xdb\x08\x51\x1c\xd3\x01\xf4" ++ "\x87\x47\x39\xb8\xd2\xdd\xbd\xfb" ++ "\x66\x13\xdf\x1c\x01\x44\xf0\x7a" ++ "\x1a\x6b\x13\xf5\xd5\x0b\xb8\xba" ++ "\x53\xba\xe1\x76\xe3\x82\x07\x86" ++ "\xa8\x8e\x9c\x74\x8c\x2b\x99\xa0" ++ "\xc8\x8c\xef\x25\x07\x83\x11\x3a" ++ "\x31\x8d\xbe\x3b\x6a\xd7\x96\xfe" ++ "\x5e\x67\xb5\x74\xe7\xe7\x85\x61" ++ "\x6a\x95\x26\x75\xcc\x53\x89\xf3" ++ "\x74\xc9\x2a\x76\x20\xa2\x64\x62", ++ .rlen = 128 + 48, ++ }, ++}; ++ ++#define HMAC_SHA512_DES_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha512_des_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x08" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" ++ "\x33\x44\x55\x66\x77\x88\x99\xaa" ++ "\xbb\xcc\xdd\xee\xff\x11\x22\x33" ++ "\x44\x55\x66\x77\x88\x99\xaa\xbb" ++ "\xcc\xdd\xee\xff\x11\x22\x33\x44" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24", ++ .klen = 8 + 64 + 8, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x70\xd6\xde\x64\x87\x17\xf1\xe8" ++ "\x54\x31\x85\x37\xed\x6b\x01\x8d" ++ "\xe3\xcc\xe0\x1d\x5e\xf3\xfe\xf1" ++ "\x41\xaa\x33\x91\xa7\x7d\x99\x88" ++ "\x4d\x85\x6e\x2f\xa3\x69\xf5\x82" ++ "\x3a\x6f\x25\xcb\x7d\x58\x1f\x9b" ++ "\xaa\x9c\x11\xd5\x76\x67\xce\xde" ++ "\x56\xd7\x5a\x80\x69\xea\x3a\x02" ++ "\xf0\xc7\x7c\xe3\xcb\x40\xe5\x52" ++ "\xd1\x10\x92\x78\x0b\x8e\x5b\xf1" ++ "\xe3\x26\x1f\xe1\x15\x41\xc7\xba" ++ "\x99\xdb\x08\x51\x1c\xd3\x01\xf4" ++ "\x87\x47\x39\xb8\xd2\xdd\xbd\xfb" ++ "\x66\x13\xdf\x1c\x01\x44\xf0\x7a" ++ "\x1a\x6b\x13\xf5\xd5\x0b\xb8\xba" ++ "\x53\xba\xe1\x76\xe3\x82\x07\x86" ++ "\xc6\x2c\x73\x88\xb0\x9d\x5f\x3e" ++ "\x5b\x78\xca\x0e\xab\x8a\xa3\xbb" ++ "\xd9\x1d\xc3\xe3\x05\xac\x76\xfb" ++ "\x58\x83\xda\x67\xfb\x21\x24\xa2" ++ "\xb1\xa7\xd7\x66\xa6\x8d\xa6\x93" ++ "\x97\xe2\xe3\xb8\xaa\x48\x85\xee" ++ "\x8c\xf6\x07\x95\x1f\xa6\x6c\x96" ++ "\x99\xc7\x5c\x8d\xd8\xb5\x68\x7b", ++ .rlen = 128 + 64, ++ }, ++}; ++ ++ ++#define HMAC_SHA1_DES3_EDE_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha1_des3_ede_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x18" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24" ++ "\x44\x4D\x99\x5A\x12\xD6\x40\xC0" ++ "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8", ++ .klen = 8 + 20 + 24, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4" ++ "\x67\x17\x21\xc7\x6e\x8a\xd5\x49" ++ "\x74\xb3\x49\x05\xc5\x1c\xd0\xed" ++ "\x12\x56\x5c\x53\x96\xb6\x00\x7d" ++ "\x90\x48\xfc\xf5\x8d\x29\x39\xcc" ++ "\x8a\xd5\x35\x18\x36\x23\x4e\xd7" ++ "\x76\xd1\xda\x0c\x94\x67\xbb\x04" ++ "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea" ++ "\x22\x64\x47\xaa\x8f\x75\x13\xbf" ++ "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a" ++ "\x71\x63\x2e\x89\x7b\x1e\x12\xca" ++ "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a" ++ "\xd6\xf9\x21\x31\x62\x44\x45\xa6" ++ "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc" ++ "\x9d\xde\xa5\x70\xe9\x42\x45\x8a" ++ "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19" ++ "\x67\x6d\xb1\xf5\xb8\x10\xdc\xc6" ++ "\x75\x86\x96\x6b\xb1\xc5\xe4\xcf" ++ "\xd1\x60\x91\xb3", ++ .rlen = 128 + 20, ++ }, ++}; ++ ++#define HMAC_SHA224_DES3_EDE_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha224_des3_ede_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x18" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24" ++ "\x44\x4D\x99\x5A\x12\xD6\x40\xC0" ++ "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8", ++ .klen = 8 + 24 + 24, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4" ++ "\x67\x17\x21\xc7\x6e\x8a\xd5\x49" ++ "\x74\xb3\x49\x05\xc5\x1c\xd0\xed" ++ "\x12\x56\x5c\x53\x96\xb6\x00\x7d" ++ "\x90\x48\xfc\xf5\x8d\x29\x39\xcc" ++ "\x8a\xd5\x35\x18\x36\x23\x4e\xd7" ++ "\x76\xd1\xda\x0c\x94\x67\xbb\x04" ++ "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea" ++ "\x22\x64\x47\xaa\x8f\x75\x13\xbf" ++ "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a" ++ "\x71\x63\x2e\x89\x7b\x1e\x12\xca" ++ "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a" ++ "\xd6\xf9\x21\x31\x62\x44\x45\xa6" ++ "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc" ++ "\x9d\xde\xa5\x70\xe9\x42\x45\x8a" ++ "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19" ++ "\x15\x24\x7f\x5a\x45\x4a\x66\xce" ++ "\x2b\x0b\x93\x99\x2f\x9d\x0c\x6c" ++ "\x56\x1f\xe1\xa6\x41\xb2\x4c\xd0", ++ .rlen = 128 + 24, ++ }, ++}; ++ ++#define HMAC_SHA256_DES3_EDE_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha256_des3_ede_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x18" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24" ++ "\x44\x4D\x99\x5A\x12\xD6\x40\xC0" ++ "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8", ++ .klen = 8 + 32 + 24, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4" ++ "\x67\x17\x21\xc7\x6e\x8a\xd5\x49" ++ "\x74\xb3\x49\x05\xc5\x1c\xd0\xed" ++ "\x12\x56\x5c\x53\x96\xb6\x00\x7d" ++ "\x90\x48\xfc\xf5\x8d\x29\x39\xcc" ++ "\x8a\xd5\x35\x18\x36\x23\x4e\xd7" ++ "\x76\xd1\xda\x0c\x94\x67\xbb\x04" ++ "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea" ++ "\x22\x64\x47\xaa\x8f\x75\x13\xbf" ++ "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a" ++ "\x71\x63\x2e\x89\x7b\x1e\x12\xca" ++ "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a" ++ "\xd6\xf9\x21\x31\x62\x44\x45\xa6" ++ "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc" ++ "\x9d\xde\xa5\x70\xe9\x42\x45\x8a" ++ "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19" ++ "\x73\xb0\xea\x9f\xe8\x18\x80\xd6" ++ "\x56\x38\x44\xc0\xdb\xe3\x4f\x71" ++ "\xf7\xce\xd1\xd3\xf8\xbd\x3e\x4f" ++ "\xca\x43\x95\xdf\x80\x61\x81\xa9", ++ .rlen = 128 + 32, ++ }, ++}; ++ ++#define HMAC_SHA384_DES3_EDE_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha384_des3_ede_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x18" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" ++ "\x33\x44\x55\x66\x77\x88\x99\xaa" ++ "\xbb\xcc\xdd\xee\xff\x11\x22\x33" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24" ++ "\x44\x4D\x99\x5A\x12\xD6\x40\xC0" ++ "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8", ++ .klen = 8 + 48 + 24, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4" ++ "\x67\x17\x21\xc7\x6e\x8a\xd5\x49" ++ "\x74\xb3\x49\x05\xc5\x1c\xd0\xed" ++ "\x12\x56\x5c\x53\x96\xb6\x00\x7d" ++ "\x90\x48\xfc\xf5\x8d\x29\x39\xcc" ++ "\x8a\xd5\x35\x18\x36\x23\x4e\xd7" ++ "\x76\xd1\xda\x0c\x94\x67\xbb\x04" ++ "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea" ++ "\x22\x64\x47\xaa\x8f\x75\x13\xbf" ++ "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a" ++ "\x71\x63\x2e\x89\x7b\x1e\x12\xca" ++ "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a" ++ "\xd6\xf9\x21\x31\x62\x44\x45\xa6" ++ "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc" ++ "\x9d\xde\xa5\x70\xe9\x42\x45\x8a" ++ "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19" ++ "\x6d\x77\xfc\x80\x9d\x8a\x9c\xb7" ++ "\x70\xe7\x93\xbf\x73\xe6\x9f\x83" ++ "\x99\x62\x23\xe6\x5b\xd0\xda\x18" ++ "\xa4\x32\x8a\x0b\x46\xd7\xf0\x39" ++ "\x36\x5d\x13\x2f\x86\x10\x78\xd6" ++ "\xd6\xbe\x5c\xb9\x15\x89\xf9\x1b", ++ .rlen = 128 + 48, ++ }, ++}; ++ ++#define HMAC_SHA512_DES3_EDE_CBC_ENC_TEST_VECTORS 1 ++ ++static struct aead_testvec hmac_sha512_des3_ede_cbc_enc_tv_template[] = { ++ { /*Generated with cryptopp*/ ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x18" /* enc key length */ ++ "\x11\x22\x33\x44\x55\x66\x77\x88" ++ "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" ++ "\x22\x33\x44\x55\x66\x77\x88\x99" ++ "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" ++ "\x33\x44\x55\x66\x77\x88\x99\xaa" ++ "\xbb\xcc\xdd\xee\xff\x11\x22\x33" ++ "\x44\x55\x66\x77\x88\x99\xaa\xbb" ++ "\xcc\xdd\xee\xff\x11\x22\x33\x44" ++ "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24" ++ "\x44\x4D\x99\x5A\x12\xD6\x40\xC0" ++ "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8", ++ .klen = 8 + 64 + 24, ++ .iv = "\x7D\x33\x88\x93\x0F\x93\xB2\x42", ++ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01", ++ .alen = 8, ++ .input = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e" ++ "\x53\x20\x63\x65\x65\x72\x73\x74" ++ "\x54\x20\x6f\x6f\x4d\x20\x6e\x61" ++ "\x20\x79\x65\x53\x72\x63\x74\x65" ++ "\x20\x73\x6f\x54\x20\x6f\x61\x4d" ++ "\x79\x6e\x53\x20\x63\x65\x65\x72" ++ "\x73\x74\x54\x20\x6f\x6f\x4d\x20" ++ "\x6e\x61\x20\x79\x65\x53\x72\x63" ++ "\x74\x65\x20\x73\x6f\x54\x20\x6f" ++ "\x61\x4d\x79\x6e\x53\x20\x63\x65" ++ "\x65\x72\x73\x74\x54\x20\x6f\x6f" ++ "\x4d\x20\x6e\x61\x20\x79\x65\x53" ++ "\x72\x63\x74\x65\x20\x73\x6f\x54" ++ "\x20\x6f\x61\x4d\x79\x6e\x53\x20" ++ "\x63\x65\x65\x72\x73\x74\x54\x20" ++ "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79", ++ .ilen = 128, ++ .result = "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4" ++ "\x67\x17\x21\xc7\x6e\x8a\xd5\x49" ++ "\x74\xb3\x49\x05\xc5\x1c\xd0\xed" ++ "\x12\x56\x5c\x53\x96\xb6\x00\x7d" ++ "\x90\x48\xfc\xf5\x8d\x29\x39\xcc" ++ "\x8a\xd5\x35\x18\x36\x23\x4e\xd7" ++ "\x76\xd1\xda\x0c\x94\x67\xbb\x04" ++ "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea" ++ "\x22\x64\x47\xaa\x8f\x75\x13\xbf" ++ "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a" ++ "\x71\x63\x2e\x89\x7b\x1e\x12\xca" ++ "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a" ++ "\xd6\xf9\x21\x31\x62\x44\x45\xa6" ++ "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc" ++ "\x9d\xde\xa5\x70\xe9\x42\x45\x8a" ++ "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19" ++ "\x41\xb5\x1f\xbb\xbd\x4e\xb8\x32" ++ "\x22\x86\x4e\x57\x1b\x2a\xd8\x6e" ++ "\xa9\xfb\xc8\xf3\xbf\x2d\xae\x2b" ++ "\x3b\xbc\x41\xe8\x38\xbb\xf1\x60" ++ "\x4c\x68\xa9\x4e\x8c\x73\xa7\xc0" ++ "\x2a\x74\xd4\x65\x12\xcb\x55\xf2" ++ "\xd5\x02\x6d\xe6\xaf\xc9\x2f\xf2" ++ "\x57\xaa\x85\xf7\xf3\x6a\xcb\xdb", ++ .rlen = 128 + 64, ++ }, ++}; ++ + /* + * MD4 test vectors from RFC1320 + */ +diff -Nur linux-3.14.72.orig/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg linux-3.14.72/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg +--- linux-3.14.72.orig/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg 2016-06-19 22:11:55.073155238 +0200 +@@ -0,0 +1,56 @@ ++What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req ++Date: Feb 2014 ++Contact: Li Jun ++Description: ++ Can be set and read. ++ Set a_bus_req(A-device bus request) input to be 1 if ++ the application running on the A-device wants to use the bus, ++ and to be 0 when the application no longer wants to use ++ the bus(or wants to work as peripheral). a_bus_req can also ++ be set to 1 by kernel in response to remote wakeup signaling ++ from the B-device, the A-device should decide to resume the bus. ++ ++ Valid values are "1" and "0". ++ ++ Reading: returns 1 if the application running on the A-device ++ is using the bus as host role, otherwise 0. ++ ++What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop ++Date: Feb 2014 ++Contact: Li Jun ++Description: ++ Can be set and read ++ The a_bus_drop(A-device bus drop) input is 1 when the ++ application running on the A-device wants to power down ++ the bus, and is 0 otherwise, When a_bus_drop is 1, then ++ the a_bus_req shall be 0. ++ ++ Valid values are "1" and "0". ++ ++ Reading: returns 1 if the bus is off(vbus is turned off) by ++ A-device, otherwise 0. ++ ++What: /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req ++Date: Feb 2014 ++Contact: Li Jun ++Description: ++ Can be set and read. ++ The b_bus_req(B-device bus request) input is 1 during the time ++ that the application running on the B-device wants to use the ++ bus as host, and is 0 when the application no longer wants to ++ work as host and decides to switch back to be peripheral. ++ ++ Valid values are "1" and "0". ++ ++ Reading: returns if the application running on the B device ++ is using the bus as host role, otherwise 0. ++ ++What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_clr_err ++Date: Feb 2014 ++Contact: Li Jun ++Description: ++ Only can be set. ++ The a_clr_err(A-device Vbus error clear) input is used to clear ++ vbus error, then A-device will power down the bus. ++ ++ Valid value is "1" +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt linux-3.14.72/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -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.72.orig/Documentation/devicetree/bindings/arm/l2cc.txt linux-3.14.72/Documentation/devicetree/bindings/arm/l2cc.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/arm/l2cc.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/arm/l2cc.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -40,6 +40,8 @@ + - arm,filter-ranges : Starting address and length of window to + filter. Addresses in the filter window are directed to the M1 port. Other + addresses will go to the M0 port. ++- arm,dynamic-clk-gating : Enables dynamic clock gating (PL310) ++- arm,standby-mode : Enables standby mode (PL310) + - interrupts : 1 combined interrupt. + - cache-id-part: cache id part number to be used if it is not present + on hardware +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt linux-3.14.72/Documentation/devicetree/bindings/ata/ahci-platform.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/ata/ahci-platform.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -4,17 +4,39 @@ + Each SATA controller should have its own node. + + Required properties: +-- compatible : compatible list, contains "snps,spear-ahci" ++- compatible : compatible string, one of: ++ - "allwinner,sun4i-a10-ahci" ++ - "fsl,imx53-ahci" ++ - "fsl,imx6q-ahci" ++ - "hisilicon,hisi-ahci" ++ - "ibm,476gtr-ahci" ++ - "marvell,armada-380-ahci" ++ - "snps,dwc-ahci" ++ - "snps,exynos5440-ahci" ++ - "snps,spear-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 + +-Example: ++"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 ++ ++Examples: + sata@ffe08000 { + compatible = "snps,spear-ahci"; + reg = <0xffe08000 0x1000>; + interrupts = <115>; +- + }; ++ ++ ahci: sata@01c18000 { ++ compatible = "allwinner,sun4i-a10-ahci"; ++ reg = <0x01c18000 0x1000>; ++ interrupts = <56>; ++ clocks = <&pll6 0>, <&ahb_gates 25>; ++ target-supply = <®_ahci_5v>; ++ }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/clock/clock-bindings.txt linux-3.14.72/Documentation/devicetree/bindings/clock/clock-bindings.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/clock/clock-bindings.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/clock/clock-bindings.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -115,3 +115,39 @@ + ("pll" and "pll-switched"). + * The UART has its baud clock connected the external oscillator and its + register clock connected to the PLL clock (the "pll-switched" signal) ++ ++==Assigned clock parents and rates== ++ ++Some platforms may require initial configuration of default parent clocks ++and clock frequencies. Such a configuration can be specified in a device tree ++node through assigned-clocks, assigned-clock-parents and assigned-clock-rates ++properties. The assigned-clock-parents property should contain a list of parent ++clocks in form of phandle and clock specifier pairs, the assigned-clock-parents ++property the list of assigned clock frequency values - corresponding to clocks ++listed in the assigned-clocks property. ++ ++To skip setting parent or rate of a clock its corresponding entry should be ++set to 0, or can be omitted if it is not followed by any non-zero entry. ++ ++ uart@a000 { ++ compatible = "fsl,imx-uart"; ++ reg = <0xa000 0x1000>; ++ ... ++ clocks = <&osc 0>, <&pll 1>; ++ clock-names = "baud", "register"; ++ ++ assigned-clocks = <&clkcon 0>, <&pll 2>; ++ assigned-clock-parents = <&pll 2>; ++ assigned-clock-rates = <0>, <460800>; ++ }; ++ ++In this example the <&pll 2> clock is set as parent of clock <&clkcon 0> and ++the <&pll 2> clock is assigned a frequency value of 460800 Hz. ++ ++Configuring a clock's parent and rate through the device node that consumes ++the clock can be done only for clocks that have a single user. Specifying ++conflicting parent or rate configuration in multiple consumer nodes for ++a shared clock is forbidden. ++ ++Configuration of common clocks, which affect multiple consumer devices can ++be similarly specified in the clock provider node. +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/clock/imx6q-clock.txt linux-3.14.72/Documentation/devicetree/bindings/clock/imx6q-clock.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/clock/imx6q-clock.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/clock/imx6q-clock.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -7,222 +7,13 @@ + - #clock-cells: Should be <1> + + The clock consumer should specify the desired clock by having the clock +-ID in its "clocks" phandle cell. The following is a full list of i.MX6Q +-clocks and IDs. +- +- Clock ID +- --------------------------- +- dummy 0 +- ckil 1 +- ckih 2 +- osc 3 +- pll2_pfd0_352m 4 +- pll2_pfd1_594m 5 +- pll2_pfd2_396m 6 +- pll3_pfd0_720m 7 +- pll3_pfd1_540m 8 +- pll3_pfd2_508m 9 +- pll3_pfd3_454m 10 +- pll2_198m 11 +- pll3_120m 12 +- pll3_80m 13 +- pll3_60m 14 +- twd 15 +- step 16 +- pll1_sw 17 +- periph_pre 18 +- periph2_pre 19 +- periph_clk2_sel 20 +- periph2_clk2_sel 21 +- axi_sel 22 +- esai_sel 23 +- asrc_sel 24 +- spdif_sel 25 +- gpu2d_axi 26 +- gpu3d_axi 27 +- gpu2d_core_sel 28 +- gpu3d_core_sel 29 +- gpu3d_shader_sel 30 +- ipu1_sel 31 +- ipu2_sel 32 +- ldb_di0_sel 33 +- ldb_di1_sel 34 +- ipu1_di0_pre_sel 35 +- ipu1_di1_pre_sel 36 +- ipu2_di0_pre_sel 37 +- ipu2_di1_pre_sel 38 +- ipu1_di0_sel 39 +- ipu1_di1_sel 40 +- ipu2_di0_sel 41 +- ipu2_di1_sel 42 +- hsi_tx_sel 43 +- pcie_axi_sel 44 +- ssi1_sel 45 +- ssi2_sel 46 +- ssi3_sel 47 +- usdhc1_sel 48 +- usdhc2_sel 49 +- usdhc3_sel 50 +- usdhc4_sel 51 +- enfc_sel 52 +- emi_sel 53 +- emi_slow_sel 54 +- vdo_axi_sel 55 +- vpu_axi_sel 56 +- cko1_sel 57 +- periph 58 +- periph2 59 +- periph_clk2 60 +- periph2_clk2 61 +- ipg 62 +- ipg_per 63 +- esai_pred 64 +- esai_podf 65 +- asrc_pred 66 +- asrc_podf 67 +- spdif_pred 68 +- spdif_podf 69 +- can_root 70 +- ecspi_root 71 +- gpu2d_core_podf 72 +- gpu3d_core_podf 73 +- 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 +- ipu2_di1_pre 82 +- hsi_tx_podf 83 +- ssi1_pred 84 +- ssi1_podf 85 +- ssi2_pred 86 +- ssi2_podf 87 +- ssi3_pred 88 +- ssi3_podf 89 +- uart_serial_podf 90 +- usdhc1_podf 91 +- usdhc2_podf 92 +- usdhc3_podf 93 +- usdhc4_podf 94 +- enfc_pred 95 +- enfc_podf 96 +- emi_podf 97 +- emi_slow_podf 98 +- vpu_axi_podf 99 +- cko1_podf 100 +- axi 101 +- mmdc_ch0_axi_podf 102 +- mmdc_ch1_axi_podf 103 +- arm 104 +- ahb 105 +- apbh_dma 106 +- asrc 107 +- can1_ipg 108 +- can1_serial 109 +- can2_ipg 110 +- can2_serial 111 +- ecspi1 112 +- ecspi2 113 +- ecspi3 114 +- ecspi4 115 +- ecspi5 116 +- enet 117 +- esai 118 +- gpt_ipg 119 +- gpt_ipg_per 120 +- gpu2d_core 121 +- gpu3d_core 122 +- hdmi_iahb 123 +- hdmi_isfr 124 +- i2c1 125 +- i2c2 126 +- i2c3 127 +- iim 128 +- enfc 129 +- ipu1 130 +- ipu1_di0 131 +- ipu1_di1 132 +- ipu2 133 +- ipu2_di0 134 +- ldb_di0 135 +- ldb_di1 136 +- ipu2_di1 137 +- hsi_tx 138 +- mlb 139 +- mmdc_ch0_axi 140 +- mmdc_ch1_axi 141 +- ocram 142 +- openvg_axi 143 +- pcie_axi 144 +- pwm1 145 +- pwm2 146 +- pwm3 147 +- pwm4 148 +- per1_bch 149 +- gpmi_bch_apb 150 +- gpmi_bch 151 +- gpmi_io 152 +- gpmi_apb 153 +- sata 154 +- sdma 155 +- spba 156 +- ssi1 157 +- ssi2 158 +- ssi3 159 +- uart_ipg 160 +- uart_serial 161 +- usboh3 162 +- usdhc1 163 +- usdhc2 164 +- usdhc3 165 +- usdhc4 166 +- vdo_axi 167 +- vpu_axi 168 +- cko1 169 +- pll1_sys 170 +- pll2_bus 171 +- pll3_usb_otg 172 +- pll4_audio 173 +- pll5_video 174 +- pll8_mlb 175 +- pll7_usb_host 176 +- pll6_enet 177 +- ssi1_ipg 178 +- ssi2_ipg 179 +- ssi3_ipg 180 +- rom 181 +- usbphy1 182 +- usbphy2 183 +- ldb_di0_div_3_5 184 +- ldb_di1_div_3_5 185 +- sata_ref 186 +- sata_ref_100m 187 +- pcie_ref 188 +- pcie_ref_125m 189 +- enet_ref 190 +- usbphy1_gate 191 +- usbphy2_gate 192 +- pll4_post_div 193 +- pll5_post_div 194 +- pll5_video_div 195 +- eim_slow 196 +- spdif 197 +- cko2_sel 198 +- cko2_podf 199 +- cko2 200 +- cko 201 +- vdoa 202 +- pll4_audio_div 203 +- lvds1_sel 204 +- lvds2_sel 205 +- lvds1_gate 206 +- lvds2_gate 207 ++ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6qdl-clock.h ++for the full list of i.MX6 Quad and DualLite clock IDs. + + Examples: + ++#include ++ + clks: ccm@020c4000 { + compatible = "fsl,imx6q-ccm"; + reg = <0x020c4000 0x4000>; +@@ -234,7 +25,7 @@ + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; + interrupts = <0 26 0x04>; +- clocks = <&clks 160>, <&clks 161>; ++ clocks = <&clks IMX6QDL_CLK_UART_IPG>, <&clks IMX6QDL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; + status = "disabled"; + }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/clock/imx6sx-clock.txt linux-3.14.72/Documentation/devicetree/bindings/clock/imx6sx-clock.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/clock/imx6sx-clock.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/clock/imx6sx-clock.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -0,0 +1,13 @@ ++* Clock bindings for Freescale i.MX6 SoloX ++ ++Required properties: ++- compatible: Should be "fsl,imx6sx-ccm" ++- reg: Address and length of the register set ++- #clock-cells: Should be <1> ++- clocks: list of clock specifiers, must contain an entry for each required ++ entry in clock-names ++- clock-names: should include entries "ckil", "osc", "ipp_di0" and "ipp_di1" ++ ++The clock consumer should specify the desired clock by having the clock ++ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6sx-clock.h ++for the full list of i.MX6 SoloX clock IDs. +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt linux-3.14.72/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -16,6 +16,12 @@ + - #dma-cells : Must be <3>. + The first cell specifies the DMA request/event ID. See details below + about the second and third cell. ++- gpr : The phandle to general purpose register node. ++- fsl,sdma-event-remap : Register bits of sdma event remap, the format is ++ . ++ reg is the gpr register offset. ++ shift is the bit offset of event remap. ++ val is the value of the bit to be set. + - fsl,sdma-ram-script-name : Should contain the full path of SDMA RAM + scripts firmware + +@@ -47,6 +53,9 @@ + 20 ASRC + 21 ESAI + 22 SSI Dual FIFO (needs firmware ver >= 2) ++ 23 Shared ASRC ++ 24 HDMI Audio ++ 25 SAI + + The third cell specifies the transfer priority as below. + +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt linux-3.14.72/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -0,0 +1,118 @@ ++* 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. ++ ++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", "adv739x". ++- 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, "BT656-NTSC" or "BT656-PAL" for adv739x. ++- 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 ++ 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 ++- 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. ++- 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 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"; ++ }; ++ ++Example for adv739x CVBS output: ++ fb0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "adv739x"; ++ interface_pix_fmt = "BT656"; ++ mode_str ="BT656-NTSC"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/fb/mxsfb.txt linux-3.14.72/Documentation/devicetree/bindings/fb/mxsfb.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/fb/mxsfb.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/fb/mxsfb.txt 2016-06-19 22:11:55.073155238 +0200 +@@ -3,6 +3,9 @@ + Required properties: + - compatible: Should be "fsl,-lcdif". Supported chips include + imx23 and imx28. ++- pinctrl-names: Should be "default" ++- pinctrl-0: pinctrl setting for lcd ++- lcd-supply: lcd power supply, usually via GPIO + - reg: Address and length of the register set for lcdif + - interrupts: Should contain lcdif interrupts + - display : phandle to display node (see below for details) +@@ -22,6 +25,10 @@ + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 2000>; + interrupts = <38 86>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lcdif_24bit_pins_a ++ &lcdif_pins_evk>; ++ lcd-supply = <®_lcd_3v3>; + + display: display { + bits-per-pixel = <32>; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/input/snvs-pwrkey.txt linux-3.14.72/Documentation/devicetree/bindings/input/snvs-pwrkey.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/input/snvs-pwrkey.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/input/snvs-pwrkey.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,26 @@ ++* Freescale i.MX SNVS powerkey device tree bindings ++ ++The snvs-pwrkey is designed to enable POWER key function which controlled ++by SNVS ONOFF, the driver can report the status of POWER key and wakeup ++system if pressed after system suspend. ++ ++Required SoC Specific Properties: ++- compatible: Should be "fsl,imx6sx-snvs-pwrkey". ++ ++- reg: Physical base address of the SNVS and length of memory mapped ++ region. ++ ++- interrupts: The SNVS interrupt number to the CPU(s). ++ ++- fsl,keycode: Keycode to emit, KEY_POWER by default. ++ ++- fsl,wakeup: Button can wake-up the system ++ ++Example: ++snvs-pwrkey@0x020cc000 { ++ compatible = "fsl,imx6sx-snvs-pwrkey"; ++ reg = <0x020cc000 0x4000>; ++ interrupts = <0 4 0x4>; ++ fsl,keycode = <116>; /* KEY_POWER */ ++ fsl,wakeup; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt linux-3.14.72/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,55 @@ ++FocalTech EDT-FT5x06 Polytouch driver ++===================================== ++ ++There are 3 variants of the chip for various touch panel sizes ++FT5206GE1 2.8" .. 3.8" ++FT5306DE4 4.3" .. 7" ++FT5406EE8 7" .. 8.9" ++ ++The software interface is identical for all those chips, so that ++currently there is no need for the driver to distinguish between the ++different chips. Nevertheless distinct compatible strings are used so ++that a distinction can be added if necessary without changing the DT ++bindings. ++ ++ ++Required properties: ++ - compatible: "edt,edt-ft5206" ++ or: "edt,edt-ft5306" ++ or: "edt,edt-ft5406" ++ ++ - reg: I2C slave address of the chip (0x38) ++ - interrupt-parent: a phandle pointing to the interrupt controller ++ serving the interrupt for this chip ++ - interrupts: interrupt specification for the touchdetect ++ interrupt ++ ++Optional properties: ++ - reset-gpios: GPIO specification for the RESET input ++ - wake-gpios: GPIO specification for the WAKE input ++ ++ - pinctrl-names: should be "default" ++ - pinctrl-0: a phandle pointing to the pin settings for the ++ control gpios ++ ++ - threshold: allows setting the "click"-threshold in the range ++ from 20 to 80. ++ ++ - gain: allows setting the sensitivity in the range from 0 to ++ 31. Note that lower values indicate higher ++ sensitivity. ++ ++ - offset: allows setting the edge compensation in the range from ++ 0 to 31. ++ ++Example: ++ polytouch: edt-ft5x06@38 { ++ compatible = "edt,edt-ft5406", "edt,edt-ft5x06"; ++ reg = <0x38>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&edt_ft5x06_pins>; ++ interrupt-parent = <&gpio2>; ++ interrupts = <5 0>; ++ reset-gpios = <&gpio2 6 1>; ++ wake-gpios = <&gpio4 9 0>; ++ }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/leds/leds-gpio.txt linux-3.14.72/Documentation/devicetree/bindings/leds/leds-gpio.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/leds/leds-gpio.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/leds/leds-gpio.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -21,6 +21,8 @@ + on). The "keep" setting will keep the LED at whatever its current + state is, without producing a glitch. The default is off if this + property is not present. ++- retain-state-suspended: (optional) The suspend state can be retained.Such ++ as charge-led gpio. + + Examples: + +@@ -50,3 +52,13 @@ + default-state = "on"; + }; + }; ++ ++leds { ++ compatible = "gpio-leds"; ++ ++ charger-led { ++ gpios = <&gpio1 2 0>; ++ linux,default-trigger = "max8903-charger-charging"; ++ retain-state-suspended; ++ }; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/leds/leds-pwm.txt linux-3.14.72/Documentation/devicetree/bindings/leds/leds-pwm.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/leds/leds-pwm.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/leds/leds-pwm.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -17,6 +17,8 @@ + see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt ++- active-low : (optional) ++ Inverts the duty cycle to reflect a low-active output pin + + Example: + +@@ -38,6 +40,7 @@ + label = "omap4::keypad"; + pwms = <&twl_pwm 0 7812500>; + max-brightness = <127>; ++ active-low; + }; + + charging { +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/mfd/syscon.txt linux-3.14.72/Documentation/devicetree/bindings/mfd/syscon.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/mfd/syscon.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/mfd/syscon.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -13,6 +13,9 @@ + - compatible: Should contain "syscon". + - reg: the register region can be accessed from syscon + ++Optional properties: ++- clocks: clock used for accessing the regmap ++ + Examples: + gpr: iomuxc-gpr@020e0000 { + compatible = "fsl,imx6q-iomuxc-gpr", "syscon"; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/mmc/mmc.txt linux-3.14.72/Documentation/devicetree/bindings/mmc/mmc.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/mmc/mmc.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/mmc/mmc.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -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.72.orig/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt linux-3.14.72/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,52 @@ ++* Freescale Quad Serial Peripheral Interface(QuadSPI) ++ ++The QuadSPI controller acts as the SPI master. It is described with a node ++for the controller and a set of child nodes for each SPI NOR flash. ++ ++Part I - The DT node for the controller: ++------------------------------ ++ ++Required properties: ++ - compatible : Should be "fsl,vf610-qspi" ++ - reg : the first contains the register location and length, ++ the second contains the memory mapping address and length ++ - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" ++ - interrupts : Should contain the interrupt for the device ++ - clocks : The clocks needed by the QuadSPI controller ++ - clock-names : the name of the clocks ++ ++Optional properties: ++ - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B. ++ Each bus can be connected with two NOR flashes. ++ Most of the time, each bus only has one NOR flash ++ connected, this is the default case. ++ But if there are two NOR flashes connected to the ++ bus, you should enable this property. ++ (Please check the board's schematic.) ++ - ddrsmp: The value for DDR internal sampling point, range is 0 - 7. ++ ++Part II - The DT nodes for each SPI NOR flash ++------------------------------ ++Required properties: ++- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at ++ ++Optional properties: ++ Please refer to the Documentation/devicetree/bindings/mtd/spi-nor-flash.txt ++ If you set the "spi-nor,ddr-quad-read-dummy", it means you enable the DDR ++ quad read feature for the driver. ++ ++Example: ++ ++qspi0: quadspi@40044000 { ++ compatible = "fsl,vf610-qspi"; ++ reg = <0x40044000 0x1000>, <0x20000000 0x10000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks VF610_CLK_QSPI0_EN>, ++ <&clks VF610_CLK_QSPI0>; ++ clock-names = "qspi_en", "qspi"; ++ ++ flash0: s25fl128s@0 { ++ .... ++ }; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/mtd/spi-nor-flash.txt linux-3.14.72/Documentation/devicetree/bindings/mtd/spi-nor-flash.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/mtd/spi-nor-flash.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/mtd/spi-nor-flash.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,7 @@ ++This file defines some DT properties for specific SPI NOR flash features. ++The SPI NOR controller drivers may refer to this file, such as fsl-quadspi.txt ++ ++Optional properties: ++ - spi-nor,ddr-quad-read-dummy: The dummy cycles used by the DDR Quad read. ++ Please refer to the chip's datasheet. This ++ property can be 4 or 6 which is less then 8. +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt linux-3.14.72/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -15,8 +15,18 @@ + Optional properties: + + - clock-frequency : The oscillator frequency driving the flexcan device +- + - xceiver-supply: Regulator that powers the CAN transceiver ++- stop-mode: register bits of stop mode control, the format is ++ <&gpr req_gpr req_bit ack_gpr ack_bit>. ++ gpr is the phandle to general purpose register node. ++ req_gpr is the gpr register offset of CAN stop request. ++ req_bit is the bit offset of CAN stop request. ++ ack_gpr is the gpr register offset of CAN stop acknowledge. ++ ack_bit is the bit offset of CAN stop acknowledge. ++- trx_en_gpio : enable gpio ++- trx_stby_gpio : standby gpio ++- trx_nerr_gpio : NERR gpio ++- trx_wakeup_gpio : local wakeup gpio + + Example: + +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/net/can/m_can.txt linux-3.14.72/Documentation/devicetree/bindings/net/can/m_can.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/net/can/m_can.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/net/can/m_can.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,29 @@ ++Bosch MCAN controller Device Tree Bindings ++------------------------------------------------- ++ ++Required properties: ++- compatible : Should be "bosch,m_can" for M_CAN controllers ++- reg : physical base address and size of the M_CAN ++ registers map and message ram ++- interrupts : property with a value describing the interrupt ++ number ++- clocks : clocks used by controller ++- mram-cfg : message ram configuration data, the format is ++ ++ The 'offset' is the address offset inside the message ram. This is usually set ++ if you're using the shared message ram while the other part is used by another ++ m_can controller. ++ The left cell are all the number of each elements inside the message ram. ++ Please refer to 2.4.1 Message RAM Con.guration in Bosch M_CAN user mannual ++ for each elements definition. ++ ++Example: ++canfd1: canfd@020e8000 { ++ compatible = "bosch,m_can"; ++ reg = <0x020e8000 0x4000>, <0x02298000 0x4000>; ++ reg-names = "canfd", "message_ram"; ++ interrupts = <0 114 0x04>; ++ clocks = <&clks IMX6SX_CLK_CANFD>; ++ mram-cfg = <0x0 0 0 32 32 32 0 1>; ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/net/fixed-link.txt linux-3.14.72/Documentation/devicetree/bindings/net/fixed-link.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/net/fixed-link.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/net/fixed-link.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,30 @@ ++Fixed link Device Tree binding ++------------------------------ ++ ++Some Ethernet MACs have a "fixed link", and are not connected to a ++normal MDIO-managed PHY device. For those situations, a Device Tree ++binding allows to describe a "fixed link". ++ ++Such a fixed link situation is described by creating a 'fixed-link' ++sub-node of the Ethernet MAC device node, with the following ++properties: ++ ++* 'speed' (integer, mandatory), to indicate the link speed. Accepted ++ values are 10, 100 and 1000 ++* 'full-duplex' (boolean, optional), to indicate that full duplex is ++ used. When absent, half duplex is assumed. ++* 'pause' (boolean, optional), to indicate that pause should be ++ enabled. ++* 'asym-pause' (boolean, optional), to indicate that asym_pause should ++ be enabled. ++ ++Example: ++ ++ethernet@0 { ++ ... ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ ... ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/net/fsl-fec.txt linux-3.14.72/Documentation/devicetree/bindings/net/fsl-fec.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/net/fsl-fec.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/net/fsl-fec.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -15,7 +15,22 @@ + only if property "phy-reset-gpios" is available. Missing the property + will have the duration be 1 millisecond. Numbers greater than 1000 are + invalid and 1 millisecond will be used instead. +-- phy-supply: regulator that powers the Ethernet PHY. ++- phy-supply : regulator that powers the Ethernet PHY. ++- phy-handle : phandle to the PHY device connected to this device. ++- fixed-link : Assume a fixed link. See fixed-link.txt in the same directory. ++ Use instead of phy-handle. ++- fsl,num-tx-queues : The property is valid for enet-avb IP, which supports ++ hw multi queues. Should specify the tx queue number, otherwise set tx queue ++ number to 1. ++- fsl,num-rx-queues : The property is valid for enet-avb IP, which supports ++ hw multi queues. Should specify the rx queue number, otherwise set rx queue ++ number to 1. ++- fsl,magic-packet : If present, indicates that the hardware supports waking ++ up via magic packet. ++ ++Optional subnodes: ++- mdio : specifies the mdio bus in the FEC, used as a container for phy nodes ++ according to phy.txt in the same directory + + Example: + +@@ -28,3 +43,23 @@ + local-mac-address = [00 04 9F 01 1B B9]; + phy-supply = <®_fec_supply>; + }; ++ ++Example with phy specified: ++ ++ethernet@83fec000 { ++ compatible = "fsl,imx51-fec", "fsl,imx27-fec"; ++ reg = <0x83fec000 0x4000>; ++ interrupts = <87>; ++ phy-mode = "mii"; ++ phy-reset-gpios = <&gpio2 14 0>; /* GPIO2_14 */ ++ local-mac-address = [00 04 9F 01 1B B9]; ++ phy-supply = <®_fec_supply>; ++ phy-handle = <ðphy>; ++ mdio { ++ ethphy: ethernet-phy@6 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <6>; ++ max-speed = <100>; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pci/designware-pcie.txt linux-3.14.72/Documentation/devicetree/bindings/pci/designware-pcie.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pci/designware-pcie.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/pci/designware-pcie.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -1,15 +1,11 @@ + * Synopsys Designware PCIe interface + + Required properties: +-- compatible: should contain "snps,dw-pcie" to identify the +- core, plus an identifier for the specific instance, such +- as "samsung,exynos5440-pcie" or "fsl,imx6q-pcie". +-- reg: base addresses and lengths of the pcie controller, +- the phy controller, additional register for the phy controller. +-- interrupts: interrupt values for level interrupt, +- pulse interrupt, special interrupt. +-- clocks: from common clock binding: handle to pci clock. +-- clock-names: from common clock binding: should be "pcie" and "pcie_bus". ++- compatible: should contain "snps,dw-pcie" to identify the core. ++- reg: Should contain the configuration address space. ++- reg-names: Must be "config" for the PCIe configuration space. ++ (The old way of getting the configuration address space from "ranges" ++ is deprecated and should be avoided.) + - #address-cells: set to <3> + - #size-cells: set to <2> + - device_type: set to "pci" +@@ -19,65 +15,14 @@ + to define the mapping of the PCIe interface to interrupt + numbers. + - num-lanes: number of lanes to use ++- clocks: Must contain an entry for each entry in clock-names. ++ See ../clocks/clock-bindings.txt for details. ++- clock-names: Must include the following entries: ++ - "pcie" ++ - "pcie_bus" + + Optional properties: + - reset-gpio: gpio pin number of power good signal +- +-Optional properties for fsl,imx6q-pcie +-- power-on-gpio: gpio pin number of power-enable signal +-- wake-up-gpio: gpio pin number of incoming wakeup signal +-- disable-gpio: gpio pin number of outgoing rfkill/endpoint disable signal +- +-Example: +- +-SoC specific DT Entry: +- +- pcie@290000 { +- compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; +- reg = <0x290000 0x1000 +- 0x270000 0x1000 +- 0x271000 0x40>; +- interrupts = <0 20 0>, <0 21 0>, <0 22 0>; +- clocks = <&clock 28>, <&clock 27>; +- clock-names = "pcie", "pcie_bus"; +- #address-cells = <3>; +- #size-cells = <2>; +- device_type = "pci"; +- ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */ +- 0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */ +- 0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */ +- #interrupt-cells = <1>; +- interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0x0 0 &gic 53>; +- num-lanes = <4>; +- }; +- +- pcie@2a0000 { +- compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; +- reg = <0x2a0000 0x1000 +- 0x272000 0x1000 +- 0x271040 0x40>; +- interrupts = <0 23 0>, <0 24 0>, <0 25 0>; +- clocks = <&clock 29>, <&clock 27>; +- clock-names = "pcie", "pcie_bus"; +- #address-cells = <3>; +- #size-cells = <2>; +- device_type = "pci"; +- ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */ +- 0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */ +- 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */ +- #interrupt-cells = <1>; +- interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0x0 0 &gic 56>; +- num-lanes = <4>; +- }; +- +-Board specific DT Entry: +- +- pcie@290000 { +- reset-gpio = <&pin_ctrl 5 0>; +- }; +- +- pcie@2a0000 { +- reset-gpio = <&pin_ctrl 22 0>; +- }; ++- bus-range: PCI bus numbers covered (it is recommended for new devicetrees to ++ specify this property, to keep backwards compatibility a range of 0x00-0xff ++ is assumed if not present) +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt linux-3.14.72/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,44 @@ ++* Freescale i.MX6 PCIe interface ++ ++This PCIe host controller is based on the Synopsis Designware PCIe IP ++and thus inherits all the common properties defined in designware-pcie.txt. ++ ++Required properties: ++- compatible: "fsl,imx6q-pcie", "fsl,imx6sx-pcie" ++- reg: base addresse and length of the pcie controller ++- interrupts: A list of interrupt outputs of the controller. Must contain an ++ entry for each entry in the interrupt-names property. ++- interrupt-names: Must include the following entries: ++ - "msi": The interrupt that is asserted when an MSI is received ++- clock-names: Must include the following additional entries: ++ - "pcie_phy" ++ ++Additional required properties for imx6sx-pcie: ++- clock names: Must include the following additional entries: ++ - "pcie_inbound_axi" ++- power supplies: ++ - pcie-phy-supply: regulator used to power the PCIe PHY ++ ++Example: ++ ++ pcie@0x01000000 { ++ compatible = "fsl,imx6q-pcie", "snps,dw-pcie"; ++ reg = <0x01ffc000 0x4000>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 ++ 0x81000000 0 0 0x01f80000 0 0x00010000 ++ 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; ++ num-lanes = <1>; ++ interrupts = ; ++ interrupt-names = "msi"; ++ #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 206>, <&clks 189>; ++ clock-names = "pcie", "pcie_bus", "pcie_phy"; ++ }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pci/host-generic-pci.txt linux-3.14.72/Documentation/devicetree/bindings/pci/host-generic-pci.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pci/host-generic-pci.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/pci/host-generic-pci.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,100 @@ ++* Generic PCI host controller ++ ++Firmware-initialised PCI host controllers and PCI emulations, such as the ++virtio-pci implementations found in kvmtool and other para-virtualised ++systems, do not require driver support for complexities such as regulator ++and clock management. In fact, the controller may not even require the ++configuration of a control interface by the operating system, instead ++presenting a set of fixed windows describing a subset of IO, Memory and ++Configuration Spaces. ++ ++Such a controller can be described purely in terms of the standardized device ++tree bindings communicated in pci.txt: ++ ++ ++Properties of the host controller node: ++ ++- compatible : Must be "pci-host-cam-generic" or "pci-host-ecam-generic" ++ depending on the layout of configuration space (CAM vs ++ ECAM respectively). ++ ++- device_type : Must be "pci". ++ ++- ranges : As described in IEEE Std 1275-1994, but must provide ++ at least a definition of non-prefetchable memory. One ++ or both of prefetchable Memory and IO Space may also ++ be provided. ++ ++- bus-range : Optional property (also described in IEEE Std 1275-1994) ++ to indicate the range of bus numbers for this controller. ++ If absent, defaults to <0 255> (i.e. all buses). ++ ++- #address-cells : Must be 3. ++ ++- #size-cells : Must be 2. ++ ++- reg : The Configuration Space base address and size, as accessed ++ from the parent bus. ++ ++ ++Properties of the /chosen node: ++ ++- linux,pci-probe-only ++ : Optional property which takes a single-cell argument. ++ If '0', then Linux will assign devices in its usual manner, ++ otherwise it will not try to assign devices and instead use ++ them as they are configured already. ++ ++Configuration Space is assumed to be memory-mapped (as opposed to being ++accessed via an ioport) and laid out with a direct correspondence to the ++geography of a PCI bus address by concatenating the various components to ++form an offset. ++ ++For CAM, this 24-bit offset is: ++ ++ cfg_offset(bus, device, function, register) = ++ bus << 16 | device << 11 | function << 8 | register ++ ++Whilst ECAM extends this by 4 bits to accomodate 4k of function space: ++ ++ cfg_offset(bus, device, function, register) = ++ bus << 20 | device << 15 | function << 12 | register ++ ++Interrupt mapping is exactly as described in `Open Firmware Recommended ++Practice: Interrupt Mapping' and requires the following properties: ++ ++- #interrupt-cells : Must be 1 ++ ++- interrupt-map : ++ ++- interrupt-map-mask : ++ ++ ++Example: ++ ++pci { ++ compatible = "pci-host-cam-generic" ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ bus-range = <0x0 0x1>; ++ ++ // CPU_PHYSICAL(2) SIZE(2) ++ reg = <0x0 0x40000000 0x0 0x1000000>; ++ ++ // BUS_ADDRESS(3) CPU_PHYSICAL(2) SIZE(2) ++ ranges = <0x01000000 0x0 0x01000000 0x0 0x01000000 0x0 0x00010000>, ++ <0x02000000 0x0 0x41000000 0x0 0x41000000 0x0 0x3f000000>; ++ ++ ++ #interrupt-cells = <0x1>; ++ ++ // PCI_DEVICE(3) INT#(1) CONTROLLER(PHANDLE) CONTROLLER_DATA(3) ++ interrupt-map = < 0x0 0x0 0x0 0x1 &gic 0x0 0x4 0x1 ++ 0x800 0x0 0x0 0x1 &gic 0x0 0x5 0x1 ++ 0x1000 0x0 0x0 0x1 &gic 0x0 0x6 0x1 ++ 0x1800 0x0 0x0 0x1 &gic 0x0 0x7 0x1>; ++ ++ // PCI_DEVICE(3) INT#(1) ++ interrupt-map-mask = <0xf800 0x0 0x0 0x7>; ++} +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt linux-3.14.72/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,65 @@ ++* Samsung Exynos 5440 PCIe interface ++ ++This PCIe host controller is based on the Synopsis Designware PCIe IP ++and thus inherits all the common properties defined in designware-pcie.txt. ++ ++Required properties: ++- compatible: "samsung,exynos5440-pcie" ++- reg: base addresses and lengths of the pcie controller, ++ the phy controller, additional register for the phy controller. ++- interrupts: A list of interrupt outputs for level interrupt, ++ pulse interrupt, special interrupt. ++ ++Example: ++ ++SoC specific DT Entry: ++ ++ pcie@290000 { ++ compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; ++ reg = <0x290000 0x1000 ++ 0x270000 0x1000 ++ 0x271000 0x40>; ++ interrupts = <0 20 0>, <0 21 0>, <0 22 0>; ++ clocks = <&clock 28>, <&clock 27>; ++ clock-names = "pcie", "pcie_bus"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */ ++ 0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; ++ num-lanes = <4>; ++ }; ++ ++ pcie@2a0000 { ++ compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; ++ reg = <0x2a0000 0x1000 ++ 0x272000 0x1000 ++ 0x271040 0x40>; ++ interrupts = <0 23 0>, <0 24 0>, <0 25 0>; ++ clocks = <&clock 29>, <&clock 27>; ++ clock-names = "pcie", "pcie_bus"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */ ++ 0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &gic GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; ++ num-lanes = <4>; ++ }; ++ ++Board specific DT Entry: ++ ++ pcie@290000 { ++ reset-gpio = <&pin_ctrl 5 0>; ++ }; ++ ++ pcie@2a0000 { ++ reset-gpio = <&pin_ctrl 22 0>; ++ }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pci/spear13xx-pcie.txt linux-3.14.72/Documentation/devicetree/bindings/pci/spear13xx-pcie.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pci/spear13xx-pcie.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/pci/spear13xx-pcie.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,14 @@ ++SPEAr13XX PCIe DT detail: ++================================ ++ ++SPEAr13XX uses synopsis designware PCIe controller and ST MiPHY as phy ++controller. ++ ++Required properties: ++- compatible : should be "st,spear1340-pcie", "snps,dw-pcie". ++- phys : phandle to phy node associated with pcie controller ++- phy-names : must be "pcie-phy" ++- All other definitions as per generic PCI bindings ++ ++ Optional properties: ++- st,pcie-is-gen1 indicates that forced gen1 initialization is needed. +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pci/ti-pci.txt linux-3.14.72/Documentation/devicetree/bindings/pci/ti-pci.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pci/ti-pci.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/pci/ti-pci.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,59 @@ ++TI PCI Controllers ++ ++PCIe Designware Controller ++ - compatible: Should be "ti,dra7-pcie"" ++ - reg : Two register ranges as listed in the reg-names property ++ - reg-names : The first entry must be "ti-conf" for the TI specific registers ++ The second entry must be "rc-dbics" for the designware pcie ++ registers ++ The third entry must be "config" for the PCIe configuration space ++ - phys : list of PHY specifiers (used by generic PHY framework) ++ - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the ++ number of PHYs as specified in *phys* property. ++ - ti,hwmods : Name of the hwmod associated to the pcie, "pcie", ++ where is the instance number of the pcie from the HW spec. ++ - interrupts : Two interrupt entries must be specified. The first one is for ++ main interrupt line and the second for MSI interrupt line. ++ - #address-cells, ++ #size-cells, ++ #interrupt-cells, ++ device_type, ++ ranges, ++ num-lanes, ++ interrupt-map-mask, ++ interrupt-map : as specified in ../designware-pcie.txt ++ ++Example: ++axi { ++ compatible = "simple-bus"; ++ #size-cells = <1>; ++ #address-cells = <1>; ++ ranges = <0x51000000 0x51000000 0x3000 ++ 0x0 0x20000000 0x10000000>; ++ pcie@51000000 { ++ compatible = "ti,dra7-pcie"; ++ reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>; ++ reg-names = "rc_dbics", "ti_conf", "config"; ++ interrupts = <0 232 0x4>, <0 233 0x4>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x81000000 0 0 0x03000 0 0x00010000 ++ 0x82000000 0 0x20013000 0x13000 0 0xffed000>; ++ #interrupt-cells = <1>; ++ num-lanes = <1>; ++ ti,hwmods = "pcie1"; ++ phys = <&pcie1_phy>; ++ phy-names = "pcie-phy0"; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &pcie_intc 1>, ++ <0 0 0 2 &pcie_intc 2>, ++ <0 0 0 3 &pcie_intc 3>, ++ <0 0 0 4 &pcie_intc 4>; ++ pcie_intc: interrupt-controller { ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ }; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pinctrl/fsl,imx6sx-pinctrl.txt linux-3.14.72/Documentation/devicetree/bindings/pinctrl/fsl,imx6sx-pinctrl.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pinctrl/fsl,imx6sx-pinctrl.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/pinctrl/fsl,imx6sx-pinctrl.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,36 @@ ++* Freescale i.MX6 SoloX IOMUX Controller ++ ++Please refer to fsl,imx-pinctrl.txt in this directory for common binding part ++and usage. ++ ++Required properties: ++- compatible: "fsl,imx6sx-iomuxc" ++- fsl,pins: each entry consists of 6 integers and represents the mux and config ++ setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in ++ imx6sx-pinfunc.h under device tree source folder. The last integer CONFIG is ++ the pad setting value like pull-up on this pin. Please refer to i.MX6 SoloX ++ Reference Manual for detailed CONFIG settings. ++ ++CONFIG bits definition: ++PAD_CTL_HYS (1 << 16) ++PAD_CTL_PUS_100K_DOWN (0 << 14) ++PAD_CTL_PUS_47K_UP (1 << 14) ++PAD_CTL_PUS_100K_UP (2 << 14) ++PAD_CTL_PUS_22K_UP (3 << 14) ++PAD_CTL_PUE (1 << 13) ++PAD_CTL_PKE (1 << 12) ++PAD_CTL_ODE (1 << 11) ++PAD_CTL_SPEED_LOW (0 << 6) ++PAD_CTL_SPEED_MED (1 << 6) ++PAD_CTL_SPEED_HIGH (3 << 6) ++PAD_CTL_DSE_DISABLE (0 << 3) ++PAD_CTL_DSE_260ohm (1 << 3) ++PAD_CTL_DSE_130ohm (2 << 3) ++PAD_CTL_DSE_87ohm (3 << 3) ++PAD_CTL_DSE_65ohm (4 << 3) ++PAD_CTL_DSE_52ohm (5 << 3) ++PAD_CTL_DSE_43ohm (6 << 3) ++PAD_CTL_DSE_37ohm (7 << 3) ++PAD_CTL_SRE_FAST (1 << 0) ++PAD_CTL_SRE_SLOW (0 << 0) +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt linux-3.14.72/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -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.72.orig/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt linux-3.14.72/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,54 @@ ++Freescale i.MX General Power Controller ++======================================= ++ ++The i.MX6Q General Power Control (GPC) block contains DVFS load tracking ++counters and Power Gating Control (PGC) for the CPU and PU (GPU/VPU) power ++domains. ++ ++Required properties: ++- compatible: Should be "fsl,imx6q-gpc" or "fsl,imx6sl-gpc" ++- reg: should be register base and length as documented in the ++ datasheet ++- interrupts: Should contain GPC interrupt request 1 ++- pu-supply: Link to the LDO regulator powering the PU power domain ++- clocks: Clock phandles to devices in the PU power domain that need ++ to be enabled during domain power-up for reset propagation. ++- #power-domain-cells: Should be 1, see below: ++ ++The gpc node is a power-controller as documented by the generic power domain ++bindings in Documentation/devicetree/bindings/power/power_domain.txt. ++ ++Example: ++ ++ gpc: gpc@020dc000 { ++ compatible = "fsl,imx6q-gpc"; ++ reg = <0x020dc000 0x4000>; ++ interrupts = <0 89 0x04 0 90 0x04>; ++ pu-supply = <®_pu>; ++ clocks = <&clks 122>, <&clks 74>, <&clks 121>, ++ <&clks 26>, <&clks 143>, <&clks 168>; ++ #power-domain-cells = <1>; ++ }; ++ ++ ++Specifying power domain for IP modules ++====================================== ++ ++IP cores belonging to a power domain should contain a 'power-domains' property ++that is a phandle pointing to the gpc device node and a DOMAIN_INDEX specifying ++the power domain the device belongs to. ++ ++Example of a device that is part of the PU power domain: ++ ++ vpu: vpu@02040000 { ++ reg = <0x02040000 0x3c000>; ++ /* ... */ ++ power-domains = <&gpc 1>; ++ /* ... */ ++ }; ++ ++The following DOMAIN_INDEX values are valid for i.MX6Q: ++ARM_DOMAIN 0 ++PU_DOMAIN 1 ++The following additional DOMAIN_INDEX value is valid for i.MX6SL: ++DISPLAY_DOMAIN 2 +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/power/power_domain.txt linux-3.14.72/Documentation/devicetree/bindings/power/power_domain.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/power/power_domain.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/power/power_domain.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,49 @@ ++* Generic PM domains ++ ++System on chip designs are often divided into multiple PM domains that can be ++used for power gating of selected IP blocks for power saving by reduced leakage ++current. ++ ++This device tree binding can be used to bind PM domain consumer devices with ++their PM domains provided by PM domain providers. A PM domain provider can be ++represented by any node in the device tree and can provide one or more PM ++domains. A consumer node can refer to the provider by a phandle and a set of ++phandle arguments (so called PM domain specifiers) of length specified by the ++#power-domain-cells property in the PM domain provider node. ++ ++==PM domain providers== ++ ++Required properties: ++ - #power-domain-cells : Number of cells in a PM domain specifier; ++ Typically 0 for nodes representing a single PM domain and 1 for nodes ++ providing multiple PM domains (e.g. power controllers), but can be any value ++ as specified by device tree binding documentation of particular provider. ++ ++Example: ++ ++ power: power-controller@12340000 { ++ compatible = "foo,power-controller"; ++ reg = <0x12340000 0x1000>; ++ #power-domain-cells = <1>; ++ }; ++ ++The node above defines a power controller that is a PM domain provider and ++expects one cell as its phandle argument. ++ ++==PM domain consumers== ++ ++Required properties: ++ - power-domains : A phandle and PM domain specifier as defined by bindings of ++ the power controller specified by phandle. ++ ++Example: ++ ++ leaky-device@12350000 { ++ compatible = "foo,i-leak-current"; ++ reg = <0x12350000 0x1000>; ++ power-domains = <&power 0>; ++ }; ++ ++The node above defines a typical PM domain consumer device, which is located ++inside a PM domain with index 0 of a power controller represented by a node ++with the label "power". +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/regulator/ltc3676.txt linux-3.14.72/Documentation/devicetree/bindings/regulator/ltc3676.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/regulator/ltc3676.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/regulator/ltc3676.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,103 @@ ++Linear Technology LTC3676 8-output regulators ++ ++Required properties: ++- compatible: "lltc,ltc3676" ++- reg: I2C slave address ++ ++Required child node: ++- regulators: Contains eight regulator child nodes sw1, sw2, sw3, sw4, ++ ldo1, ldo2, ldo3, and ldo4, specifying the initialization data as ++ documented in Documentation/devicetree/bindings/regulator/regulator.txt. ++ ++Each regulator is defined using the standard binding for regulators. The ++nodes for sw1, sw2, sw3, sw4, ldo1, ldo2 and ldo4 additionally need to specify ++the resistor values of their external feedback voltage dividers: ++ ++Required properties (not on ldo3): ++- lltc,fb-voltage-divider: An array of two integers containing the resistor ++ values R1 and R2 of the feedback voltage divider in ohms. ++ ++Regulators sw1, sw2, sw3, sw4 can regulate the feedback reference from: ++412.5mV to 800mV in 12.5 mV steps. The output voltage thus ranges between ++0.4125 * (1 + R1/R2) V and 0.8 * (1 + R1/R2) V. ++ ++Regulators ldo1, ldo2, and ldo4 have a fixed 0.725 V reference and thus output ++0.725 * (1 + R1/R2) V. The ldo3 regulator is fixed to 1.8 V. The ldo1 standby ++regulator can not be disabled and thus should have the regulator-always-on ++property set. ++ ++Example: ++ ++ ltc3676: pmic@3c { ++ compatible = "lltc,ltc3676"; ++ reg = <0x3c>; ++ ++ regulators { ++ sw1_reg: sw1 { ++ regulator-min-microvolt = <674400>; ++ regulator-max-microvolt = <1308000>; ++ lltc,fb-voltage-divider = <127000 200000>; ++ regulator-ramp-delay = <7000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw2_reg: sw2 { ++ regulator-min-microvolt = <1033310>; ++ regulator-max-microvolt = <200400>; ++ lltc,fb-voltage-divider = <301000 200000>; ++ regulator-ramp-delay = <7000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3_reg: sw3 { ++ regulator-min-microvolt = <674400>; ++ regulator-max-microvolt = <130800>; ++ lltc,fb-voltage-divider = <127000 200000>; ++ regulator-ramp-delay = <7000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw4_reg: sw4 { ++ regulator-min-microvolt = <868310>; ++ regulator-max-microvolt = <168400>; ++ lltc,fb-voltage-divider = <221000 200000>; ++ regulator-ramp-delay = <7000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ /* unused */ ++ ldo1_reg: ldo1 { ++ regulator-min-microvolt = <0>; ++ regulator-max-microvolt = <0>; ++ lltc,fb-voltage-divider = <0 0>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo2_reg: ldo2 { ++ regulator-min-microvolt = <2490375>; ++ regulator-max-microvolt = <2490375>; ++ lltc,fb-voltage-divider = <487000 200000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo3_reg: ldo3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ }; ++ ++ ldo4_reg: ldo4 { ++ regulator-min-microvolt = <3023250>; ++ regulator-max-microvolt = <3023250>; ++ lltc,fb-voltage-divider = <634000 200000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ }; ++ }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/regulator/pfuze100.txt linux-3.14.72/Documentation/devicetree/bindings/regulator/pfuze100.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/regulator/pfuze100.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/regulator/pfuze100.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -1,7 +1,7 @@ + PFUZE100 family of regulators + + Required properties: +-- compatible: "fsl,pfuze100" ++- compatible: "fsl,pfuze100" or "fsl,pfuze200" + - reg: I2C slave address + + Required child node: +@@ -10,11 +10,14 @@ + Documentation/devicetree/bindings/regulator/regulator.txt. + + The valid names for regulators are: ++ --PFUZE100 + sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 ++ --PFUZE200 ++ sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6 + + Each regulator is defined using the standard binding for regulators. + +-Example: ++Example 1: PFUZE100 + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; +@@ -63,6 +66,95 @@ + }; + + 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; ++ }; ++ }; ++ }; ++ ++ ++Example 2: PFUZE200 ++ ++ pmic: pfuze200@08 { ++ compatible = "fsl,pfuze200"; ++ reg = <0x08>; ++ ++ regulators { ++ sw1a_reg: sw1ab { ++ 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; ++ }; ++ ++ swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/reset/gpio-reset.txt linux-3.14.72/Documentation/devicetree/bindings/reset/gpio-reset.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/reset/gpio-reset.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/reset/gpio-reset.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -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.72.orig/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt linux-3.14.72/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,14 @@ ++NXP Semiconductors PCF8523 Real Time Clock ++ ++Required properties: ++- compatible: should be: "nxp,pcf8523" ++- reg: i2c address ++- nxp,12p5_pf: force autodetection to start at 12.5 pf instead of 7pf ++ ++Example: ++ ++rtc: pcf8523@68 { ++ compatible = "nxp,pcf8523"; ++ reg = <0x68>; ++ nxp,12p5_pf; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/cs42xx8.txt linux-3.14.72/Documentation/devicetree/bindings/sound/cs42xx8.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/cs42xx8.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/cs42xx8.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,28 @@ ++CS42448/CS42888 audio CODEC ++ ++Required properties: ++ ++ - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888" ++ ++ - reg : the I2C address of the device for I2C ++ ++ - clocks : a list of phandles + clock-specifiers, one for each entry in ++ clock-names ++ ++ - clock-names : must contain "mclk" ++ ++ - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device, ++ as covered in Documentation/devicetree/bindings/regulator/regulator.txt ++ ++Example: ++ ++codec: cs42888@48 { ++ compatible = "cirrus,cs42888"; ++ reg = <0x48>; ++ clocks = <&codec_mclk 0>; ++ clock-names = "mclk"; ++ VA-supply = <®_audio>; ++ VD-supply = <®_audio>; ++ VLS-supply = <®_audio>; ++ VLC-supply = <®_audio>; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,asrc.txt linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,asrc.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,asrc.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,asrc.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,60 @@ ++Freescale Asynchronous Sample Rate Converter (ASRC) Controller ++ ++The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a ++signal associated with an input clock into a signal associated with a different ++output clock. The driver currently works as a Front End of DPCM with other Back ++Ends Audio controller such as ESAI, SSI and SAI. It has three pairs to support ++three substreams within totally 10 channels. ++ ++Required properties: ++ ++ - compatible : Contains "fsl,imx35-asrc" or "fsl,imx53-asrc". ++ ++ - reg : Offset and length of the register set for the device. ++ ++ - interrupts : Contains the spdif interrupt. ++ ++ - dmas : Generic dma devicetree binding as described in ++ Documentation/devicetree/bindings/dma/dma.txt. ++ ++ - dma-names : Contains "rxa", "rxb", "rxc", "txa", "txb" and "txc". ++ ++ - clocks : Contains an entry for each entry in clock-names. ++ ++ - clock-names : Contains the following entries ++ "mem" Peripheral access clock to access registers. ++ "ipg" Peripheral clock to driver module. ++ "asrck_<0-f>" Clock sources for input and output clock. ++ ++ - big-endian : If this property is absent, the little endian mode ++ will be in use as default. Otherwise, the big endian ++ mode will be in use for all the device registers. ++ ++ - fsl,asrc-rate : Defines a mutual sample rate used by DPCM Back Ends. ++ ++ - fsl,asrc-width : Defines a mutual sample width used by DPCM Back Ends. ++ ++Example: ++ ++asrc: asrc@02034000 { ++ compatible = "fsl,imx53-asrc"; ++ reg = <0x02034000 0x4000>; ++ interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 107>, <&clks 107>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks 107>, <&clks 0>, <&clks 0>; ++ clock-names = "mem", "ipg", "asrck0", ++ "asrck_1", "asrck_2", "asrck_3", "asrck_4", ++ "asrck_5", "asrck_6", "asrck_7", "asrck_8", ++ "asrck_9", "asrck_a", "asrck_b", "asrck_c", ++ "asrck_d", "asrck_e", "asrck_f"; ++ dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, ++ <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; ++ dma-names = "rxa", "rxb", "rxc", ++ "txa", "txb", "txc"; ++ fsl,asrc-rate = <48000>; ++ fsl,asrc-width = <16>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,esai.txt linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,esai.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,esai.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,esai.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -34,6 +34,10 @@ + that ESAI would work in the synchronous mode, which means all the settings + for Receiving would be duplicated from Transmition related registers. + ++ - big-endian : If this property is absent, the native endian mode will ++ be in use as default, or the big endian mode will be in use for all the ++ device registers. ++ + Example: + + esai: esai@02024000 { +@@ -46,5 +50,6 @@ + dma-names = "rx", "tx"; + fsl,fifo-depth = <128>; + fsl,esai-synchronous; ++ big-endian; + status = "disabled"; + }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,mqs.txt linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,mqs.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,mqs.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,mqs.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,22 @@ ++fsl,mqs audio CODEC ++ ++Required properties: ++ ++ - compatible : must contain one of "fsl,imx6sx-mqs" and "fsl,codec-mqs" ++ ++ - clocks : a list of phandles + clock-specifiers, one for each entry in ++ clock-names ++ ++ - clock-names : must contain "mclk" ++ ++ - gpr : the gpr node. ++ ++Example: ++ ++mqs: mqs { ++ compatible = "fsl,imx6sx-mqs"; ++ gpr = <&gpr>; ++ clocks = <&clks IMX6SX_CLK_SAI1>; ++ clock-names = "mclk"; ++ status = "disabled"; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl-sai.txt linux-3.14.72/Documentation/devicetree/bindings/sound/fsl-sai.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl-sai.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/fsl-sai.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -7,22 +7,37 @@ + + + Required properties: +-- compatible: Compatible list, contains "fsl,vf610-sai". ++- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai". + - reg: Offset and length of the register set for the device. + - clocks: Must contain an entry for each entry in clock-names. +-- clock-names : Must include the "sai" entry. ++- clock-names : Must include the "bus" for register access and "mclk1" "mclk2" ++ "mclk3" for bit clock and frame clock providing. + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + - dma-names : Two dmas have to be defined, "tx" and "rx". + - pinctrl-names: Must contain a "default" entry. + - pinctrl-NNN: One property must exist for each entry in pinctrl-names. + See ../pinctrl/pinctrl-bindings.txt for details of the property values. +-- big-endian-regs: If this property is absent, the little endian mode will +- be in use as default, or the big endian mode will be in use for all the +- device registers. +-- big-endian-data: If this property is absent, the little endian mode will +- be in use as default, or the big endian mode will be in use for all the +- fifo data. ++- big-endian: Boolean property, required if all the FTM_PWM registers ++ are big-endian rather than little-endian. ++- lsb-first: Configures whether the LSB or the MSB is transmitted first for ++ the fifo data. If this property is absent, the MSB is transmitted first as ++ default, or the LSB is transmitted first. ++- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating ++ that SAI will work in the synchronous mode (sync Tx with Rx) which means ++ both the transimitter and receiver will send and receive data by following ++ receiver's bit clocks and frame sync clocks. ++- fsl,sai-asynchronous: This is a boolean property. If present, indicating ++ that SAI will work in the asynchronous mode, which means both transimitter ++ and receiver will send and receive data by following their own bit clocks ++ and frame sync clocks separately. ++ ++Note: ++- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the ++ default synchronous mode (sync Rx with Tx) will be used, which means both ++ transimitter and receiver will send and receive data by following clocks ++ of transimitter. ++- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive. + + Example: + sai2: sai@40031000 { +@@ -30,11 +45,13 @@ + reg = <0x40031000 0x1000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2_1>; +- clocks = <&clks VF610_CLK_SAI2>; +- clock-names = "sai"; ++ clocks = <&clks VF610_CLK_PLATFORM_BUS>, ++ <&clks VF610_CLK_SAI2>, ++ <&clks 0>, <&clks 0>; ++ clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dma-names = "tx", "rx"; + dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, + <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; +- big-endian-regs; +- big-endian-data; ++ big-endian; ++ lsb-first; + }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,spdif.txt linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,spdif.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/fsl,spdif.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/fsl,spdif.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -29,6 +29,10 @@ + can also be referred to TxClk_Source + bit of register SPDIF_STC. + ++ - big-endian : If this property is absent, the native endian mode will ++ be in use as default, or the big endian mode will be in use for all the ++ device registers. ++ + Example: + + spdif: spdif@02004000 { +@@ -50,5 +54,6 @@ + "rxtx5", "rxtx6", + "rxtx7"; + ++ big-endian; + status = "okay"; + }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -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.72.orig/Documentation/devicetree/bindings/sound/imx-audio-mqs.txt linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-mqs.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-mqs.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-mqs.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,18 @@ ++Freescale i.MX audio complex with mqs codec ++ ++Required properties: ++- compatible : "fsl,imx-audio-mqs" ++- model : The user-visible name of this sound complex ++- cpu-dai : The phandle of the i.MX sai controller ++- audio-codec : The phandle of the mqs audio codec ++ ++Example: ++ ++sound-mqs { ++ compatible = "fsl,imx6sx-sdb-mqs", ++ "fsl,imx-audio-mqs"; ++ model = "mqs-audio"; ++ cpu-dai = <&sai1>; ++ audio-codec = <&mqs>; ++}; ++ +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -3,7 +3,7 @@ + Required properties: + - compatible : "fsl,imx-audio-sgtl5000" + - model : The user-visible name of this sound complex +-- ssi-controller : The phandle of the i.MX SSI controller ++- cpu-dai : The phandle of CPU dai + - audio-codec : The phandle of the SGTL5000 audio codec + - audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, +@@ -38,7 +38,7 @@ + compatible = "fsl,imx51-babbage-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx51-babbage-sgtl5000"; +- ssi-controller = <&ssi1>; ++ cpu-dai = <&ssi1>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -0,0 +1,24 @@ ++Freescale i.MX audio complex with si476x codec ++ ++Required properties: ++- compatible : "fsl,imx-audio-si476x" ++- model : The user-visible name of this sound complex ++- ssi-controller : The phandle of the i.MX SSI controller ++ ++- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) ++- mux-ext-port : The external port of the i.MX audio muxer ++ ++Note: The AUDMUX port numbering should start at 1, which is consistent with ++hardware manual. ++ ++Example: ++ ++sound { ++ compatible = "fsl,imx-audio-si476x", ++ "fsl,imx-tuner-si476x"; ++ model = "imx-radio-si476x"; ++ ++ ssi-controller = <&ssi1>; ++ mux-int-port = <2>; ++ mux-ext-port = <5>; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt 2016-06-19 22:11:55.077154974 +0200 +@@ -3,7 +3,7 @@ + Required properties: + - compatible : "fsl,imx-audio-wm8962" + - model : The user-visible name of this sound complex +-- ssi-controller : The phandle of the i.MX SSI controller ++- cpu-dai : The phandle of CPU DAI + - audio-codec : The phandle of the WM8962 audio codec + - audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, +@@ -24,13 +24,19 @@ + Note: The AUDMUX port numbering should start at 1, which is consistent with + hardware manual. + ++Optional properties: ++- hp-det-gpios : The gpio pin to detect plug in/out event that happens to ++ Headphone jack. ++- mic-det-gpios: The gpio pin to detect plug in/out event that happens to ++ Microphone jack. ++ + Example: + + sound { + compatible = "fsl,imx6q-sabresd-wm8962", + "fsl,imx-audio-wm8962"; + model = "wm8962-audio"; +- ssi-controller = <&ssi2>; ++ cpu-dai = <&ssi2>; + audio-codec = <&codec>; + audio-routing = + "Headphone Jack", "HPOUTL", +@@ -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.72.orig/Documentation/devicetree/bindings/sound/wm8960.txt linux-3.14.72/Documentation/devicetree/bindings/sound/wm8960.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/wm8960.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/wm8960.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -0,0 +1,31 @@ ++WM8960 audio CODEC ++ ++This device supports I2C only. ++ ++Required properties: ++ ++ - compatible : "wlf,wm8960" ++ ++ - reg : the I2C address of the device. ++ ++Optional properties: ++ - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of ++ R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins ++ will be disabled only when ADC (Left and Right) and DAC (Left and Right) ++ are disabled. ++ When wm8960 works on synchronize mode and DACLRC pin is used to supply ++ frame clock, it will no frame clock for captrue unless enable DAC to enable ++ DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue. ++ ++ - wlf,capless: This is a boolean property. If present, OUT3 pin will be ++ enabled and disabled together with HP_L and HP_R pins in response to jack ++ detect events. ++ ++Example: ++ ++codec: wm8960@1a { ++ compatible = "wlf,wm8960"; ++ reg = <0x1a>; ++ ++ wlf,shared-lrclk; ++}; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/sound/wm8962.txt linux-3.14.72/Documentation/devicetree/bindings/sound/wm8962.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/sound/wm8962.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/sound/wm8962.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -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.72.orig/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt linux-3.14.72/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -7,6 +7,9 @@ + - interrupts : Should contain CSPI/eCSPI interrupt + - fsl,spi-num-chipselects : Contains the number of the chipselect + - cs-gpios : Specifies the gpio pins to be used for chipselects. ++- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, ++ Documentation/devicetree/bindings/dma/dma.txt ++- dma-names: DMA request names should include "tx" and "rx" if present. + + Example: + +@@ -19,4 +22,6 @@ + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */ + <&gpio3 25 0>; /* GPIO3_25 */ ++ dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; ++ dma-names = "rx", "tx"; + }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/spi/spi-bus.txt linux-3.14.72/Documentation/devicetree/bindings/spi/spi-bus.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/spi/spi-bus.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/spi/spi-bus.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -55,6 +55,8 @@ + chip select active high + - spi-3wire - (optional) Empty property indicating device requires + 3-wire mode. ++- spi-lsb-first - (optional) Empty property indicating device requires ++ LSB first mode. + - spi-tx-bus-width - (optional) The bus width(number of data wires) that + used for MOSI. Defaults to 1 if not present. + - spi-rx-bus-width - (optional) The bus width(number of data wires) that +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt linux-3.14.72/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -4,6 +4,7 @@ + - compatible: Should be "fsl,imx27-usb" + - reg: Should contain registers location and length + - interrupts: Should contain controller interrupt ++- fsl,usbphy: phandle of usb phy that connects to the port + + Recommended properies: + - phy_type: the type of the phy connected to the core. Should be one +@@ -12,12 +13,25 @@ + - dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" + + Optional properties: +-- fsl,usbphy: phandler of usb phy that connects to the only one port + - fsl,usbmisc: phandler of non-core register device, with one argument + that indicate usb controller index + - vbus-supply: regulator for vbus + - disable-over-current: disable over current detect + - external-vbus-divider: enables off-chip resistor divider for Vbus ++- imx6-usb-charger-detection: enable imx6 usb charger detect function, ++ only set it when the user wants SoC usb charger detection capabilities. ++ If the user wants to use charger IC's usb charger detection capabilities, ++ please do not set it. ++- fsl,anatop: phandle for anatop module, anatop module is only existed ++ at imx6 SoC series. ++- pinctrl-names: for names of hsic pin group ++- pinctrl-0: hsic "idle" pin group ++- pinctrl-1: hsic "active" pin group ++- osc-clkgate-delay: the delay between powering up the xtal 24MHz clock ++ and release the clock to the digital logic inside the analog block, ++ 0 <= osc-clkgate-delay <= 7. ++- maximum-speed: limit the maximum connection speed to "full-speed". ++- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts + + Examples: + usb@02184000 { /* USB OTG */ +@@ -28,4 +42,12 @@ + fsl,usbmisc = <&usbmisc 0>; + disable-over-current; + external-vbus-divider; ++ imx6-usb-charger-detection; ++ fsl,anatop = <&anatop>; ++ pinctrl-names = "idle", "active"; ++ pinctrl-0 = <&pinctrl_usbh2_1>; ++ pinctrl-1 = <&pinctrl_usbh2_2>; ++ osc-clkgate-delay = <0x3>; ++ maximum-speed = "full-speed"; ++ tpl-support; + }; +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/usb/mxs-phy.txt linux-3.14.72/Documentation/devicetree/bindings/usb/mxs-phy.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/usb/mxs-phy.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/usb/mxs-phy.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -1,13 +1,21 @@ + * Freescale MXS USB Phy Device + + Required properties: +-- compatible: Should be "fsl,imx23-usbphy" ++- compatible: should contain: ++ * "fsl,imx23-usbphy" for imx23 and imx28 ++ * "fsl,imx6q-usbphy" for imx6dq and imx6dl ++ * "fsl,imx6sl-usbphy" for imx6sl ++ * "fsl,vf610-usbphy" for Vybrid vf610 ++ * "fsl,imx6sx-usbphy" for imx6sx ++ "fsl,imx23-usbphy" is still a fallback for other strings + - 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.72.orig/Documentation/devicetree/bindings/usb/usbmisc-imx.txt linux-3.14.72/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/usb/usbmisc-imx.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/usb/usbmisc-imx.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -4,6 +4,8 @@ + - #index-cells: Cells used to descibe usb controller index. Should be <1> + - compatible: Should be one of below: + "fsl,imx6q-usbmisc" for imx6q ++ "fsl,vf610-usbmisc" for Vybrid vf610 ++ "fsl,imx6sx-usbmisc" for imx6sx + - reg: Should contain registers location and length + + Examples: +diff -Nur linux-3.14.72.orig/Documentation/devicetree/bindings/vendor-prefixes.txt linux-3.14.72/Documentation/devicetree/bindings/vendor-prefixes.txt +--- linux-3.14.72.orig/Documentation/devicetree/bindings/vendor-prefixes.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/devicetree/bindings/vendor-prefixes.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -22,6 +22,7 @@ + capella Capella Microsystems, Inc + cavium Cavium, Inc. + cdns Cadence Design Systems Inc. ++chipidea Chipidea, Inc + chrp Common Hardware Reference Platform + chunghwa Chunghwa Picture Tubes Ltd. + cirrus Cirrus Logic, Inc. +@@ -29,6 +30,7 @@ + dallas Maxim Integrated Products (formerly Dallas Semiconductor) + davicom DAVICOM Semiconductor, Inc. + denx Denx Software Engineering ++eeti EGalax_eMPIA Technology, Inc. + edt Emerging Display Technologies + emmicro EM Microelectronic + epfl Ecole Polytechnique Fédérale de Lausanne +diff -Nur linux-3.14.72.orig/Documentation/DocBook/media/v4l/subdev-formats.xml linux-3.14.72/Documentation/DocBook/media/v4l/subdev-formats.xml +--- linux-3.14.72.orig/Documentation/DocBook/media/v4l/subdev-formats.xml 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/DocBook/media/v4l/subdev-formats.xml 2016-06-19 22:11:55.081154709 +0200 +@@ -1898,6 +1898,134 @@ + y1 + y0 + ++ ++ V4L2_MBUS_FMT_UYVY10_2X10 ++ 0x2018 ++ ++ &dash-ent-22; ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ ++ ++ ++ ++ ++ &dash-ent-22; ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-22; ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ ++ ++ ++ &dash-ent-22; ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ V4L2_MBUS_FMT_VYUY10_2X10 ++ 0x2019 ++ ++ &dash-ent-22; ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ ++ ++ ++ &dash-ent-22; ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-22; ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ ++ ++ ++ ++ ++ &dash-ent-22; ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ + + V4L2_MBUS_FMT_YUYV10_2X10 + 0x200b +@@ -2308,6 +2436,110 @@ + v1 + v0 + ++ ++ V4L2_MBUS_FMT_UYVY10_1X20 ++ 0x201a ++ ++ &dash-ent-12; ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-12; ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ V4L2_MBUS_FMT_VYUY10_1X20 ++ 0x201b ++ ++ &dash-ent-12; ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-12; ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ + + V4L2_MBUS_FMT_YUYV10_1X20 + 0x200d +@@ -2486,6 +2718,534 @@ + v1 + v0 + ++ ++ V4L2_MBUS_FMT_UYVY12_2X12 ++ 0x201c ++ ++ &dash-ent-20; ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ V4L2_MBUS_FMT_VYUY12_2X12 ++ 0x201d ++ ++ &dash-ent-20; ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ V4L2_MBUS_FMT_YUYV12_2X12 ++ 0x201e ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ V4L2_MBUS_FMT_YVYU12_2X12 ++ 0x201f ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-20; ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ ++ ++ V4L2_MBUS_FMT_UYVY12_1X24 ++ 0x2020 ++ ++ &dash-ent-8; ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-8; ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ V4L2_MBUS_FMT_VYUY12_1X24 ++ 0x2021 ++ ++ &dash-ent-8; ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ ++ ++ ++ &dash-ent-8; ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ ++ ++ V4L2_MBUS_FMT_YUYV12_1X24 ++ 0x2022 ++ ++ &dash-ent-8; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ ++ ++ ++ ++ ++ &dash-ent-8; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ V4L2_MBUS_FMT_YVYU12_1X24 ++ 0x2023 ++ ++ &dash-ent-8; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ v11 ++ v10 ++ v9 ++ v8 ++ v7 ++ v6 ++ v5 ++ v4 ++ v3 ++ v2 ++ v1 ++ v0 ++ ++ ++ ++ ++ ++ &dash-ent-8; ++ y11 ++ y10 ++ y9 ++ y8 ++ y7 ++ y6 ++ y5 ++ y4 ++ y3 ++ y2 ++ y1 ++ y0 ++ u11 ++ u10 ++ u9 ++ u8 ++ u7 ++ u6 ++ u5 ++ u4 ++ u3 ++ u2 ++ u1 ++ u0 ++ + + + +diff -Nur linux-3.14.72.orig/Documentation/kernel-parameters.txt linux-3.14.72/Documentation/kernel-parameters.txt +--- linux-3.14.72.orig/Documentation/kernel-parameters.txt 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/Documentation/kernel-parameters.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -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 + +@@ -2538,6 +2541,13 @@ + + pcmv= [HW,PCMCIA] BadgePAD 4 + ++ pd_ignore_unused ++ [PM] ++ Keep all power-domains already enabled by bootloader on, ++ even if no driver has claimed them. This is useful ++ for debug and development, but should not be ++ needed on a platform with proper driver support. ++ + pd. [PARIDE] + See Documentation/blockdev/paride.txt. + +diff -Nur linux-3.14.72.orig/Documentation/mtd/spi-nor.txt linux-3.14.72/Documentation/mtd/spi-nor.txt +--- linux-3.14.72.orig/Documentation/mtd/spi-nor.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/mtd/spi-nor.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -0,0 +1,62 @@ ++ SPI NOR framework ++ ============================================ ++ ++Part I - Why do we need this framework? ++--------------------------------------- ++ ++SPI bus controllers (drivers/spi/) only deal with streams of bytes; the bus ++controller operates agnostic of the specific device attached. However, some ++controllers (such as Freescale's QuadSPI controller) cannot easily handle ++arbitrary streams of bytes, but rather are designed specifically for SPI NOR. ++ ++In particular, Freescale's QuadSPI controller must know the NOR commands to ++find the right LUT sequence. Unfortunately, the SPI subsystem has no notion of ++opcodes, addresses, or data payloads; a SPI controller simply knows to send or ++receive bytes (Tx and Rx). Therefore, we must define a new layering scheme under ++which the controller driver is aware of the opcodes, addressing, and other ++details of the SPI NOR protocol. ++ ++Part II - How does the framework work? ++-------------------------------------- ++ ++This framework just adds a new layer between the MTD and the SPI bus driver. ++With this new layer, the SPI NOR controller driver does not depend on the ++m25p80 code anymore. ++ ++ Before this framework, the layer is like: ++ ++ MTD ++ ------------------------ ++ m25p80 ++ ------------------------ ++ SPI bus driver ++ ------------------------ ++ SPI NOR chip ++ ++ After this framework, the layer is like: ++ MTD ++ ------------------------ ++ SPI NOR framework ++ ------------------------ ++ m25p80 ++ ------------------------ ++ SPI bus driver ++ ------------------------ ++ SPI NOR chip ++ ++ With the SPI NOR controller driver (Freescale QuadSPI), it looks like: ++ MTD ++ ------------------------ ++ SPI NOR framework ++ ------------------------ ++ fsl-quadSPI ++ ------------------------ ++ SPI NOR chip ++ ++Part III - How can drivers use the framework? ++--------------------------------------------- ++ ++The main API is spi_nor_scan(). Before you call the hook, a driver should ++initialize the necessary fields for spi_nor{}. Please see ++drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c ++when you want to write a new driver for a SPI NOR controller. +diff -Nur linux-3.14.72.orig/Documentation/tda1997x linux-3.14.72/Documentation/tda1997x +--- linux-3.14.72.orig/Documentation/tda1997x 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/tda1997x 2016-06-19 22:11:55.081154709 +0200 +@@ -0,0 +1,31 @@ ++The NXP TDA19971/19972 are HDMI receiver devices that decode HDMI ++input signals and present a configurable parallel video output bus and ++audio output bus. The internal video bus is 36bits while the output bus ++differs per device. These devices offer High Definition (HD) video resolutions ++up to 1080p50/60 or WUXGA and HD audio formats up to 8 channels such as DTS HD ++and Dolby True HD. The chips optionally include an HDCP 1.4 engine with ++pre-programmed keys stored into an internal NV memory. Additionally the chips ++also supports several HDMI 1.4b options such as 3D formats up to 1080p50/60, ++Deep Colors up to 36bpp and extended colorimetry. ++ ++The TDA19971 has one HDMI input (HDMI-A) and 24bit output bus and the TDA19972 ++has two HDMI inputs (HDMI-A/B) and a 36bit video output bus. ++ ++Driver Details: ++--------------- ++ ++The chips respond to two i2c slave addresses, the first allows access to ++HDMI input, audio, and video status and configuration and the second allows ++access to CEC. ++ ++The tda1997x-core driver attaches to the i2c slave that controls the device. ++It also manages the 2nd i2c slave for CEC. The platform data structure ++provides details about the desired video output bus configuration and the ++desired audio output bus configuration. An ASoC codec driver is also provided ++however this is merely a skeleton driver as the audio output format cannot ++be changed and is dependent upon the HDMI input signal. A separate platform ++specific device video driver can interact with the core to obtain information ++about the video data format which is dependent upon the HDMI input signal. A ++separate platform specific ASoC SoC DAI driver can interact with the core ++to obtain information about the audio data format which is dependent upon ++the HDMI input signal. +diff -Nur linux-3.14.72.orig/Documentation/usb/chipidea.txt linux-3.14.72/Documentation/usb/chipidea.txt +--- linux-3.14.72.orig/Documentation/usb/chipidea.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/Documentation/usb/chipidea.txt 2016-06-19 22:11:55.081154709 +0200 +@@ -0,0 +1,98 @@ ++1. How to test OTG FSM(HNP and SRP) ++----------------------------------- ++To show how to demo OTG HNP and SRP functions via sys input files ++with 2 Freescale i.MX6Q sabre SD boards. ++ ++1.1 How to enable OTG FSM in menuconfig ++--------------------------------------- ++Select CONFIG_USB_OTG_FSM, rebuild kernel Image and modules. ++If you want to check some internal variables for otg fsm, ++select CONFIG_USB_CHIPIDEA_DEBUG, there are 2 files which ++can show otg fsm variables and some controller registers value: ++cat /sys/kernel/debug/ci_hdrc.0/otg ++cat /sys/kernel/debug/ci_hdrc.0/registers ++ ++1.2 Test operations ++------------------- ++1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded ++ (e.g. g_mass_storage). ++ ++2) Connect 2 boards with usb cable with one end is micro A plug, the other end ++ is micro B plug. ++ ++ The A-device(with micro A plug inserted) should enumrate B-device. ++ ++3) Role switch ++ On B-device: ++ echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req ++ ++ B-device should take host role and enumrate A-device. ++ ++4) A-device switch back to host. ++ On A-device: ++ echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req ++ ++ or, on B-device: ++ echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req ++ ++ A-device should switch back to host and enumrate B-device. ++ ++5) Remove B-device(unplug micro B plug) and insert again in 10 seconds, ++ A-device should enumrate B-device again. ++ ++6) Remove B-device(unplug micro B plug) and insert again after 10 seconds, ++ A-device should NOT enumrate B-device. ++ ++ if A-device wants to use bus: ++ On A-device: ++ echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop ++ echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req ++ ++ if B-device wants to use bus: ++ On B-device: ++ echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req ++ ++7) A-device power down the bus. ++ On A-device: ++ echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop ++ ++ A-device should disconnect with B-device and power down the bus. ++ ++8) B-device does data pulse for SRP. ++ On B-device: ++ echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req ++ ++ A-device should resume usb bus and enumrate B-device. ++ ++1.3 Reference document ++---------------------- ++"On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification ++July 27, 2012 Revision 2.0 version 1.1a" ++ ++1.4 OTG compliance test ++---------------------- ++Only below 3 popular gadget drivers are declared to be USB OTG and EH 2.0 ++compliant(with otg descriptor comply with USB OTG and EH 2.0 as a peripheral): ++- mass storage ++- ether ++- serial ++ ++2. How to enable USB as system wakeup source ++----------------------------------- ++Below is the example for how to enable USB as system wakeup source ++at imx6 platform. ++ ++2.1 Enable core's wakeup ++echo enabled > /sys/bus/platform/devices/ci_hdrc.0/power/wakeup ++2.2 Enable glue layer's wakeup ++echo enabled > /sys/bus/platform/devices/2184000.usb/power/wakeup ++2.3 Enable PHY's wakeup (optional) ++echo enabled > /sys/bus/platform/devices/20c9000.usbphy/power/wakeup ++2.4 Enable roothub's wakeup ++echo enabled > /sys/bus/usb/devices/usb1/power/wakeup ++2.5 Enable related device's wakeup ++echo enabled > /sys/bus/usb/devices/1-1/power/wakeup ++ ++If the system has only one usb port, and you want usb wakeup at this port, you ++can use below script to enable usb wakeup. ++for i in $(find /sys -name wakeup | grep usb);do echo enabled > $i;done; +diff -Nur linux-3.14.72.orig/drivers/acpi/device_pm.c linux-3.14.72/drivers/acpi/device_pm.c +--- linux-3.14.72.orig/drivers/acpi/device_pm.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/acpi/device_pm.c 2016-06-19 22:11:55.081154709 +0200 +@@ -987,6 +987,8 @@ + acpi_dev_pm_full_power(adev); + __acpi_device_run_wake(adev, false); + } ++ ++ dev->pm_domain->detach = acpi_dev_pm_detach; + return 0; + } + EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); +diff -Nur linux-3.14.72.orig/drivers/ata/acard-ahci.c linux-3.14.72/drivers/ata/acard-ahci.c +--- linux-3.14.72.orig/drivers/ata/acard-ahci.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/acard-ahci.c 2016-06-19 22:11:55.081154709 +0200 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -78,7 +77,7 @@ + static int acard_ahci_port_start(struct ata_port *ap); + static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); + static int acard_ahci_pci_device_resume(struct pci_dev *pdev); + #endif +@@ -119,13 +118,13 @@ + .id_table = acard_ahci_pci_tbl, + .probe = acard_ahci_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = acard_ahci_pci_device_suspend, + .resume = acard_ahci_pci_device_resume, + #endif + }; + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -442,7 +441,7 @@ + hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; + + /* save initial config */ +- ahci_save_initial_config(&pdev->dev, hpriv, 0, 0); ++ ahci_save_initial_config(&pdev->dev, hpriv); + + /* prepare host */ + if (hpriv->cap & HOST_CAP_NCQ) +diff -Nur linux-3.14.72.orig/drivers/ata/ahci.c linux-3.14.72/drivers/ata/ahci.c +--- linux-3.14.72.orig/drivers/ata/ahci.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/ahci.c 2016-06-19 22:11:55.081154709 +0200 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -574,8 +573,7 @@ + "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n"); + } + +- ahci_save_initial_config(&pdev->dev, hpriv, force_port_map, +- mask_port_map); ++ ahci_save_initial_config(&pdev->dev, hpriv); + } + + static int ahci_pci_reset_controller(struct ata_host *host) +@@ -630,6 +628,7 @@ + unsigned long deadline) + { + struct ata_port *ap = link->ap; ++ struct ahci_host_priv *hpriv = ap->host->private_data; + bool online; + int rc; + +@@ -640,7 +639,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); + +@@ -655,6 +654,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; +@@ -670,7 +670,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 +@@ -1243,6 +1243,13 @@ + + /* fallback to single MSI mode if the controller enforced MRSM mode */ + if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) { ++ pci_disable_msi(pdev); ++ printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n"); ++ goto single_msi; ++ } ++ ++ /* fallback to single MSI mode if the controller enforced MRSM mode */ ++ if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) { + pci_disable_msi(pdev); + printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n"); + goto single_msi; +diff -Nur linux-3.14.72.orig/drivers/ata/ahci_da850.c linux-3.14.72/drivers/ata/ahci_da850.c +--- linux-3.14.72.orig/drivers/ata/ahci_da850.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/ata/ahci_da850.c 2016-06-19 22:11:55.081154709 +0200 +@@ -0,0 +1,114 @@ ++/* ++ * DaVinci DA850 AHCI SATA platform driver ++ * ++ * 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 "ahci.h" ++ ++/* SATA PHY Control Register offset from AHCI base */ ++#define SATA_P0PHYCR_REG 0x178 ++ ++#define SATA_PHY_MPY(x) ((x) << 0) ++#define SATA_PHY_LOS(x) ((x) << 6) ++#define SATA_PHY_RXCDR(x) ((x) << 10) ++#define SATA_PHY_RXEQ(x) ((x) << 13) ++#define SATA_PHY_TXSWING(x) ((x) << 19) ++#define SATA_PHY_ENPLL(x) ((x) << 31) ++ ++/* ++ * The multiplier needed for 1.5GHz PLL output. ++ * ++ * NOTE: This is currently hardcoded to be suitable for 100MHz crystal ++ * frequency (which is used by DA850 EVM board) and may need to be changed ++ * if you would like to use this driver on some other board. ++ */ ++#define DA850_SATA_CLK_MULTIPLIER 7 ++ ++static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg, ++ void __iomem *ahci_base) ++{ ++ unsigned int val; ++ ++ /* Enable SATA clock receiver */ ++ val = readl(pwrdn_reg); ++ val &= ~BIT(0); ++ writel(val, pwrdn_reg); ++ ++ val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) | ++ SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) | ++ SATA_PHY_ENPLL(1); ++ ++ writel(val, ahci_base + SATA_P0PHYCR_REG); ++} ++ ++static const struct ata_port_info ahci_da850_port_info = { ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_platform_ops, ++}; ++ ++static int ahci_da850_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ahci_host_priv *hpriv; ++ struct resource *res; ++ void __iomem *pwrdn_reg; ++ int rc; ++ ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ rc = ahci_platform_enable_resources(hpriv); ++ if (rc) ++ return rc; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!res) ++ goto disable_resources; ++ ++ pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res)); ++ if (!pwrdn_reg) ++ goto disable_resources; ++ ++ da850_sata_init(dev, pwrdn_reg, hpriv->mmio); ++ ++ rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info); ++ if (rc) ++ goto disable_resources; ++ ++ return 0; ++disable_resources: ++ ahci_platform_disable_resources(hpriv); ++ return rc; ++} ++ ++static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend, ++ ahci_platform_resume); ++ ++static struct platform_driver ahci_da850_driver = { ++ .probe = ahci_da850_probe, ++ .remove = ata_platform_remove_one, ++ .driver = { ++ .name = "ahci_da850", ++ .owner = THIS_MODULE, ++ .pm = &ahci_da850_pm_ops, ++ }, ++}; ++module_platform_driver(ahci_da850_driver); ++ ++MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver"); ++MODULE_AUTHOR("Bartlomiej Zolnierkiewicz "); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/ata/ahci.h linux-3.14.72/drivers/ata/ahci.h +--- linux-3.14.72.orig/drivers/ata/ahci.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/ahci.h 2016-06-19 22:11:55.085154441 +0200 +@@ -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 = 4, + AHCI_MAX_SG = 168, /* hardware max is 64K */ + AHCI_DMA_BOUNDARY = 0xffffffff, + AHCI_MAX_CMDS = 32, +@@ -233,6 +236,7 @@ + port start (wait until + error-handling stage) */ + AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */ ++ AHCI_HFLAG_NO_FBS = (1 << 17), /* no FBS */ + + /* ap->flags bits */ + +@@ -311,8 +315,12 @@ + }; + + struct ahci_host_priv { +- void __iomem * mmio; /* bus-independent mem map */ ++ /* Input fields */ + unsigned int flags; /* AHCI_HFLAG_* */ ++ u32 force_port_map; /* force port map */ ++ u32 mask_port_map; /* mask out particular bits */ ++ ++ void __iomem * mmio; /* bus-independent mem map */ + u32 cap; /* cap to use */ + u32 cap2; /* cap2 to use */ + u32 port_map; /* port map to use */ +@@ -322,8 +330,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; +@@ -347,9 +364,7 @@ + void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, + u32 opts); + void ahci_save_initial_config(struct device *dev, +- struct ahci_host_priv *hpriv, +- unsigned int force_port_map, +- unsigned int mask_port_map); ++ struct ahci_host_priv *hpriv); + void ahci_init_controller(struct ata_host *host); + int ahci_reset_controller(struct ata_host *host); + +@@ -357,7 +372,9 @@ + int pmp, unsigned long deadline, + int (*check_ready)(struct ata_link *link)); + ++unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); + int ahci_stop_engine(struct ata_port *ap); ++void ahci_start_fis_rx(struct ata_port *ap); + void ahci_start_engine(struct ata_port *ap); + int ahci_check_ready(struct ata_link *link); + int ahci_kick_engine(struct ata_port *ap); +diff -Nur linux-3.14.72.orig/drivers/ata/ahci_imx.c linux-3.14.72/drivers/ata/ahci_imx.c +--- linux-3.14.72.orig/drivers/ata/ahci_imx.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/ahci_imx.c 2016-06-19 22:11:55.085154441 +0200 +@@ -29,9 +29,25 @@ + #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 +58,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_clk; + 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) ++{ ++ u32 crval = addr; ++ int 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; ++ } ++ ++ /* 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) + { +- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++ void __iomem *mmio = hpriv->mmio; ++ int timeout = 10; ++ u16 val; + 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); ++ /* 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; +- } + } + + 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; +- } ++ 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_clk; ++ } + } + + usleep_range(1000, 2000); + + return 0; + +-clk_err: +- if (imxpriv->type == AHCI_IMX53) +- clk_disable_unprepare(imxpriv->sata_gate_clk); ++disable_clk: ++ clk_disable_unprepare(imxpriv->sata_ref_clk); ++disable_regulator: ++ 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, +@@ -107,8 +291,8 @@ + + clk_disable_unprepare(imxpriv->sata_ref_clk); + +- if (imxpriv->type == AHCI_IMX53) +- clk_disable_unprepare(imxpriv->sata_gate_clk); ++ if (hpriv->target_pwr) ++ regulator_disable(hpriv->target_pwr); + } + + static void ahci_imx_error_handler(struct ata_port *ap) +@@ -118,7 +302,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 +318,22 @@ + * 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 +345,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 +358,330 @@ + .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->ahb_clk = devm_clk_get(dev, "ahb"); +- if (IS_ERR(imxpriv->ahb_clk)) { +- dev_err(dev, "can't get ahb clock.\n"); +- ret = PTR_ERR(imxpriv->ahb_clk); +- goto err_out; +- } ++ imxpriv->type = (enum ahci_imx_type)of_id->data; + +- 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_clk = devm_clk_get(dev, "sata"); ++ if (IS_ERR(imxpriv->sata_clk)) { ++ dev_err(dev, "can't get sata clock.\n"); ++ return PTR_ERR(imxpriv->sata_clk); + } + + 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->sata_ref_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; ++ imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); ++ if (IS_ERR(imxpriv->ahb_clk)) { ++ dev_err(dev, "can't get ahb clock.\n"); ++ return PTR_ERR(imxpriv->ahb_clk); + } + +- 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 = clk_prepare_enable(imxpriv->sata_clk); + if (ret) +- goto err_out; ++ return ret; + +- ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata)); ++ ret = imx_sata_enable(hpriv); + if (ret) +- goto err_out; ++ goto disable_clk; + +- ret = platform_device_add(ahci_pdev); +- if (ret) { +-err_out: +- platform_device_put(ahci_pdev); +- return ret; ++ /* ++ * 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); ++ if (ret) ++ goto disable_sata; ++ + return 0; ++ ++disable_sata: ++ imx_sata_disable(hpriv); ++disable_clk: ++ clk_disable_unprepare(imxpriv->sata_clk); ++ return ret; + } + +-static int imx_ahci_remove(struct platform_device *pdev) ++static void ahci_imx_host_stop(struct ata_host *host) + { +- struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev); +- struct platform_device *ahci_pdev = imxpriv->ahci_pdev; ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ ++ imx_sata_disable(hpriv); ++ clk_disable_unprepare(imxpriv->sata_clk); ++} ++ ++#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); + +- platform_device_unregister(ahci_pdev); + return 0; + } + ++static int imx_ahci_resume(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ int ret; ++ ++ 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.72.orig/drivers/ata/ahci_mvebu.c linux-3.14.72/drivers/ata/ahci_mvebu.c +--- linux-3.14.72.orig/drivers/ata/ahci_mvebu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/ata/ahci_mvebu.c 2016-06-19 22:11:55.085154441 +0200 +@@ -0,0 +1,127 @@ ++/* ++ * AHCI glue platform driver for Marvell EBU SOCs ++ * ++ * Copyright (C) 2014 Marvell ++ * ++ * Thomas Petazzoni ++ * Marcin Wojtas ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ahci.h" ++ ++#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0 ++#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4 ++ ++#define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4)) ++#define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4)) ++#define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4)) ++ ++static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv, ++ const struct mbus_dram_target_info *dram) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ writel(0, hpriv->mmio + AHCI_WINDOW_CTRL(i)); ++ writel(0, hpriv->mmio + AHCI_WINDOW_BASE(i)); ++ writel(0, hpriv->mmio + AHCI_WINDOW_SIZE(i)); ++ } ++ ++ for (i = 0; i < dram->num_cs; i++) { ++ const struct mbus_dram_window *cs = dram->cs + i; ++ ++ writel((cs->mbus_attr << 8) | ++ (dram->mbus_dram_target_id << 4) | 1, ++ hpriv->mmio + AHCI_WINDOW_CTRL(i)); ++ writel(cs->base, hpriv->mmio + AHCI_WINDOW_BASE(i)); ++ writel(((cs->size - 1) & 0xffff0000), ++ hpriv->mmio + AHCI_WINDOW_SIZE(i)); ++ } ++} ++ ++static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) ++{ ++ /* ++ * Enable the regret bit to allow the SATA unit to regret a ++ * request that didn't receive an acknowlegde and avoid a ++ * deadlock ++ */ ++ writel(0x4, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_ADDR); ++ writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); ++} ++ ++static const struct ata_port_info ahci_mvebu_port_info = { ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_platform_ops, ++}; ++ ++static int ahci_mvebu_probe(struct platform_device *pdev) ++{ ++ struct ahci_host_priv *hpriv; ++ const struct mbus_dram_target_info *dram; ++ int rc; ++ ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ rc = ahci_platform_enable_resources(hpriv); ++ if (rc) ++ return rc; ++ ++ dram = mv_mbus_dram_info(); ++ if (!dram) ++ return -ENODEV; ++ ++ ahci_mvebu_mbus_config(hpriv, dram); ++ ahci_mvebu_regret_option(hpriv); ++ ++ rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info); ++ if (rc) ++ goto disable_resources; ++ ++ return 0; ++ ++disable_resources: ++ ahci_platform_disable_resources(hpriv); ++ return rc; ++} ++ ++static const struct of_device_id ahci_mvebu_of_match[] = { ++ { .compatible = "marvell,armada-380-ahci", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); ++ ++/* ++ * We currently don't provide power management related operations, ++ * since there is no suspend/resume support at the platform level for ++ * Armada 38x for the moment. ++ */ ++static struct platform_driver ahci_mvebu_driver = { ++ .probe = ahci_mvebu_probe, ++ .remove = ata_platform_remove_one, ++ .driver = { ++ .name = "ahci-mvebu", ++ .owner = THIS_MODULE, ++ .of_match_table = ahci_mvebu_of_match, ++ }, ++}; ++module_platform_driver(ahci_mvebu_driver); ++ ++MODULE_DESCRIPTION("Marvell EBU AHCI SATA driver"); ++MODULE_AUTHOR("Thomas Petazzoni , Marcin Wojtas "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ahci_mvebu"); +diff -Nur linux-3.14.72.orig/drivers/ata/ahci_platform.c linux-3.14.72/drivers/ata/ahci_platform.c +--- linux-3.14.72.orig/drivers/ata/ahci_platform.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/ahci_platform.c 2016-06-19 22:11:55.085154441 +0200 +@@ -12,135 +12,37 @@ + * 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); +- +-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 +53,13 @@ + 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; +- } +- +- 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; ++ goto disable_resources; + } + +- rc = ahci_reset_controller(host); +- if (rc) +- goto pdata_exit; ++ if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) ++ hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ; + +- 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); + if (rc) + goto pdata_exit; + +@@ -221,115 +67,20 @@ + 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", }, ++ { .compatible = "hisilicon,hisi-ahci", }, + {}, + }; + MODULE_DEVICE_TABLE(of, ahci_of_match); +@@ -343,7 +94,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.72.orig/drivers/ata/ahci_st.c linux-3.14.72/drivers/ata/ahci_st.c +--- linux-3.14.72.orig/drivers/ata/ahci_st.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/ata/ahci_st.c 2016-06-19 22:11:55.085154441 +0200 +@@ -0,0 +1,245 @@ ++/* ++ * Copyright (C) 2012 STMicroelectronics Limited ++ * ++ * Authors: Francesco Virlinzi ++ * Alexandre Torgue ++ * ++ * This program is free software; you can 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 "ahci.h" ++ ++#define ST_AHCI_OOBR 0xbc ++#define ST_AHCI_OOBR_WE BIT(31) ++#define ST_AHCI_OOBR_CWMIN_SHIFT 24 ++#define ST_AHCI_OOBR_CWMAX_SHIFT 16 ++#define ST_AHCI_OOBR_CIMIN_SHIFT 8 ++#define ST_AHCI_OOBR_CIMAX_SHIFT 0 ++ ++struct st_ahci_drv_data { ++ struct platform_device *ahci; ++ struct reset_control *pwr; ++ struct reset_control *sw_rst; ++ struct reset_control *pwr_rst; ++ struct ahci_host_priv *hpriv; ++}; ++ ++static void st_ahci_configure_oob(void __iomem *mmio) ++{ ++ unsigned long old_val, new_val; ++ ++ new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) | ++ (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) | ++ (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) | ++ (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT); ++ ++ old_val = readl(mmio + ST_AHCI_OOBR); ++ writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR); ++ writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR); ++ writel(new_val, mmio + ST_AHCI_OOBR); ++} ++ ++static int st_ahci_deassert_resets(struct device *dev) ++{ ++ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); ++ int err; ++ ++ if (drv_data->pwr) { ++ err = reset_control_deassert(drv_data->pwr); ++ if (err) { ++ dev_err(dev, "unable to bring out of pwrdwn\n"); ++ return err; ++ } ++ } ++ ++ st_ahci_configure_oob(drv_data->hpriv->mmio); ++ ++ if (drv_data->sw_rst) { ++ err = reset_control_deassert(drv_data->sw_rst); ++ if (err) { ++ dev_err(dev, "unable to bring out of sw-rst\n"); ++ return err; ++ } ++ } ++ ++ if (drv_data->pwr_rst) { ++ err = reset_control_deassert(drv_data->pwr_rst); ++ if (err) { ++ dev_err(dev, "unable to bring out of pwr-rst\n"); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static void st_ahci_host_stop(struct ata_host *host) ++{ ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct device *dev = host->dev; ++ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); ++ int err; ++ ++ if (drv_data->pwr) { ++ err = reset_control_assert(drv_data->pwr); ++ if (err) ++ dev_err(dev, "unable to pwrdwn\n"); ++ } ++ ++ ahci_platform_disable_resources(hpriv); ++} ++ ++static int st_ahci_probe_resets(struct platform_device *pdev) ++{ ++ struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev); ++ ++ drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn"); ++ if (IS_ERR(drv_data->pwr)) { ++ dev_info(&pdev->dev, "power reset control not defined\n"); ++ drv_data->pwr = NULL; ++ } ++ ++ drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst"); ++ if (IS_ERR(drv_data->sw_rst)) { ++ dev_info(&pdev->dev, "soft reset control not defined\n"); ++ drv_data->sw_rst = NULL; ++ } ++ ++ drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst"); ++ if (IS_ERR(drv_data->pwr_rst)) { ++ dev_dbg(&pdev->dev, "power soft reset control not defined\n"); ++ drv_data->pwr_rst = NULL; ++ } ++ ++ return st_ahci_deassert_resets(&pdev->dev); ++} ++ ++static struct ata_port_operations st_ahci_port_ops = { ++ .inherits = &ahci_platform_ops, ++ .host_stop = st_ahci_host_stop, ++}; ++ ++static const struct ata_port_info st_ahci_port_info = { ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &st_ahci_port_ops, ++}; ++ ++static int st_ahci_probe(struct platform_device *pdev) ++{ ++ struct st_ahci_drv_data *drv_data; ++ struct ahci_host_priv *hpriv; ++ int err; ++ ++ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL); ++ if (!drv_data) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, drv_data); ++ ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ drv_data->hpriv = hpriv; ++ ++ err = st_ahci_probe_resets(pdev); ++ if (err) ++ return err; ++ ++ err = ahci_platform_enable_resources(hpriv); ++ if (err) ++ return err; ++ ++ err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info); ++ if (err) { ++ ahci_platform_disable_resources(hpriv); ++ return err; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int st_ahci_suspend(struct device *dev) ++{ ++ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = drv_data->hpriv; ++ int err; ++ ++ err = ahci_platform_suspend_host(dev); ++ if (err) ++ return err; ++ ++ if (drv_data->pwr) { ++ err = reset_control_assert(drv_data->pwr); ++ if (err) { ++ dev_err(dev, "unable to pwrdwn"); ++ return err; ++ } ++ } ++ ++ ahci_platform_disable_resources(hpriv); ++ ++ return 0; ++} ++ ++static int st_ahci_resume(struct device *dev) ++{ ++ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = drv_data->hpriv; ++ int err; ++ ++ err = ahci_platform_enable_resources(hpriv); ++ if (err) ++ return err; ++ ++ err = st_ahci_deassert_resets(dev); ++ if (err) { ++ ahci_platform_disable_resources(hpriv); ++ return err; ++ } ++ ++ return ahci_platform_resume_host(dev); ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume); ++ ++static struct of_device_id st_ahci_match[] = { ++ { .compatible = "st,ahci", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, st_ahci_match); ++ ++static struct platform_driver st_ahci_driver = { ++ .driver = { ++ .name = "st_ahci", ++ .owner = THIS_MODULE, ++ .pm = &st_ahci_pm_ops, ++ .of_match_table = of_match_ptr(st_ahci_match), ++ }, ++ .probe = st_ahci_probe, ++ .remove = ata_platform_remove_one, ++}; ++module_platform_driver(st_ahci_driver); ++ ++MODULE_AUTHOR("Alexandre Torgue "); ++MODULE_AUTHOR("Francesco Virlinzi "); ++MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.14.72.orig/drivers/ata/ahci_sunxi.c linux-3.14.72/drivers/ata/ahci_sunxi.c +--- linux-3.14.72.orig/drivers/ata/ahci_sunxi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/ata/ahci_sunxi.c 2016-06-19 22:11:55.085154441 +0200 +@@ -0,0 +1,250 @@ ++/* ++ * Allwinner sunxi AHCI SATA platform driver ++ * Copyright 2013 Olliver Schinagl ++ * Copyright 2014 Hans de Goede ++ * ++ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov ++ * Based on code from Allwinner Technology Co., Ltd. , ++ * Daniel Wang ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ahci.h" ++ ++#define AHCI_BISTAFR 0x00a0 ++#define AHCI_BISTCR 0x00a4 ++#define AHCI_BISTFCTR 0x00a8 ++#define AHCI_BISTSR 0x00ac ++#define AHCI_BISTDECR 0x00b0 ++#define AHCI_DIAGNR0 0x00b4 ++#define AHCI_DIAGNR1 0x00b8 ++#define AHCI_OOBR 0x00bc ++#define AHCI_PHYCS0R 0x00c0 ++#define AHCI_PHYCS1R 0x00c4 ++#define AHCI_PHYCS2R 0x00c8 ++#define AHCI_TIMER1MS 0x00e0 ++#define AHCI_GPARAM1R 0x00e8 ++#define AHCI_GPARAM2R 0x00ec ++#define AHCI_PPARAMR 0x00f0 ++#define AHCI_TESTR 0x00f4 ++#define AHCI_VERSIONR 0x00f8 ++#define AHCI_IDR 0x00fc ++#define AHCI_RWCR 0x00fc ++#define AHCI_P0DMACR 0x0170 ++#define AHCI_P0PHYCR 0x0178 ++#define AHCI_P0PHYSR 0x017c ++ ++static void sunxi_clrbits(void __iomem *reg, u32 clr_val) ++{ ++ u32 reg_val; ++ ++ reg_val = readl(reg); ++ reg_val &= ~(clr_val); ++ writel(reg_val, reg); ++} ++ ++static void sunxi_setbits(void __iomem *reg, u32 set_val) ++{ ++ u32 reg_val; ++ ++ reg_val = readl(reg); ++ reg_val |= set_val; ++ writel(reg_val, reg); ++} ++ ++static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val) ++{ ++ u32 reg_val; ++ ++ reg_val = readl(reg); ++ reg_val &= ~(clr_val); ++ reg_val |= set_val; ++ writel(reg_val, reg); ++} ++ ++static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift) ++{ ++ return (readl(reg) >> shift) & mask; ++} ++ ++static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base) ++{ ++ u32 reg_val; ++ int timeout; ++ ++ /* This magic is from the original code */ ++ writel(0, reg_base + AHCI_RWCR); ++ msleep(5); ++ ++ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, ++ (0x7 << 24), ++ (0x5 << 24) | BIT(23) | BIT(18)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R, ++ (0x3 << 16) | (0x1f << 8) | (0x3 << 6), ++ (0x2 << 16) | (0x6 << 8) | (0x2 << 6)); ++ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15)); ++ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, ++ (0x7 << 20), (0x3 << 20)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R, ++ (0x1f << 5), (0x19 << 5)); ++ msleep(5); ++ ++ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19)); ++ ++ timeout = 250; /* Power up takes aprox 50 us */ ++ do { ++ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28); ++ if (reg_val == 0x02) ++ break; ++ ++ if (--timeout == 0) { ++ dev_err(dev, "PHY power up failed.\n"); ++ return -EIO; ++ } ++ udelay(1); ++ } while (1); ++ ++ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24)); ++ ++ timeout = 100; /* Calibration takes aprox 10 us */ ++ do { ++ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24); ++ if (reg_val == 0x00) ++ break; ++ ++ if (--timeout == 0) { ++ dev_err(dev, "PHY calibration failed.\n"); ++ return -EIO; ++ } ++ udelay(1); ++ } while (1); ++ ++ msleep(15); ++ ++ writel(0x7, reg_base + AHCI_RWCR); ++ ++ return 0; ++} ++ ++static void ahci_sunxi_start_engine(struct ata_port *ap) ++{ ++ void __iomem *port_mmio = ahci_port_base(ap); ++ struct ahci_host_priv *hpriv = ap->host->private_data; ++ ++ /* Setup DMA before DMA start */ ++ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400); ++ ++ /* Start DMA */ ++ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START); ++} ++ ++static const struct ata_port_info ahci_sunxi_port_info = { ++ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_platform_ops, ++}; ++ ++static int ahci_sunxi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ahci_host_priv *hpriv; ++ int rc; ++ ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ hpriv->start_engine = ahci_sunxi_start_engine; ++ ++ rc = ahci_platform_enable_resources(hpriv); ++ if (rc) ++ return rc; ++ ++ rc = ahci_sunxi_phy_init(dev, hpriv->mmio); ++ if (rc) ++ goto disable_resources; ++ ++ hpriv->flags = AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | ++ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; ++ ++ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info); ++ if (rc) ++ goto disable_resources; ++ ++ return 0; ++ ++disable_resources: ++ ahci_platform_disable_resources(hpriv); ++ return rc; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ahci_sunxi_resume(struct device *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; ++ ++ rc = ahci_sunxi_phy_init(dev, hpriv->mmio); ++ if (rc) ++ goto disable_resources; ++ ++ rc = ahci_platform_resume_host(dev); ++ if (rc) ++ goto disable_resources; ++ ++ return 0; ++ ++disable_resources: ++ ahci_platform_disable_resources(hpriv); ++ return rc; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend, ++ ahci_sunxi_resume); ++ ++static const struct of_device_id ahci_sunxi_of_match[] = { ++ { .compatible = "allwinner,sun4i-a10-ahci", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match); ++ ++static struct platform_driver ahci_sunxi_driver = { ++ .probe = ahci_sunxi_probe, ++ .remove = ata_platform_remove_one, ++ .driver = { ++ .name = "ahci-sunxi", ++ .owner = THIS_MODULE, ++ .of_match_table = ahci_sunxi_of_match, ++ .pm = &ahci_sunxi_pm_ops, ++ }, ++}; ++module_platform_driver(ahci_sunxi_driver); ++ ++MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver"); ++MODULE_AUTHOR("Olliver Schinagl "); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/ata/ahci_tegra.c linux-3.14.72/drivers/ata/ahci_tegra.c +--- linux-3.14.72.orig/drivers/ata/ahci_tegra.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/ata/ahci_tegra.c 2016-06-19 22:11:55.085154441 +0200 +@@ -0,0 +1,376 @@ ++/* ++ * drivers/ata/ahci_tegra.c ++ * ++ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. ++ * ++ * Author: ++ * Mikko Perttunen ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ahci.h" ++ ++#define SATA_CONFIGURATION_0 0x180 ++#define SATA_CONFIGURATION_EN_FPCI BIT(0) ++ ++#define SCFG_OFFSET 0x1000 ++ ++#define T_SATA0_CFG_1 0x04 ++#define T_SATA0_CFG_1_IO_SPACE BIT(0) ++#define T_SATA0_CFG_1_MEMORY_SPACE BIT(1) ++#define T_SATA0_CFG_1_BUS_MASTER BIT(2) ++#define T_SATA0_CFG_1_SERR BIT(8) ++ ++#define T_SATA0_CFG_9 0x24 ++#define T_SATA0_CFG_9_BASE_ADDRESS_SHIFT 13 ++ ++#define SATA_FPCI_BAR5 0x94 ++#define SATA_FPCI_BAR5_START_SHIFT 4 ++ ++#define SATA_INTR_MASK 0x188 ++#define SATA_INTR_MASK_IP_INT_MASK BIT(16) ++ ++#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300 ++ ++#define T_SATA0_BKDOOR_CC 0x4a4 ++ ++#define T_SATA0_CFG_SATA 0x54c ++#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12) ++ ++#define T_SATA0_CFG_MISC 0x550 ++ ++#define T_SATA0_INDEX 0x680 ++ ++#define T_SATA0_CHX_PHY_CTRL1_GEN1 0x690 ++#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK 0xff ++#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT 0 ++#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK (0xff << 8) ++#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT 8 ++ ++#define T_SATA0_CHX_PHY_CTRL1_GEN2 0x694 ++#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK 0xff ++#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT 0 ++#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK (0xff << 12) ++#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT 12 ++ ++#define T_SATA0_CHX_PHY_CTRL2 0x69c ++#define T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1 0x23 ++ ++#define T_SATA0_CHX_PHY_CTRL11 0x6d0 ++#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16) ++ ++#define FUSE_SATA_CALIB 0x124 ++#define FUSE_SATA_CALIB_MASK 0x3 ++ ++struct sata_pad_calibration { ++ u8 gen1_tx_amp; ++ u8 gen1_tx_peak; ++ u8 gen2_tx_amp; ++ u8 gen2_tx_peak; ++}; ++ ++static const struct sata_pad_calibration tegra124_pad_calibration[] = { ++ {0x18, 0x04, 0x18, 0x0a}, ++ {0x0e, 0x04, 0x14, 0x0a}, ++ {0x0e, 0x07, 0x1a, 0x0e}, ++ {0x14, 0x0e, 0x1a, 0x0e}, ++}; ++ ++struct tegra_ahci_priv { ++ struct platform_device *pdev; ++ void __iomem *sata_regs; ++ struct reset_control *sata_rst; ++ struct reset_control *sata_oob_rst; ++ struct reset_control *sata_cold_rst; ++ /* Needs special handling, cannot use ahci_platform */ ++ struct clk *sata_clk; ++ struct regulator_bulk_data supplies[5]; ++}; ++ ++static int tegra_ahci_power_on(struct ahci_host_priv *hpriv) ++{ ++ struct tegra_ahci_priv *tegra = hpriv->plat_data; ++ int ret; ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(tegra->supplies), ++ tegra->supplies); ++ if (ret) ++ return ret; ++ ++ ret = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SATA, ++ tegra->sata_clk, ++ tegra->sata_rst); ++ if (ret) ++ goto disable_regulators; ++ ++ reset_control_assert(tegra->sata_oob_rst); ++ reset_control_assert(tegra->sata_cold_rst); ++ ++ ret = ahci_platform_enable_resources(hpriv); ++ if (ret) ++ goto disable_power; ++ ++ reset_control_deassert(tegra->sata_cold_rst); ++ reset_control_deassert(tegra->sata_oob_rst); ++ ++ return 0; ++ ++disable_power: ++ clk_disable_unprepare(tegra->sata_clk); ++ ++ tegra_powergate_power_off(TEGRA_POWERGATE_SATA); ++ ++disable_regulators: ++ regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies); ++ ++ return ret; ++} ++ ++static void tegra_ahci_power_off(struct ahci_host_priv *hpriv) ++{ ++ struct tegra_ahci_priv *tegra = hpriv->plat_data; ++ ++ ahci_platform_disable_resources(hpriv); ++ ++ reset_control_assert(tegra->sata_rst); ++ reset_control_assert(tegra->sata_oob_rst); ++ reset_control_assert(tegra->sata_cold_rst); ++ ++ clk_disable_unprepare(tegra->sata_clk); ++ tegra_powergate_power_off(TEGRA_POWERGATE_SATA); ++ ++ regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies); ++} ++ ++static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv) ++{ ++ struct tegra_ahci_priv *tegra = hpriv->plat_data; ++ int ret; ++ unsigned int val; ++ struct sata_pad_calibration calib; ++ ++ ret = tegra_ahci_power_on(hpriv); ++ if (ret) { ++ dev_err(&tegra->pdev->dev, ++ "failed to power on AHCI controller: %d\n", ret); ++ return ret; ++ } ++ ++ val = readl(tegra->sata_regs + SATA_CONFIGURATION_0); ++ val |= SATA_CONFIGURATION_EN_FPCI; ++ writel(val, tegra->sata_regs + SATA_CONFIGURATION_0); ++ ++ /* Pad calibration */ ++ ++ /* FIXME Always use calibration 0. Change this to read the calibration ++ * fuse once the fuse driver has landed. */ ++ val = 0; ++ ++ calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK]; ++ ++ writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX); ++ ++ val = readl(tegra->sata_regs + ++ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1); ++ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK; ++ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK; ++ val |= calib.gen1_tx_amp << ++ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT; ++ val |= calib.gen1_tx_peak << ++ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT; ++ writel(val, tegra->sata_regs + SCFG_OFFSET + ++ T_SATA0_CHX_PHY_CTRL1_GEN1); ++ ++ val = readl(tegra->sata_regs + ++ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2); ++ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK; ++ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK; ++ val |= calib.gen2_tx_amp << ++ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT; ++ val |= calib.gen2_tx_peak << ++ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT; ++ writel(val, tegra->sata_regs + SCFG_OFFSET + ++ T_SATA0_CHX_PHY_CTRL1_GEN2); ++ ++ writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ, ++ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11); ++ writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1, ++ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2); ++ ++ writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX); ++ ++ /* Program controller device ID */ ++ ++ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); ++ val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; ++ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); ++ ++ writel(0x01060100, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC); ++ ++ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); ++ val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; ++ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); ++ ++ /* Enable IO & memory access, bus master mode */ ++ ++ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1); ++ val |= T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE | ++ T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR; ++ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1); ++ ++ /* Program SATA MMIO */ ++ ++ writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT, ++ tegra->sata_regs + SATA_FPCI_BAR5); ++ ++ writel(0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT, ++ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9); ++ ++ /* Unmask SATA interrupts */ ++ ++ val = readl(tegra->sata_regs + SATA_INTR_MASK); ++ val |= SATA_INTR_MASK_IP_INT_MASK; ++ writel(val, tegra->sata_regs + SATA_INTR_MASK); ++ ++ return 0; ++} ++ ++static void tegra_ahci_controller_deinit(struct ahci_host_priv *hpriv) ++{ ++ tegra_ahci_power_off(hpriv); ++} ++ ++static void tegra_ahci_host_stop(struct ata_host *host) ++{ ++ struct ahci_host_priv *hpriv = host->private_data; ++ ++ tegra_ahci_controller_deinit(hpriv); ++} ++ ++static struct ata_port_operations ahci_tegra_port_ops = { ++ .inherits = &ahci_ops, ++ .host_stop = tegra_ahci_host_stop, ++}; ++ ++static const struct ata_port_info ahci_tegra_port_info = { ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_tegra_port_ops, ++}; ++ ++static const struct of_device_id tegra_ahci_of_match[] = { ++ { .compatible = "nvidia,tegra124-ahci" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, tegra_ahci_of_match); ++ ++static int tegra_ahci_probe(struct platform_device *pdev) ++{ ++ struct ahci_host_priv *hpriv; ++ struct tegra_ahci_priv *tegra; ++ struct resource *res; ++ int ret; ++ ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); ++ if (!tegra) ++ return -ENOMEM; ++ ++ hpriv->plat_data = tegra; ++ ++ tegra->pdev = pdev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(tegra->sata_regs)) ++ return PTR_ERR(tegra->sata_regs); ++ ++ tegra->sata_rst = devm_reset_control_get(&pdev->dev, "sata"); ++ if (IS_ERR(tegra->sata_rst)) { ++ dev_err(&pdev->dev, "Failed to get sata reset\n"); ++ return PTR_ERR(tegra->sata_rst); ++ } ++ ++ tegra->sata_oob_rst = devm_reset_control_get(&pdev->dev, "sata-oob"); ++ if (IS_ERR(tegra->sata_oob_rst)) { ++ dev_err(&pdev->dev, "Failed to get sata-oob reset\n"); ++ return PTR_ERR(tegra->sata_oob_rst); ++ } ++ ++ tegra->sata_cold_rst = devm_reset_control_get(&pdev->dev, "sata-cold"); ++ if (IS_ERR(tegra->sata_cold_rst)) { ++ dev_err(&pdev->dev, "Failed to get sata-cold reset\n"); ++ return PTR_ERR(tegra->sata_cold_rst); ++ } ++ ++ tegra->sata_clk = devm_clk_get(&pdev->dev, "sata"); ++ if (IS_ERR(tegra->sata_clk)) { ++ dev_err(&pdev->dev, "Failed to get sata clock\n"); ++ return PTR_ERR(tegra->sata_clk); ++ } ++ ++ tegra->supplies[0].supply = "avdd"; ++ tegra->supplies[1].supply = "hvdd"; ++ tegra->supplies[2].supply = "vddio"; ++ tegra->supplies[3].supply = "target-5v"; ++ tegra->supplies[4].supply = "target-12v"; ++ ++ ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(tegra->supplies), ++ tegra->supplies); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to get regulators\n"); ++ return ret; ++ } ++ ++ ret = tegra_ahci_controller_init(hpriv); ++ if (ret) ++ return ret; ++ ++ ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info); ++ if (ret) ++ goto deinit_controller; ++ ++ return 0; ++ ++deinit_controller: ++ tegra_ahci_controller_deinit(hpriv); ++ ++ return ret; ++}; ++ ++static struct platform_driver tegra_ahci_driver = { ++ .probe = tegra_ahci_probe, ++ .remove = ata_platform_remove_one, ++ .driver = { ++ .name = "tegra-ahci", ++ .of_match_table = tegra_ahci_of_match, ++ }, ++ /* LP0 suspend support not implemented */ ++}; ++module_platform_driver(tegra_ahci_driver); ++ ++MODULE_AUTHOR("Mikko Perttunen "); ++MODULE_DESCRIPTION("Tegra124 AHCI SATA driver"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.14.72.orig/drivers/ata/ahci_xgene.c linux-3.14.72/drivers/ata/ahci_xgene.c +--- linux-3.14.72.orig/drivers/ata/ahci_xgene.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/ata/ahci_xgene.c 2016-06-19 22:11:55.085154441 +0200 +@@ -0,0 +1,518 @@ ++/* ++ * AppliedMicro X-Gene SoC SATA Host Controller Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Author: Loc Ho ++ * Tuan Phan ++ * Suman Tripathi ++ * ++ * 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, see . ++ * ++ * NOTE: PM support is not currently available. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ahci.h" ++ ++/* Max # of disk per a controller */ ++#define MAX_AHCI_CHN_PERCTR 2 ++ ++/* MUX CSR */ ++#define SATA_ENET_CONFIG_REG 0x00000000 ++#define CFG_SATA_ENET_SELECT_MASK 0x00000001 ++ ++/* SATA core host controller CSR */ ++#define SLVRDERRATTRIBUTES 0x00000000 ++#define SLVWRERRATTRIBUTES 0x00000004 ++#define MSTRDERRATTRIBUTES 0x00000008 ++#define MSTWRERRATTRIBUTES 0x0000000c ++#define BUSCTLREG 0x00000014 ++#define IOFMSTRWAUX 0x00000018 ++#define INTSTATUSMASK 0x0000002c ++#define ERRINTSTATUS 0x00000030 ++#define ERRINTSTATUSMASK 0x00000034 ++ ++/* SATA host AHCI CSR */ ++#define PORTCFG 0x000000a4 ++#define PORTADDR_SET(dst, src) \ ++ (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f)) ++#define PORTPHY1CFG 0x000000a8 ++#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \ ++ (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000)) ++#define PORTPHY2CFG 0x000000ac ++#define PORTPHY3CFG 0x000000b0 ++#define PORTPHY4CFG 0x000000b4 ++#define PORTPHY5CFG 0x000000b8 ++#define SCTL0 0x0000012C ++#define PORTPHY5CFG_RTCHG_SET(dst, src) \ ++ (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000)) ++#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \ ++ (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000)) ++#define PORTAXICFG 0x000000bc ++#define PORTAXICFG_OUTTRANS_SET(dst, src) \ ++ (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000)) ++#define PORTRANSCFG 0x000000c8 ++#define PORTRANSCFG_RXWM_SET(dst, src) \ ++ (((dst) & ~0x0000007f) | (((u32)(src)) & 0x0000007f)) ++ ++/* SATA host controller AXI CSR */ ++#define INT_SLV_TMOMASK 0x00000010 ++ ++/* SATA diagnostic CSR */ ++#define CFG_MEM_RAM_SHUTDOWN 0x00000070 ++#define BLOCK_MEM_RDY 0x00000074 ++ ++struct xgene_ahci_context { ++ struct ahci_host_priv *hpriv; ++ struct device *dev; ++ u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/ ++ void __iomem *csr_core; /* Core CSR address of IP */ ++ void __iomem *csr_diag; /* Diag CSR address of IP */ ++ void __iomem *csr_axi; /* AXI CSR address of IP */ ++ void __iomem *csr_mux; /* MUX CSR address of IP */ ++}; ++ ++static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) ++{ ++ dev_dbg(ctx->dev, "Release memory from shutdown\n"); ++ writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); ++ readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */ ++ msleep(1); /* reset may take up to 1ms */ ++ if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) { ++ dev_err(ctx->dev, "failed to release memory from shutdown\n"); ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++/** ++ * xgene_ahci_restart_engine - Restart the dma engine. ++ * @ap : ATA port of interest ++ * ++ * Restarts the dma engine inside the controller. ++ */ ++static int xgene_ahci_restart_engine(struct ata_port *ap) ++{ ++ struct ahci_host_priv *hpriv = ap->host->private_data; ++ ++ ahci_stop_engine(ap); ++ ahci_start_fis_rx(ap); ++ hpriv->start_engine(ap); ++ ++ return 0; ++} ++ ++/** ++ * xgene_ahci_qc_issue - Issue commands to the device ++ * @qc: Command to issue ++ * ++ * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot ++ * clear the BSY bit after receiving the PIO setup FIS. This results in the dma ++ * state machine goes into the CMFatalErrorUpdate state and locks up. By ++ * restarting the dma engine, it removes the controller out of lock up state. ++ */ ++static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) ++{ ++ struct ata_port *ap = qc->ap; ++ struct ahci_host_priv *hpriv = ap->host->private_data; ++ struct xgene_ahci_context *ctx = hpriv->plat_data; ++ int rc = 0; ++ ++ if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA)) ++ xgene_ahci_restart_engine(ap); ++ ++ rc = ahci_qc_issue(qc); ++ ++ /* Save the last command issued */ ++ ctx->last_cmd[ap->port_no] = qc->tf.command; ++ ++ return rc; ++} ++ ++/** ++ * xgene_ahci_read_id - Read ID data from the specified device ++ * @dev: device ++ * @tf: proposed taskfile ++ * @id: data buffer ++ * ++ * This custom read ID function is required due to the fact that the HW ++ * does not support DEVSLP. ++ */ ++static unsigned int xgene_ahci_read_id(struct ata_device *dev, ++ struct ata_taskfile *tf, u16 *id) ++{ ++ u32 err_mask; ++ ++ err_mask = ata_do_dev_read_id(dev, tf, id); ++ if (err_mask) ++ return err_mask; ++ ++ /* ++ * Mask reserved area. Word78 spec of Link Power Management ++ * bit15-8: reserved ++ * bit7: NCQ autosence ++ * bit6: Software settings preservation supported ++ * bit5: reserved ++ * bit4: In-order sata delivery supported ++ * bit3: DIPM requests supported ++ * bit2: DMA Setup FIS Auto-Activate optimization supported ++ * bit1: DMA Setup FIX non-Zero buffer offsets supported ++ * bit0: Reserved ++ * ++ * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP ++ */ ++ id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); ++ ++ return 0; ++} ++ ++static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) ++{ ++ void __iomem *mmio = ctx->hpriv->mmio; ++ u32 val; ++ ++ dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n", ++ mmio, channel); ++ val = readl(mmio + PORTCFG); ++ val = PORTADDR_SET(val, channel == 0 ? 2 : 3); ++ writel(val, mmio + PORTCFG); ++ readl(mmio + PORTCFG); /* Force a barrier */ ++ /* Disable fix rate */ ++ writel(0x0001fffe, mmio + PORTPHY1CFG); ++ readl(mmio + PORTPHY1CFG); /* Force a barrier */ ++ writel(0x28183219, mmio + PORTPHY2CFG); ++ readl(mmio + PORTPHY2CFG); /* Force a barrier */ ++ writel(0x13081008, mmio + PORTPHY3CFG); ++ readl(mmio + PORTPHY3CFG); /* Force a barrier */ ++ writel(0x00480815, mmio + PORTPHY4CFG); ++ readl(mmio + PORTPHY4CFG); /* Force a barrier */ ++ /* Set window negotiation */ ++ val = readl(mmio + PORTPHY5CFG); ++ val = PORTPHY5CFG_RTCHG_SET(val, 0x300); ++ writel(val, mmio + PORTPHY5CFG); ++ readl(mmio + PORTPHY5CFG); /* Force a barrier */ ++ val = readl(mmio + PORTAXICFG); ++ val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */ ++ val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */ ++ writel(val, mmio + PORTAXICFG); ++ readl(mmio + PORTAXICFG); /* Force a barrier */ ++ /* Set the watermark threshold of the receive FIFO */ ++ val = readl(mmio + PORTRANSCFG); ++ val = PORTRANSCFG_RXWM_SET(val, 0x30); ++ writel(val, mmio + PORTRANSCFG); ++} ++ ++/** ++ * xgene_ahci_do_hardreset - Issue the actual COMRESET ++ * @link: link to reset ++ * @deadline: deadline jiffies for the operation ++ * @online: Return value to indicate if device online ++ * ++ * Due to the limitation of the hardware PHY, a difference set of setting is ++ * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps), ++ * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will ++ * report disparity error and etc. In addition, during COMRESET, there can ++ * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and ++ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following ++ * algorithm is followed to proper configure the hardware PHY during COMRESET: ++ * ++ * Alg Part 1: ++ * 1. Start the PHY at Gen3 speed (default setting) ++ * 2. Issue the COMRESET ++ * 3. If no link, go to Alg Part 3 ++ * 4. If link up, determine if the negotiated speed matches the PHY ++ * configured speed ++ * 5. If they matched, go to Alg Part 2 ++ * 6. If they do not matched and first time, configure the PHY for the linked ++ * up disk speed and repeat step 2 ++ * 7. Go to Alg Part 2 ++ * ++ * Alg Part 2: ++ * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error ++ * reported in the register PORT_SCR_ERR, then reset the PHY receiver line ++ * 2. Go to Alg Part 3 ++ * ++ * Alg Part 3: ++ * 1. Clear any pending from register PORT_SCR_ERR. ++ * ++ * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition ++ * and until the underlying PHY supports an method to reset the receiver ++ * line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors, ++ * an warning message will be printed. ++ */ ++static int xgene_ahci_do_hardreset(struct ata_link *link, ++ unsigned long deadline, bool *online) ++{ ++ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); ++ struct ata_port *ap = link->ap; ++ struct ahci_host_priv *hpriv = ap->host->private_data; ++ struct xgene_ahci_context *ctx = hpriv->plat_data; ++ struct ahci_port_priv *pp = ap->private_data; ++ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; ++ void __iomem *port_mmio = ahci_port_base(ap); ++ struct ata_taskfile tf; ++ int rc; ++ u32 val; ++ ++ /* clear D2H reception area to properly wait for D2H FIS */ ++ ata_tf_init(link->device, &tf); ++ tf.command = ATA_BUSY; ++ ata_tf_to_fis(&tf, 0, 0, d2h_fis); ++ rc = sata_link_hardreset(link, timing, deadline, online, ++ ahci_check_ready); ++ ++ val = readl(port_mmio + PORT_SCR_ERR); ++ if (val & (SERR_DISPARITY | SERR_10B_8B_ERR)) ++ dev_warn(ctx->dev, "link has error\n"); ++ ++ /* clear all errors if any pending */ ++ val = readl(port_mmio + PORT_SCR_ERR); ++ writel(val, port_mmio + PORT_SCR_ERR); ++ ++ return rc; ++} ++ ++static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class, ++ unsigned long deadline) ++{ ++ struct ata_port *ap = link->ap; ++ struct ahci_host_priv *hpriv = ap->host->private_data; ++ void __iomem *port_mmio = ahci_port_base(ap); ++ bool online; ++ int rc; ++ u32 portcmd_saved; ++ u32 portclb_saved; ++ u32 portclbhi_saved; ++ u32 portrxfis_saved; ++ u32 portrxfishi_saved; ++ ++ /* As hardreset resets these CSR, save it to restore later */ ++ portcmd_saved = readl(port_mmio + PORT_CMD); ++ portclb_saved = readl(port_mmio + PORT_LST_ADDR); ++ portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI); ++ portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); ++ portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); ++ ++ ahci_stop_engine(ap); ++ ++ rc = xgene_ahci_do_hardreset(link, deadline, &online); ++ ++ /* As controller hardreset clears them, restore them */ ++ writel(portcmd_saved, port_mmio + PORT_CMD); ++ writel(portclb_saved, port_mmio + PORT_LST_ADDR); ++ writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI); ++ writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR); ++ writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI); ++ ++ hpriv->start_engine(ap); ++ ++ if (online) ++ *class = ahci_dev_classify(ap); ++ ++ return rc; ++} ++ ++static void xgene_ahci_host_stop(struct ata_host *host) ++{ ++ struct ahci_host_priv *hpriv = host->private_data; ++ ++ ahci_platform_disable_resources(hpriv); ++} ++ ++static struct ata_port_operations xgene_ahci_ops = { ++ .inherits = &ahci_ops, ++ .host_stop = xgene_ahci_host_stop, ++ .hardreset = xgene_ahci_hardreset, ++ .read_id = xgene_ahci_read_id, ++ .qc_issue = xgene_ahci_qc_issue, ++}; ++ ++static const struct ata_port_info xgene_ahci_port_info = { ++ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &xgene_ahci_ops, ++}; ++ ++static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) ++{ ++ struct xgene_ahci_context *ctx = hpriv->plat_data; ++ int i; ++ int rc; ++ u32 val; ++ ++ /* Remove IP RAM out of shutdown */ ++ rc = xgene_ahci_init_memram(ctx); ++ if (rc) ++ return rc; ++ ++ for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++) ++ xgene_ahci_set_phy_cfg(ctx, i); ++ ++ /* AXI disable Mask */ ++ writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT); ++ readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */ ++ writel(0, ctx->csr_core + INTSTATUSMASK); ++ val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */ ++ dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n", ++ INTSTATUSMASK, val); ++ ++ writel(0x0, ctx->csr_core + ERRINTSTATUSMASK); ++ readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */ ++ writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK); ++ readl(ctx->csr_axi + INT_SLV_TMOMASK); ++ ++ /* Enable AXI Interrupt */ ++ writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES); ++ writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES); ++ writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES); ++ writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES); ++ ++ /* Enable coherency */ ++ val = readl(ctx->csr_core + BUSCTLREG); ++ val &= ~0x00000002; /* Enable write coherency */ ++ val &= ~0x00000001; /* Enable read coherency */ ++ writel(val, ctx->csr_core + BUSCTLREG); ++ ++ val = readl(ctx->csr_core + IOFMSTRWAUX); ++ val |= (1 << 3); /* Enable read coherency */ ++ val |= (1 << 9); /* Enable write coherency */ ++ writel(val, ctx->csr_core + IOFMSTRWAUX); ++ val = readl(ctx->csr_core + IOFMSTRWAUX); ++ dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n", ++ IOFMSTRWAUX, val); ++ ++ return rc; ++} ++ ++static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx) ++{ ++ u32 val; ++ ++ /* Check for optional MUX resource */ ++ if (IS_ERR(ctx->csr_mux)) ++ return 0; ++ ++ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); ++ val &= ~CFG_SATA_ENET_SELECT_MASK; ++ writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG); ++ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); ++ return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0; ++} ++ ++static int xgene_ahci_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ahci_host_priv *hpriv; ++ struct xgene_ahci_context *ctx; ++ struct resource *res; ++ int rc; ++ ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ hpriv->plat_data = ctx; ++ ctx->hpriv = hpriv; ++ ctx->dev = dev; ++ ++ /* Retrieve the IP core resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ ctx->csr_core = devm_ioremap_resource(dev, res); ++ if (IS_ERR(ctx->csr_core)) ++ return PTR_ERR(ctx->csr_core); ++ ++ /* Retrieve the IP diagnostic resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ ctx->csr_diag = devm_ioremap_resource(dev, res); ++ if (IS_ERR(ctx->csr_diag)) ++ return PTR_ERR(ctx->csr_diag); ++ ++ /* Retrieve the IP AXI resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 3); ++ ctx->csr_axi = devm_ioremap_resource(dev, res); ++ if (IS_ERR(ctx->csr_axi)) ++ return PTR_ERR(ctx->csr_axi); ++ ++ /* Retrieve the optional IP mux resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 4); ++ ctx->csr_mux = devm_ioremap_resource(dev, res); ++ ++ dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, ++ hpriv->mmio); ++ ++ /* Select ATA */ ++ if ((rc = xgene_ahci_mux_select(ctx))) { ++ dev_err(dev, "SATA mux selection failed error %d\n", rc); ++ return -ENODEV; ++ } ++ ++ /* Due to errata, HW requires full toggle transition */ ++ rc = ahci_platform_enable_clks(hpriv); ++ if (rc) ++ goto disable_resources; ++ ahci_platform_disable_clks(hpriv); ++ ++ rc = ahci_platform_enable_resources(hpriv); ++ if (rc) ++ goto disable_resources; ++ ++ /* Configure the host controller */ ++ xgene_ahci_hw_init(hpriv); ++ ++ hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; ++ ++ rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info); ++ if (rc) ++ goto disable_resources; ++ ++ dev_dbg(dev, "X-Gene SATA host controller initialized\n"); ++ return 0; ++ ++disable_resources: ++ ahci_platform_disable_resources(hpriv); ++ return rc; ++} ++ ++static const struct of_device_id xgene_ahci_of_match[] = { ++ {.compatible = "apm,xgene-ahci"}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); ++ ++static struct platform_driver xgene_ahci_driver = { ++ .probe = xgene_ahci_probe, ++ .remove = ata_platform_remove_one, ++ .driver = { ++ .name = "xgene-ahci", ++ .owner = THIS_MODULE, ++ .of_match_table = xgene_ahci_of_match, ++ }, ++}; ++ ++module_platform_driver(xgene_ahci_driver); ++ ++MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver"); ++MODULE_AUTHOR("Loc Ho "); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("0.4"); +diff -Nur linux-3.14.72.orig/drivers/ata/ata_generic.c linux-3.14.72/drivers/ata/ata_generic.c +--- linux-3.14.72.orig/drivers/ata/ata_generic.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/ata_generic.c 2016-06-19 22:11:55.085154441 +0200 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -242,7 +241,7 @@ + .id_table = ata_generic, + .probe = ata_generic_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/ata_piix.c linux-3.14.72/drivers/ata/ata_piix.c +--- linux-3.14.72.orig/drivers/ata/ata_piix.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/ata_piix.c 2016-06-19 22:11:55.085154441 +0200 +@@ -838,7 +838,7 @@ + return ap->ops->bmdma_status(ap) & ATA_DMA_INTR; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int piix_broken_suspend(void) + { + static const struct dmi_system_id sysids[] = { +@@ -1775,7 +1775,7 @@ + .id_table = piix_pci_tbl, + .probe = piix_init_one, + .remove = piix_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = piix_pci_device_suspend, + .resume = piix_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/Kconfig linux-3.14.72/drivers/ata/Kconfig +--- linux-3.14.72.orig/drivers/ata/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/Kconfig 2016-06-19 22:11:55.085154441 +0200 +@@ -60,7 +60,7 @@ + + config SATA_ZPODD + bool "SATA Zero Power Optical Disc Drive (ZPODD) support" +- depends on ATA_ACPI ++ depends on ATA_ACPI && PM_RUNTIME + default n + help + This option adds support for SATA Zero Power Optical Disc +@@ -97,15 +97,65 @@ + + If unsure, say N. + ++config AHCI_DA850 ++ tristate "DaVinci DA850 AHCI SATA support" ++ depends on ARCH_DAVINCI_DA850 ++ help ++ This option enables support for the DaVinci DA850 SoC's ++ onboard AHCI SATA. ++ ++ If unsure, say N. ++ ++config AHCI_ST ++ tristate "ST AHCI SATA support" ++ depends on ARCH_STI ++ help ++ This option enables support for ST AHCI SATA controller. ++ ++ If unsure, say N. ++ + config AHCI_IMX + tristate "Freescale i.MX AHCI SATA support" +- depends on SATA_AHCI_PLATFORM && MFD_SYSCON ++ depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST) + help + This option enables support for the Freescale i.MX SoC's + onboard AHCI SATA. + + If unsure, say N. + ++config AHCI_MVEBU ++ tristate "Marvell EBU AHCI SATA support" ++ depends on ARCH_MVEBU ++ help ++ This option enables support for the Marvebu EBU SoC's ++ onboard AHCI SATA. ++ ++ If unsure, say N. ++ ++config AHCI_SUNXI ++ tristate "Allwinner sunxi AHCI SATA support" ++ depends on ARCH_SUNXI ++ help ++ This option enables support for the Allwinner sunxi SoC's ++ onboard AHCI SATA. ++ ++ If unsure, say N. ++ ++config AHCI_TEGRA ++ tristate "NVIDIA Tegra124 AHCI SATA support" ++ depends on ARCH_TEGRA ++ help ++ This option enables support for the NVIDIA Tegra124 SoC's ++ onboard AHCI SATA. ++ ++ If unsure, say N. ++ ++config AHCI_XGENE ++ tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support" ++ depends on PHY_XGENE ++ help ++ This option enables support for APM X-Gene SoC SATA host controller. ++ + config SATA_FSL + tristate "Freescale 3.0Gbps SATA support" + depends on FSL_SOC +@@ -239,6 +289,7 @@ + + config SATA_HIGHBANK + tristate "Calxeda Highbank SATA support" ++ depends on ARCH_HIGHBANK || COMPILE_TEST + help + This option enables support for the Calxeda Highbank SoC's + onboard SATA. +@@ -273,6 +324,7 @@ + + config SATA_RCAR + tristate "Renesas R-Car SATA support" ++ depends on ARCH_SHMOBILE || COMPILE_TEST + help + This option enables support for Renesas R-Car Serial ATA. + +@@ -352,6 +404,7 @@ + + config PATA_ARASAN_CF + tristate "ARASAN CompactFlash PATA Controller Support" ++ depends on ARCH_SPEAR13XX || COMPILE_TEST + depends on DMADEVICES + select DMA_ENGINE + help +@@ -403,7 +456,7 @@ + + config PATA_CS5520 + tristate "CS5510/5520 PATA support" +- depends on PCI ++ depends on PCI && (X86_32 || COMPILE_TEST) + help + This option enables support for the Cyrix 5510/5520 + companion chip used with the MediaGX/Geode processor family. +@@ -412,7 +465,7 @@ + + config PATA_CS5530 + tristate "CS5530 PATA support" +- depends on PCI ++ depends on PCI && (X86_32 || COMPILE_TEST) + help + This option enables support for the Cyrix/NatSemi/AMD CS5530 + companion chip used with the MediaGX/Geode processor family. +@@ -421,7 +474,7 @@ + + config PATA_CS5535 + tristate "CS5535 PATA support (Experimental)" +- depends on PCI && X86 && !X86_64 ++ depends on PCI && X86_32 + help + This option enables support for the NatSemi/AMD CS5535 + companion chip used with the Geode processor family. +@@ -430,7 +483,7 @@ + + config PATA_CS5536 + tristate "CS5536 PATA support" +- depends on PCI ++ depends on PCI && (X86_32 || MIPS || COMPILE_TEST) + help + This option enables support for the AMD CS5536 + companion chip used with the Geode LX processor family. +@@ -666,7 +719,7 @@ + + config PATA_SC1200 + tristate "SC1200 PATA support" +- depends on PCI ++ depends on PCI && (X86_32 || COMPILE_TEST) + help + This option enables support for the NatSemi/AMD SC1200 SoC + companion chip used with the Geode processor family. +@@ -778,7 +831,7 @@ + + config PATA_AT91 + tristate "PATA support for AT91SAM9260" +- depends on ARM && ARCH_AT91 ++ depends on ARM && SOC_AT91SAM9 + help + This option enables support for IDE devices on the Atmel AT91SAM9260 SoC. + +diff -Nur linux-3.14.72.orig/drivers/ata/libahci.c linux-3.14.72/drivers/ata/libahci.c +--- linux-3.14.72.orig/drivers/ata/libahci.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/libahci.c 2016-06-19 22:11:55.085154441 +0200 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -69,7 +68,6 @@ + + static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); + static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); +-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); + static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); + static int ahci_port_start(struct ata_port *ap); + static void ahci_port_stop(struct ata_port *ap); +@@ -384,8 +382,6 @@ + * ahci_save_initial_config - Save and fixup initial config values + * @dev: target AHCI device + * @hpriv: host private area to store config values +- * @force_port_map: force port map to a specified value +- * @mask_port_map: mask out particular bits from port map + * + * Some registers containing configuration info might be setup by + * BIOS and might be cleared on reset. This function saves the +@@ -394,13 +390,13 @@ + * + * 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. + */ +-void ahci_save_initial_config(struct device *dev, +- struct ahci_host_priv *hpriv, +- unsigned int force_port_map, +- unsigned int mask_port_map) ++void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) + { + void __iomem *mmio = hpriv->mmio; + u32 cap, cap2, vers, port_map; +@@ -455,17 +451,22 @@ + cap |= HOST_CAP_FBS; + } + +- if (force_port_map && port_map != force_port_map) { ++ 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 (hpriv->force_port_map && port_map != hpriv->force_port_map) { + dev_info(dev, "forcing port_map 0x%x -> 0x%x\n", +- port_map, force_port_map); +- port_map = force_port_map; ++ port_map, hpriv->force_port_map); ++ port_map = hpriv->force_port_map; + } + +- if (mask_port_map) { ++ if (hpriv->mask_port_map) { + dev_warn(dev, "masking port_map 0x%x -> 0x%x\n", + port_map, +- port_map & mask_port_map); +- port_map &= mask_port_map; ++ port_map & hpriv->mask_port_map); ++ port_map &= hpriv->mask_port_map; + } + + /* cross check port_map and cap.n_ports */ +@@ -500,6 +501,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); + +@@ -603,7 +607,7 @@ + } + EXPORT_SYMBOL_GPL(ahci_stop_engine); + +-static void ahci_start_fis_rx(struct ata_port *ap) ++void ahci_start_fis_rx(struct ata_port *ap) + { + void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_host_priv *hpriv = ap->host->private_data; +@@ -629,6 +633,7 @@ + /* flush */ + readl(port_mmio + PORT_CMD); + } ++EXPORT_SYMBOL_GPL(ahci_start_fis_rx); + + static int ahci_stop_fis_rx(struct ata_port *ap) + { +@@ -766,7 +771,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 +1239,7 @@ + + /* restart engine */ + out_restart: +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + return rc; + } + EXPORT_SYMBOL_GPL(ahci_kick_engine); +@@ -1435,6 +1440,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; +@@ -1452,7 +1458,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); +@@ -1638,7 +1644,7 @@ + } + + if (irq_stat & PORT_IRQ_UNK_FIS) { +- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); ++ u32 *unk = pp->rx_fis + RX_FIS_UNK; + + active_ehi->err_mask |= AC_ERR_HSM; + active_ehi->action |= ATA_EH_RESET; +@@ -1934,7 +1940,7 @@ + } + EXPORT_SYMBOL_GPL(ahci_interrupt); + +-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) ++unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) + { + struct ata_port *ap = qc->ap; + void __iomem *port_mmio = ahci_port_base(ap); +@@ -1963,6 +1969,7 @@ + + return 0; + } ++EXPORT_SYMBOL_GPL(ahci_qc_issue); + + static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) + { +@@ -2015,10 +2022,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); +@@ -2039,6 +2048,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; +@@ -2102,7 +2112,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, +@@ -2114,6 +2124,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; +@@ -2142,11 +2153,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; +@@ -2174,7 +2186,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.72.orig/drivers/ata/libahci_platform.c linux-3.14.72/drivers/ata/libahci_platform.c +--- linux-3.14.72.orig/drivers/ata/libahci_platform.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/ata/libahci_platform.c 2016-06-19 22:11:55.085154441 +0200 +@@ -0,0 +1,555 @@ ++/* ++ * 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 -ENOSYS: ++ /* No PHY support. Check if PHY is required. */ ++ if (of_find_property(dev->of_node, "phys", NULL)) { ++ dev_err(dev, "couldn't get sata-phy: ENOSYS\n"); ++ goto err_out; ++ } ++ case -ENODEV: ++ /* 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 ++ * ++ * 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) ++{ ++ 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 *)hpriv->flags; ++ ++ ahci_save_initial_config(dev, hpriv); ++ ++ 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; ++ } ++ ++ if (hpriv->cap & HOST_CAP_64) { ++ rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ rc = dma_coerce_mask_and_coherent(dev, ++ DMA_BIT_MASK(32)); ++ if (rc) { ++ dev_err(dev, "Failed to enable 64-bit DMA.\n"); ++ return rc; ++ } ++ dev_warn(dev, "Enable 32-bit DMA instead of 64-bit.\n"); ++ } ++ } ++ ++ 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.72.orig/drivers/ata/libata-acpi.c linux-3.14.72/drivers/ata/libata-acpi.c +--- linux-3.14.72.orig/drivers/ata/libata-acpi.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/libata-acpi.c 2016-06-19 22:11:55.085154441 +0200 +@@ -835,6 +835,7 @@ + ata_for_each_dev(dev, &ap->link, ALL) { + ata_acpi_clear_gtf(dev); + if (ata_dev_enabled(dev) && ++ ata_dev_acpi_handle(dev) && + ata_dev_get_GTF(dev, NULL) >= 0) + dev->flags |= ATA_DFLAG_ACPI_PENDING; + } +diff -Nur linux-3.14.72.orig/drivers/ata/libata-core.c linux-3.14.72/drivers/ata/libata-core.c +--- linux-3.14.72.orig/drivers/ata/libata-core.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/libata-core.c 2016-06-19 22:11:55.089154177 +0200 +@@ -5369,22 +5369,17 @@ + } + + #ifdef CONFIG_PM +-static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, +- unsigned int action, unsigned int ehi_flags, +- int *async) ++static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, ++ unsigned int action, unsigned int ehi_flags, ++ bool async) + { + struct ata_link *link; + unsigned long flags; +- int rc = 0; + + /* Previous resume operation might still be in + * progress. Wait for PM_PENDING to clear. + */ + if (ap->pflags & ATA_PFLAG_PM_PENDING) { +- if (async) { +- *async = -EAGAIN; +- return 0; +- } + ata_port_wait_eh(ap); + WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); + } +@@ -5393,11 +5388,6 @@ + spin_lock_irqsave(ap->lock, flags); + + ap->pm_mesg = mesg; +- if (async) +- ap->pm_result = async; +- else +- ap->pm_result = &rc; +- + ap->pflags |= ATA_PFLAG_PM_PENDING; + ata_for_each_link(link, ap, HOST_FIRST) { + link->eh_info.action |= action; +@@ -5408,87 +5398,81 @@ + + spin_unlock_irqrestore(ap->lock, flags); + +- /* wait and check result */ + if (!async) { + ata_port_wait_eh(ap); + WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); + } +- +- return rc; + } + +-static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async) ++/* ++ * On some hardware, device fails to respond after spun down for suspend. As ++ * the device won't be used before being resumed, we don't need to touch the ++ * device. Ask EH to skip the usual stuff and proceed directly to suspend. ++ * ++ * http://thread.gmane.org/gmane.linux.ide/46764 ++ */ ++static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET ++ | ATA_EHI_NO_AUTOPSY ++ | ATA_EHI_NO_RECOVERY; ++ ++static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg) + { +- /* +- * On some hardware, device fails to respond after spun down +- * for suspend. As the device won't be used before being +- * resumed, we don't need to touch the device. Ask EH to skip +- * the usual stuff and proceed directly to suspend. +- * +- * http://thread.gmane.org/gmane.linux.ide/46764 +- */ +- unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY | +- ATA_EHI_NO_RECOVERY; +- return ata_port_request_pm(ap, mesg, 0, ehi_flags, async); ++ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false); + } + +-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg) ++static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg) + { +- struct ata_port *ap = to_ata_port(dev); +- +- return __ata_port_suspend_common(ap, mesg, NULL); ++ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true); + } + +-static int ata_port_suspend(struct device *dev) ++static int ata_port_pm_suspend(struct device *dev) + { ++ struct ata_port *ap = to_ata_port(dev); ++ + if (pm_runtime_suspended(dev)) + return 0; + +- return ata_port_suspend_common(dev, PMSG_SUSPEND); ++ ata_port_suspend(ap, PMSG_SUSPEND); ++ return 0; + } + +-static int ata_port_do_freeze(struct device *dev) ++static int ata_port_pm_freeze(struct device *dev) + { ++ struct ata_port *ap = to_ata_port(dev); ++ + if (pm_runtime_suspended(dev)) + return 0; + +- return ata_port_suspend_common(dev, PMSG_FREEZE); ++ ata_port_suspend(ap, PMSG_FREEZE); ++ return 0; + } + +-static int ata_port_poweroff(struct device *dev) ++static int ata_port_pm_poweroff(struct device *dev) + { +- return ata_port_suspend_common(dev, PMSG_HIBERNATE); ++ ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE); ++ return 0; + } + +-static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg, +- int *async) +-{ +- int rc; ++static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY ++ | ATA_EHI_QUIET; + +- rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET, +- ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async); +- return rc; ++static void ata_port_resume(struct ata_port *ap, pm_message_t mesg) ++{ ++ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, false); + } + +-static int ata_port_resume_common(struct device *dev, pm_message_t mesg) ++static void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg) + { +- struct ata_port *ap = to_ata_port(dev); +- +- return __ata_port_resume_common(ap, mesg, NULL); ++ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true); + } + +-static int ata_port_resume(struct device *dev) ++static int ata_port_pm_resume(struct device *dev) + { +- int rc; +- +- rc = ata_port_resume_common(dev, PMSG_RESUME); +- if (!rc) { +- pm_runtime_disable(dev); +- pm_runtime_set_active(dev); +- pm_runtime_enable(dev); +- } +- +- return rc; ++ ata_port_resume_async(to_ata_port(dev), PMSG_RESUME); ++ pm_runtime_disable(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ return 0; + } + + /* +@@ -5517,21 +5501,23 @@ + + static int ata_port_runtime_suspend(struct device *dev) + { +- return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND); ++ ata_port_suspend(to_ata_port(dev), PMSG_AUTO_SUSPEND); ++ return 0; + } + + static int ata_port_runtime_resume(struct device *dev) + { +- return ata_port_resume_common(dev, PMSG_AUTO_RESUME); ++ ata_port_resume(to_ata_port(dev), PMSG_AUTO_RESUME); ++ return 0; + } + + static const struct dev_pm_ops ata_port_pm_ops = { +- .suspend = ata_port_suspend, +- .resume = ata_port_resume, +- .freeze = ata_port_do_freeze, +- .thaw = ata_port_resume, +- .poweroff = ata_port_poweroff, +- .restore = ata_port_resume, ++ .suspend = ata_port_pm_suspend, ++ .resume = ata_port_pm_resume, ++ .freeze = ata_port_pm_freeze, ++ .thaw = ata_port_pm_resume, ++ .poweroff = ata_port_pm_poweroff, ++ .restore = ata_port_pm_resume, + + .runtime_suspend = ata_port_runtime_suspend, + .runtime_resume = ata_port_runtime_resume, +@@ -5543,18 +5529,17 @@ + * level. sas suspend/resume is async to allow parallel port recovery + * since sas has multiple ata_port instances per Scsi_Host. + */ +-int ata_sas_port_async_suspend(struct ata_port *ap, int *async) ++void ata_sas_port_suspend(struct ata_port *ap) + { +- return __ata_port_suspend_common(ap, PMSG_SUSPEND, async); ++ ata_port_suspend_async(ap, PMSG_SUSPEND); + } +-EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend); ++EXPORT_SYMBOL_GPL(ata_sas_port_suspend); + +-int ata_sas_port_async_resume(struct ata_port *ap, int *async) ++void ata_sas_port_resume(struct ata_port *ap) + { +- return __ata_port_resume_common(ap, PMSG_RESUME, async); ++ ata_port_resume_async(ap, PMSG_RESUME); + } +-EXPORT_SYMBOL_GPL(ata_sas_port_async_resume); +- ++EXPORT_SYMBOL_GPL(ata_sas_port_resume); + + /** + * ata_host_suspend - suspend host +diff -Nur linux-3.14.72.orig/drivers/ata/libata-eh.c linux-3.14.72/drivers/ata/libata-eh.c +--- linux-3.14.72.orig/drivers/ata/libata-eh.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/libata-eh.c 2016-06-19 22:11:55.089154177 +0200 +@@ -95,12 +95,13 @@ + * represents timeout for that try. The first try can be soft or + * hardreset. All others are hardreset if available. In most cases + * the first reset w/ 10sec timeout should succeed. Following entries +- * are mostly for error handling, hotplug and retarded devices. ++ * are mostly for error handling, hotplug and those outlier devices that ++ * take an exceptionally long time to recover from reset. + */ + static const unsigned long ata_eh_reset_timeouts[] = { + 10000, /* most drives spin up by 10sec */ + 10000, /* > 99% working drives spin up before 20sec */ +- 35000, /* give > 30 secs of idleness for retarded devices */ ++ 35000, /* give > 30 secs of idleness for outlier devices */ + 5000, /* and sweet one last chance */ + ULONG_MAX, /* > 1 min has elapsed, give up */ + }; +@@ -1810,7 +1811,7 @@ + case ATA_DEV_ATA: + if (err & ATA_ICRC) + qc->err_mask |= AC_ERR_ATA_BUS; +- if (err & ATA_UNC) ++ if (err & (ATA_UNC | ATA_AMNF)) + qc->err_mask |= AC_ERR_MEDIA; + if (err & ATA_IDNF) + qc->err_mask |= AC_ERR_INVALID; +@@ -2555,11 +2556,12 @@ + } + + if (cmd->command != ATA_CMD_PACKET && +- (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | +- ATA_ABORTED))) +- ata_dev_err(qc->dev, "error: { %s%s%s%s}\n", ++ (res->feature & (ATA_ICRC | ATA_UNC | ATA_AMNF | ++ ATA_IDNF | ATA_ABORTED))) ++ ata_dev_err(qc->dev, "error: { %s%s%s%s%s}\n", + res->feature & ATA_ICRC ? "ICRC " : "", + res->feature & ATA_UNC ? "UNC " : "", ++ res->feature & ATA_AMNF ? "AMNF " : "", + res->feature & ATA_IDNF ? "IDNF " : "", + res->feature & ATA_ABORTED ? "ABRT " : ""); + #endif +@@ -4072,7 +4074,7 @@ + + ata_acpi_set_state(ap, ap->pm_mesg); + out: +- /* report result */ ++ /* update the flags */ + spin_lock_irqsave(ap->lock, flags); + + ap->pflags &= ~ATA_PFLAG_PM_PENDING; +@@ -4081,11 +4083,6 @@ + else if (ap->pflags & ATA_PFLAG_FROZEN) + ata_port_schedule_eh(ap); + +- if (ap->pm_result) { +- *ap->pm_result = rc; +- ap->pm_result = NULL; +- } +- + spin_unlock_irqrestore(ap->lock, flags); + + return; +@@ -4137,13 +4134,9 @@ + /* tell ACPI that we're resuming */ + ata_acpi_on_resume(ap); + +- /* report result */ ++ /* update the flags */ + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); +- if (ap->pm_result) { +- *ap->pm_result = rc; +- ap->pm_result = NULL; +- } + spin_unlock_irqrestore(ap->lock, flags); + } + #endif /* CONFIG_PM */ +diff -Nur linux-3.14.72.orig/drivers/ata/libata-scsi.c linux-3.14.72/drivers/ata/libata-scsi.c +--- linux-3.14.72.orig/drivers/ata/libata-scsi.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/libata-scsi.c 2016-06-19 22:11:55.089154177 +0200 +@@ -1992,7 +1992,11 @@ + memcpy(rbuf, hdr, sizeof(hdr)); + memcpy(&rbuf[8], "ATA ", 8); + ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); +- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); ++ ++ /* From SAT, use last 2 words from fw rev unless they are spaces */ ++ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); ++ if (strncmp(&rbuf[32], " ", 4) == 0) ++ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); + + if (rbuf[32] == 0 || rbuf[32] == ' ') + memcpy(&rbuf[32], "n/a ", 4); +diff -Nur linux-3.14.72.orig/drivers/ata/libata-sff.c linux-3.14.72/drivers/ata/libata-sff.c +--- linux-3.14.72.orig/drivers/ata/libata-sff.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/libata-sff.c 2016-06-19 22:11:55.089154177 +0200 +@@ -2433,15 +2433,6 @@ + mask = (1 << 2) | (1 << 0); + if ((tmp8 & mask) != mask) + legacy_mode = 1; +-#if defined(CONFIG_NO_ATA_LEGACY) +- /* Some platforms with PCI limits cannot address compat +- port space. In that case we punt if their firmware has +- left a device in compatibility mode */ +- if (legacy_mode) { +- printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); +- return -EOPNOTSUPP; +- } +-#endif + } + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) +diff -Nur linux-3.14.72.orig/drivers/ata/libata-zpodd.c linux-3.14.72/drivers/ata/libata-zpodd.c +--- linux-3.14.72.orig/drivers/ata/libata-zpodd.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/libata-zpodd.c 2016-06-19 22:11:55.089154177 +0200 +@@ -85,21 +85,6 @@ + return ODD_MECH_TYPE_UNSUPPORTED; + } + +-static bool odd_can_poweroff(struct ata_device *ata_dev) +-{ +- acpi_handle handle; +- struct acpi_device *acpi_dev; +- +- handle = ata_dev_acpi_handle(ata_dev); +- if (!handle) +- return false; +- +- if (acpi_bus_get_device(handle, &acpi_dev)) +- return false; +- +- return acpi_device_can_poweroff(acpi_dev); +-} +- + /* Test if ODD is zero power ready by sense code */ + static bool zpready(struct ata_device *dev) + { +@@ -267,13 +252,11 @@ + + void zpodd_init(struct ata_device *dev) + { ++ struct acpi_device *adev = ACPI_COMPANION(&dev->tdev); + enum odd_mech_type mech_type; + struct zpodd *zpodd; + +- if (dev->zpodd) +- return; +- +- if (!odd_can_poweroff(dev)) ++ if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev)) + return; + + mech_type = zpodd_get_mech_type(dev); +diff -Nur linux-3.14.72.orig/drivers/ata/Makefile linux-3.14.72/drivers/ata/Makefile +--- linux-3.14.72.orig/drivers/ata/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/Makefile 2016-06-19 22:11:55.089154177 +0200 +@@ -4,13 +4,19 @@ + # 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_DA850) += ahci_da850.o libahci.o libahci_platform.o ++obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o ++obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o ++obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o ++obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o ++obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o ++obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o + + # SFF w/ custom DMA + obj-$(CONFIG_PDC_ADMA) += pdc_adma.o +diff -Nur linux-3.14.72.orig/drivers/ata/pata_acpi.c linux-3.14.72/drivers/ata/pata_acpi.c +--- linux-3.14.72.orig/drivers/ata/pata_acpi.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_acpi.c 2016-06-19 22:11:55.089154177 +0200 +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -266,7 +265,7 @@ + .id_table = pacpi_pci_tbl, + .probe = pacpi_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_ali.c linux-3.14.72/drivers/ata/pata_ali.c +--- linux-3.14.72.orig/drivers/ata/pata_ali.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_ali.c 2016-06-19 22:11:55.089154177 +0200 +@@ -589,7 +589,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &ali_sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int ali_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -616,7 +616,7 @@ + .id_table = ali, + .probe = ali_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ali_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_amd.c linux-3.14.72/drivers/ata/pata_amd.c +--- linux-3.14.72.orig/drivers/ata/pata_amd.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_amd.c 2016-06-19 22:11:55.089154177 +0200 +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -575,7 +574,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &amd_sht, hpriv, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int amd_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -626,7 +625,7 @@ + .id_table = amd, + .probe = amd_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = amd_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_arasan_cf.c linux-3.14.72/drivers/ata/pata_arasan_cf.c +--- linux-3.14.72.orig/drivers/ata/pata_arasan_cf.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_arasan_cf.c 2016-06-19 22:11:55.089154177 +0200 +@@ -356,7 +356,7 @@ + + static void dma_callback(void *dev) + { +- struct arasan_cf_dev *acdev = (struct arasan_cf_dev *) dev; ++ struct arasan_cf_dev *acdev = dev; + + complete(&acdev->dma_completion); + } +diff -Nur linux-3.14.72.orig/drivers/ata/pata_artop.c linux-3.14.72/drivers/ata/pata_artop.c +--- linux-3.14.72.orig/drivers/ata/pata_artop.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_artop.c 2016-06-19 22:11:55.089154177 +0200 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -423,7 +422,7 @@ + { } /* terminate list */ + }; + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int atp8xx_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -445,7 +444,7 @@ + .id_table = artop_pci_tbl, + .probe = artop_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = atp8xx_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_at91.c linux-3.14.72/drivers/ata/pata_at91.c +--- linux-3.14.72.orig/drivers/ata/pata_at91.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_at91.c 2016-06-19 22:11:55.089154177 +0200 +@@ -18,7 +18,6 @@ + + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/pata_atiixp.c linux-3.14.72/drivers/ata/pata_atiixp.c +--- linux-3.14.72.orig/drivers/ata/pata_atiixp.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_atiixp.c 2016-06-19 22:11:55.093153915 +0200 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -299,7 +298,7 @@ + .id_table = atiixp, + .probe = atiixp_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .resume = ata_pci_device_resume, + .suspend = ata_pci_device_suspend, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_atp867x.c linux-3.14.72/drivers/ata/pata_atp867x.c +--- linux-3.14.72.orig/drivers/ata/pata_atp867x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_atp867x.c 2016-06-19 22:11:55.093153915 +0200 +@@ -29,7 +29,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -531,7 +530,7 @@ + return rc; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int atp867x_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -559,7 +558,7 @@ + .id_table = atp867x_pci_tbl, + .probe = atp867x_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = atp867x_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_bf54x.c linux-3.14.72/drivers/ata/pata_bf54x.c +--- linux-3.14.72.orig/drivers/ata/pata_bf54x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_bf54x.c 2016-06-19 22:11:55.093153915 +0200 +@@ -1619,7 +1619,7 @@ + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state) + { + struct ata_host *host = platform_get_drvdata(pdev); +diff -Nur linux-3.14.72.orig/drivers/ata/pata_cmd640.c linux-3.14.72/drivers/ata/pata_cmd640.c +--- linux-3.14.72.orig/drivers/ata/pata_cmd640.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_cmd640.c 2016-06-19 22:11:55.093153915 +0200 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -232,7 +231,7 @@ + return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int cmd640_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -257,7 +256,7 @@ + .id_table = cmd640, + .probe = cmd640_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = cmd640_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_cmd64x.c linux-3.14.72/drivers/ata/pata_cmd64x.c +--- linux-3.14.72.orig/drivers/ata/pata_cmd64x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_cmd64x.c 2016-06-19 22:11:55.093153915 +0200 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -488,7 +487,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &cmd64x_sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int cmd64x_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -519,7 +518,7 @@ + .id_table = cmd64x, + .probe = cmd64x_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = cmd64x_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_cs5520.c linux-3.14.72/drivers/ata/pata_cs5520.c +--- linux-3.14.72.orig/drivers/ata/pata_cs5520.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_cs5520.c 2016-06-19 22:11:55.093153915 +0200 +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -230,7 +229,7 @@ + return ata_host_register(host, &cs5520_sht); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + /** + * cs5520_reinit_one - device resume + * @pdev: PCI device +@@ -279,7 +278,7 @@ + pci_save_state(pdev); + return 0; + } +-#endif /* CONFIG_PM */ ++#endif /* CONFIG_PM_SLEEP */ + + /* For now keep DMA off. We can set it for all but A rev CS5510 once the + core ATA code can handle it */ +@@ -296,7 +295,7 @@ + .id_table = pata_cs5520, + .probe = cs5520_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = cs5520_pci_device_suspend, + .resume = cs5520_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_cs5530.c linux-3.14.72/drivers/ata/pata_cs5530.c +--- linux-3.14.72.orig/drivers/ata/pata_cs5530.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_cs5530.c 2016-06-19 22:11:55.093153915 +0200 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -327,7 +326,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &cs5530_sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int cs5530_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -344,7 +343,7 @@ + ata_host_resume(host); + return 0; + } +-#endif /* CONFIG_PM */ ++#endif /* CONFIG_PM_SLEEP */ + + static const struct pci_device_id cs5530[] = { + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, +@@ -357,7 +356,7 @@ + .id_table = cs5530, + .probe = cs5530_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = cs5530_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_cs5535.c linux-3.14.72/drivers/ata/pata_cs5535.c +--- linux-3.14.72.orig/drivers/ata/pata_cs5535.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_cs5535.c 2016-06-19 22:11:55.093153915 +0200 +@@ -31,7 +31,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -201,7 +200,7 @@ + .id_table = cs5535, + .probe = cs5535_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_cs5536.c linux-3.14.72/drivers/ata/pata_cs5536.c +--- linux-3.14.72.orig/drivers/ata/pata_cs5536.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_cs5536.c 2016-06-19 22:11:55.093153915 +0200 +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -298,7 +297,7 @@ + .id_table = cs5536, + .probe = cs5536_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_cypress.c linux-3.14.72/drivers/ata/pata_cypress.c +--- linux-3.14.72.orig/drivers/ata/pata_cypress.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_cypress.c 2016-06-19 22:11:55.093153915 +0200 +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -152,7 +151,7 @@ + .id_table = cy82c693, + .probe = cy82c693_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_efar.c linux-3.14.72/drivers/ata/pata_efar.c +--- linux-3.14.72.orig/drivers/ata/pata_efar.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_efar.c 2016-06-19 22:11:55.093153915 +0200 +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -289,7 +288,7 @@ + .id_table = efar_pci_tbl, + .probe = efar_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_ep93xx.c linux-3.14.72/drivers/ata/pata_ep93xx.c +--- linux-3.14.72.orig/drivers/ata/pata_ep93xx.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_ep93xx.c 2016-06-19 22:11:55.093153915 +0200 +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -709,8 +708,8 @@ + struct dma_chan *channel = qc->dma_dir == DMA_TO_DEVICE + ? drv_data->dma_tx_channel : drv_data->dma_rx_channel; + +- txd = channel->device->device_prep_slave_sg(channel, qc->sg, +- qc->n_elem, qc->dma_dir, DMA_CTRL_ACK, NULL); ++ txd = dmaengine_prep_slave_sg(channel, qc->sg, qc->n_elem, qc->dma_dir, ++ DMA_CTRL_ACK); + if (!txd) { + dev_err(qc->ap->dev, "failed to prepare slave for sg dma\n"); + return; +diff -Nur linux-3.14.72.orig/drivers/ata/pata_hpt366.c linux-3.14.72/drivers/ata/pata_hpt366.c +--- linux-3.14.72.orig/drivers/ata/pata_hpt366.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_hpt366.c 2016-06-19 22:11:55.093153915 +0200 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -387,7 +386,7 @@ + return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int hpt36x_reinit_one(struct pci_dev *dev) + { + struct ata_host *host = pci_get_drvdata(dev); +@@ -412,7 +411,7 @@ + .id_table = hpt36x, + .probe = hpt36x_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = hpt36x_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_hpt37x.c linux-3.14.72/drivers/ata/pata_hpt37x.c +--- linux-3.14.72.orig/drivers/ata/pata_hpt37x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_hpt37x.c 2016-06-19 22:11:55.093153915 +0200 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/pata_hpt3x2n.c linux-3.14.72/drivers/ata/pata_hpt3x2n.c +--- linux-3.14.72.orig/drivers/ata/pata_hpt3x2n.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_hpt3x2n.c 2016-06-19 22:11:55.093153915 +0200 +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/pata_hpt3x3.c linux-3.14.72/drivers/ata/pata_hpt3x3.c +--- linux-3.14.72.orig/drivers/ata/pata_hpt3x3.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_hpt3x3.c 2016-06-19 22:11:55.093153915 +0200 +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -250,7 +249,7 @@ + IRQF_SHARED, &hpt3x3_sht); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int hpt3x3_reinit_one(struct pci_dev *dev) + { + struct ata_host *host = pci_get_drvdata(dev); +@@ -278,7 +277,7 @@ + .id_table = hpt3x3, + .probe = hpt3x3_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = hpt3x3_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_imx.c linux-3.14.72/drivers/ata/pata_imx.c +--- linux-3.14.72.orig/drivers/ata/pata_imx.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_imx.c 2016-06-19 22:11:55.093153915 +0200 +@@ -15,7 +15,6 @@ + */ + #include + #include +-#include + #include + #include + #include +@@ -191,7 +190,7 @@ + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int pata_imx_suspend(struct device *dev) + { + struct ata_host *host = dev_get_drvdata(dev); +@@ -250,7 +249,7 @@ + .name = DRV_NAME, + .of_match_table = imx_pata_dt_ids, + .owner = THIS_MODULE, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .pm = &pata_imx_pm_ops, + #endif + }, +diff -Nur linux-3.14.72.orig/drivers/ata/pata_it8213.c linux-3.14.72/drivers/ata/pata_it8213.c +--- linux-3.14.72.orig/drivers/ata/pata_it8213.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_it8213.c 2016-06-19 22:11:55.093153915 +0200 +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -284,7 +283,7 @@ + .id_table = it8213_pci_tbl, + .probe = it8213_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_it821x.c linux-3.14.72/drivers/ata/pata_it821x.c +--- linux-3.14.72.orig/drivers/ata/pata_it821x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_it821x.c 2016-06-19 22:11:55.093153915 +0200 +@@ -72,7 +72,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -936,7 +935,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &it821x_sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int it821x_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -966,7 +965,7 @@ + .id_table = it821x, + .probe = it821x_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = it821x_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_jmicron.c linux-3.14.72/drivers/ata/pata_jmicron.c +--- linux-3.14.72.orig/drivers/ata/pata_jmicron.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_jmicron.c 2016-06-19 22:11:55.093153915 +0200 +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -158,7 +157,7 @@ + .id_table = jmicron_pci_tbl, + .probe = jmicron_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_legacy.c linux-3.14.72/drivers/ata/pata_legacy.c +--- linux-3.14.72.orig/drivers/ata/pata_legacy.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_legacy.c 2016-06-19 22:11:55.093153915 +0200 +@@ -916,7 +916,6 @@ + local_irq_restore(flags); + return BIOS; + } +- local_irq_restore(flags); + } + + if (ht6560a & mask) +diff -Nur linux-3.14.72.orig/drivers/ata/pata_macio.c linux-3.14.72/drivers/ata/pata_macio.c +--- linux-3.14.72.orig/drivers/ata/pata_macio.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_macio.c 2016-06-19 22:11:55.097153654 +0200 +@@ -845,8 +845,7 @@ + return 0; + } + +-#ifdef CONFIG_PM +- ++#ifdef CONFIG_PM_SLEEP + static int pata_macio_do_suspend(struct pata_macio_priv *priv, pm_message_t mesg) + { + int rc; +@@ -907,8 +906,7 @@ + + return 0; + } +- +-#endif /* CONFIG_PM */ ++#endif /* CONFIG_PM_SLEEP */ + + static struct scsi_host_template pata_macio_sht = { + ATA_BASE_SHT(DRV_NAME), +@@ -1208,8 +1206,7 @@ + return 0; + } + +-#ifdef CONFIG_PM +- ++#ifdef CONFIG_PM_SLEEP + static int pata_macio_suspend(struct macio_dev *mdev, pm_message_t mesg) + { + struct ata_host *host = macio_get_drvdata(mdev); +@@ -1223,8 +1220,7 @@ + + return pata_macio_do_resume(host->private_data); + } +- +-#endif /* CONFIG_PM */ ++#endif /* CONFIG_PM_SLEEP */ + + #ifdef CONFIG_PMAC_MEDIABAY + static void pata_macio_mb_event(struct macio_dev* mdev, int mb_state) +@@ -1316,8 +1312,7 @@ + ata_host_detach(host); + } + +-#ifdef CONFIG_PM +- ++#ifdef CONFIG_PM_SLEEP + static int pata_macio_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -1331,8 +1326,7 @@ + + return pata_macio_do_resume(host->private_data); + } +- +-#endif /* CONFIG_PM */ ++#endif /* CONFIG_PM_SLEEP */ + + static struct of_device_id pata_macio_match[] = + { +@@ -1360,7 +1354,7 @@ + }, + .probe = pata_macio_attach, + .remove = pata_macio_detach, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = pata_macio_suspend, + .resume = pata_macio_resume, + #endif +@@ -1383,7 +1377,7 @@ + .id_table = pata_macio_pci_match, + .probe = pata_macio_pci_attach, + .remove = pata_macio_pci_detach, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = pata_macio_pci_suspend, + .resume = pata_macio_pci_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_marvell.c linux-3.14.72/drivers/ata/pata_marvell.c +--- linux-3.14.72.orig/drivers/ata/pata_marvell.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_marvell.c 2016-06-19 22:11:55.097153654 +0200 +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -172,7 +171,7 @@ + .id_table = marvell_pci_tbl, + .probe = marvell_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_mpc52xx.c linux-3.14.72/drivers/ata/pata_mpc52xx.c +--- linux-3.14.72.orig/drivers/ata/pata_mpc52xx.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_mpc52xx.c 2016-06-19 22:11:55.097153654 +0200 +@@ -819,9 +819,7 @@ + return 0; + } + +- +-#ifdef CONFIG_PM +- ++#ifdef CONFIG_PM_SLEEP + static int + mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state) + { +@@ -847,10 +845,8 @@ + + return 0; + } +- + #endif + +- + static struct of_device_id mpc52xx_ata_of_match[] = { + { .compatible = "fsl,mpc5200-ata", }, + { .compatible = "mpc5200-ata", }, +@@ -861,7 +857,7 @@ + static struct platform_driver mpc52xx_ata_of_platform_driver = { + .probe = mpc52xx_ata_probe, + .remove = mpc52xx_ata_remove, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = mpc52xx_ata_suspend, + .resume = mpc52xx_ata_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_mpiix.c linux-3.14.72/drivers/ata/pata_mpiix.c +--- linux-3.14.72.orig/drivers/ata/pata_mpiix.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_mpiix.c 2016-06-19 22:11:55.097153654 +0200 +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -224,7 +223,7 @@ + .id_table = mpiix, + .probe = mpiix_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_netcell.c linux-3.14.72/drivers/ata/pata_netcell.c +--- linux-3.14.72.orig/drivers/ata/pata_netcell.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_netcell.c 2016-06-19 22:11:55.097153654 +0200 +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -93,7 +92,7 @@ + .id_table = netcell_pci_tbl, + .probe = netcell_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_ninja32.c linux-3.14.72/drivers/ata/pata_ninja32.c +--- linux-3.14.72.orig/drivers/ata/pata_ninja32.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_ninja32.c 2016-06-19 22:11:55.097153654 +0200 +@@ -37,7 +37,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -153,8 +152,7 @@ + IRQF_SHARED, &ninja32_sht); + } + +-#ifdef CONFIG_PM +- ++#ifdef CONFIG_PM_SLEEP + static int ninja32_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -184,7 +182,7 @@ + .id_table = ninja32, + .probe = ninja32_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ninja32_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_ns87410.c linux-3.14.72/drivers/ata/pata_ns87410.c +--- linux-3.14.72.orig/drivers/ata/pata_ns87410.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_ns87410.c 2016-06-19 22:11:55.097153654 +0200 +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -162,7 +161,7 @@ + .id_table = ns87410, + .probe = ns87410_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_ns87415.c linux-3.14.72/drivers/ata/pata_ns87415.c +--- linux-3.14.72.orig/drivers/ata/pata_ns87415.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_ns87415.c 2016-06-19 22:11:55.097153654 +0200 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -386,7 +385,7 @@ + { } /* terminate list */ + }; + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int ns87415_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -408,7 +407,7 @@ + .id_table = ns87415_pci_tbl, + .probe = ns87415_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ns87415_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_oldpiix.c linux-3.14.72/drivers/ata/pata_oldpiix.c +--- linux-3.14.72.orig/drivers/ata/pata_oldpiix.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_oldpiix.c 2016-06-19 22:11:55.097153654 +0200 +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -259,7 +258,7 @@ + .id_table = oldpiix_pci_tbl, + .probe = oldpiix_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_opti.c linux-3.14.72/drivers/ata/pata_opti.c +--- linux-3.14.72.orig/drivers/ata/pata_opti.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_opti.c 2016-06-19 22:11:55.097153654 +0200 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -185,7 +184,7 @@ + .id_table = opti, + .probe = opti_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_optidma.c linux-3.14.72/drivers/ata/pata_optidma.c +--- linux-3.14.72.orig/drivers/ata/pata_optidma.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_optidma.c 2016-06-19 22:11:55.097153654 +0200 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -441,7 +440,7 @@ + .id_table = optidma, + .probe = optidma_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_pcmcia.c linux-3.14.72/drivers/ata/pata_pcmcia.c +--- linux-3.14.72.orig/drivers/ata/pata_pcmcia.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_pcmcia.c 2016-06-19 22:11:55.097153654 +0200 +@@ -26,7 +26,6 @@ + + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/pata_pdc2027x.c linux-3.14.72/drivers/ata/pata_pdc2027x.c +--- linux-3.14.72.orig/drivers/ata/pata_pdc2027x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_pdc2027x.c 2016-06-19 22:11:55.097153654 +0200 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -63,7 +62,7 @@ + }; + + static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int pdc2027x_reinit_one(struct pci_dev *pdev); + #endif + static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline); +@@ -129,7 +128,7 @@ + .id_table = pdc2027x_pci_tbl, + .probe = pdc2027x_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = pdc2027x_reinit_one, + #endif +@@ -762,7 +761,7 @@ + IRQF_SHARED, &pdc2027x_sht); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int pdc2027x_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +diff -Nur linux-3.14.72.orig/drivers/ata/pata_pdc202xx_old.c linux-3.14.72/drivers/ata/pata_pdc202xx_old.c +--- linux-3.14.72.orig/drivers/ata/pata_pdc202xx_old.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_pdc202xx_old.c 2016-06-19 22:11:55.097153654 +0200 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -378,7 +377,7 @@ + .id_table = pdc202xx, + .probe = pdc202xx_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_piccolo.c linux-3.14.72/drivers/ata/pata_piccolo.c +--- linux-3.14.72.orig/drivers/ata/pata_piccolo.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_piccolo.c 2016-06-19 22:11:55.097153654 +0200 +@@ -18,7 +18,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -111,7 +110,7 @@ + .id_table = ata_tosh, + .probe = ata_tosh_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_platform.c linux-3.14.72/drivers/ata/pata_platform.c +--- linux-3.14.72.orig/drivers/ata/pata_platform.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_platform.c 2016-06-19 22:11:55.097153654 +0200 +@@ -13,7 +13,6 @@ + */ + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/pata_pxa.c linux-3.14.72/drivers/ata/pata_pxa.c +--- linux-3.14.72.orig/drivers/ata/pata_pxa.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_pxa.c 2016-06-19 22:11:55.097153654 +0200 +@@ -20,7 +20,6 @@ + + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/pata_radisys.c linux-3.14.72/drivers/ata/pata_radisys.c +--- linux-3.14.72.orig/drivers/ata/pata_radisys.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_radisys.c 2016-06-19 22:11:55.097153654 +0200 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -238,7 +237,7 @@ + .id_table = radisys_pci_tbl, + .probe = radisys_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_rdc.c linux-3.14.72/drivers/ata/pata_rdc.c +--- linux-3.14.72.orig/drivers/ata/pata_rdc.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_rdc.c 2016-06-19 22:11:55.097153654 +0200 +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -383,7 +382,7 @@ + .id_table = rdc_pci_tbl, + .probe = rdc_init_one, + .remove = rdc_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_rz1000.c linux-3.14.72/drivers/ata/pata_rz1000.c +--- linux-3.14.72.orig/drivers/ata/pata_rz1000.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_rz1000.c 2016-06-19 22:11:55.097153654 +0200 +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -102,7 +101,7 @@ + return -ENODEV; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int rz1000_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -134,7 +133,7 @@ + .id_table = pata_rz1000, + .probe = rz1000_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = rz1000_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_samsung_cf.c linux-3.14.72/drivers/ata/pata_samsung_cf.c +--- linux-3.14.72.orig/drivers/ata/pata_samsung_cf.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_samsung_cf.c 2016-06-19 22:11:55.097153654 +0200 +@@ -54,7 +54,6 @@ + + enum s3c_cpu_type { + TYPE_S3C64XX, +- TYPE_S5PC100, + TYPE_S5PV210, + }; + +@@ -476,10 +475,6 @@ + writel(0x1b, info->ide_addr + S3C_ATA_IRQ_MSK); + break; + +- case TYPE_S5PC100: +- pata_s3c_cfg_mode(info->sfr_addr); +- /* FALLTHROUGH */ +- + case TYPE_S5PV210: + /* Configure as little endian */ + pata_s3c_set_endian(info->ide_addr, 0); +@@ -549,11 +544,6 @@ + info->sfr_addr = info->ide_addr + 0x1800; + info->ide_addr += 0x1900; + info->fifo_status_reg = 0x94; +- } else if (cpu_type == TYPE_S5PC100) { +- ap->ops = &pata_s5p_port_ops; +- info->sfr_addr = info->ide_addr + 0x1800; +- info->ide_addr += 0x1900; +- info->fifo_status_reg = 0x84; + } else { + ap->ops = &pata_s5p_port_ops; + info->fifo_status_reg = 0x84; +@@ -615,7 +605,7 @@ + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int pata_s3c_suspend(struct device *dev) + { + struct platform_device *pdev = to_platform_device(dev); +@@ -649,9 +639,6 @@ + .name = "s3c64xx-pata", + .driver_data = TYPE_S3C64XX, + }, { +- .name = "s5pc100-pata", +- .driver_data = TYPE_S5PC100, +- }, { + .name = "s5pv210-pata", + .driver_data = TYPE_S5PV210, + }, +@@ -666,7 +653,7 @@ + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .pm = &pata_s3c_pm_ops, + #endif + }, +diff -Nur linux-3.14.72.orig/drivers/ata/pata_sc1200.c linux-3.14.72/drivers/ata/pata_sc1200.c +--- linux-3.14.72.orig/drivers/ata/pata_sc1200.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_sc1200.c 2016-06-19 22:11:55.097153654 +0200 +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -255,7 +254,7 @@ + .id_table = sc1200, + .probe = sc1200_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_scc.c linux-3.14.72/drivers/ata/pata_scc.c +--- linux-3.14.72.orig/drivers/ata/pata_scc.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_scc.c 2016-06-19 22:11:55.097153654 +0200 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -1096,7 +1095,7 @@ + .id_table = scc_pci_tbl, + .probe = scc_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_sch.c linux-3.14.72/drivers/ata/pata_sch.c +--- linux-3.14.72.orig/drivers/ata/pata_sch.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_sch.c 2016-06-19 22:11:55.097153654 +0200 +@@ -27,7 +27,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -65,7 +64,7 @@ + .id_table = sch_pci_tbl, + .probe = sch_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_serverworks.c linux-3.14.72/drivers/ata/pata_serverworks.c +--- linux-3.14.72.orig/drivers/ata/pata_serverworks.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_serverworks.c 2016-06-19 22:11:55.097153654 +0200 +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -446,7 +445,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int serverworks_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -478,7 +477,7 @@ + .id_table = serverworks, + .probe = serverworks_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = serverworks_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_sil680.c linux-3.14.72/drivers/ata/pata_sil680.c +--- linux-3.14.72.orig/drivers/ata/pata_sil680.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_sil680.c 2016-06-19 22:11:55.097153654 +0200 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -404,7 +403,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &sil680_sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sil680_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -430,7 +429,7 @@ + .id_table = sil680, + .probe = sil680_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = sil680_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_sis.c linux-3.14.72/drivers/ata/pata_sis.c +--- linux-3.14.72.orig/drivers/ata/pata_sis.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_sis.c 2016-06-19 22:11:55.101153393 +0200 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -870,7 +869,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &sis_sht, chipset, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sis_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -900,7 +899,7 @@ + .id_table = sis_pci_tbl, + .probe = sis_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = sis_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_sl82c105.c linux-3.14.72/drivers/ata/pata_sl82c105.c +--- linux-3.14.72.orig/drivers/ata/pata_sl82c105.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_sl82c105.c 2016-06-19 22:11:55.101153393 +0200 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -338,7 +337,7 @@ + return ata_pci_bmdma_init_one(dev, ppi, &sl82c105_sht, NULL, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sl82c105_reinit_one(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -366,7 +365,7 @@ + .id_table = sl82c105, + .probe = sl82c105_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = sl82c105_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_triflex.c linux-3.14.72/drivers/ata/pata_triflex.c +--- linux-3.14.72.orig/drivers/ata/pata_triflex.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_triflex.c 2016-06-19 22:11:55.101153393 +0200 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -208,7 +207,7 @@ + { }, + }; + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -234,7 +233,7 @@ + .id_table = triflex, + .probe = triflex_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = triflex_ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pata_via.c linux-3.14.72/drivers/ata/pata_via.c +--- linux-3.14.72.orig/drivers/ata/pata_via.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pata_via.c 2016-06-19 22:11:55.101153393 +0200 +@@ -55,7 +55,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -660,7 +659,7 @@ + return ata_pci_bmdma_init_one(pdev, ppi, &via_sht, (void *)config, 0); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + /** + * via_reinit_one - reinit after resume + * @pdev; PCI device +@@ -705,7 +704,7 @@ + .id_table = via, + .probe = via_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = via_reinit_one, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/pdc_adma.c linux-3.14.72/drivers/ata/pdc_adma.c +--- linux-3.14.72.orig/drivers/ata/pdc_adma.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/pdc_adma.c 2016-06-19 22:11:55.101153393 +0200 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/sata_dwc_460ex.c linux-3.14.72/drivers/ata/sata_dwc_460ex.c +--- linux-3.14.72.orig/drivers/ata/sata_dwc_460ex.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_dwc_460ex.c 2016-06-19 22:11:55.101153393 +0200 +@@ -29,7 +29,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -462,8 +461,7 @@ + int chan; + u32 tfr_reg, err_reg; + unsigned long flags; +- struct sata_dwc_device *hsdev = +- (struct sata_dwc_device *)hsdev_instance; ++ struct sata_dwc_device *hsdev = hsdev_instance; + struct ata_host *host = (struct ata_host *)hsdev->host; + struct ata_port *ap; + struct sata_dwc_device_port *hsdevp; +diff -Nur linux-3.14.72.orig/drivers/ata/sata_fsl.c linux-3.14.72/drivers/ata/sata_fsl.c +--- linux-3.14.72.orig/drivers/ata/sata_fsl.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_fsl.c 2016-06-19 22:11:55.101153393 +0200 +@@ -734,13 +734,12 @@ + if (!pp) + return -ENOMEM; + +- mem = dma_alloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma, +- GFP_KERNEL); ++ mem = dma_zalloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma, ++ GFP_KERNEL); + if (!mem) { + kfree(pp); + return -ENOMEM; + } +- memset(mem, 0, SATA_FSL_PORT_PRIV_DMA_SZ); + + pp->cmdslot = mem; + pp->cmdslot_paddr = mem_dma; +@@ -774,20 +773,6 @@ + VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL)); + VPRINTK("CHBA = 0x%x\n", ioread32(hcr_base + CHBA)); + +-#ifdef CONFIG_MPC8315_DS +- /* +- * Workaround for 8315DS board 3gbps link-up issue, +- * currently limit SATA port to GEN1 speed +- */ +- sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp); +- temp &= ~(0xF << 4); +- temp |= (0x1 << 4); +- sata_fsl_scr_write(&ap->link, SCR_CONTROL, temp); +- +- sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp); +- dev_warn(dev, "scr_control, speed limited to %x\n", temp); +-#endif +- + return 0; + } + +@@ -1588,7 +1573,7 @@ + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sata_fsl_suspend(struct platform_device *op, pm_message_t state) + { + struct ata_host *host = platform_get_drvdata(op); +@@ -1644,7 +1629,7 @@ + }, + .probe = sata_fsl_probe, + .remove = sata_fsl_remove, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = sata_fsl_suspend, + .resume = sata_fsl_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/sata_highbank.c linux-3.14.72/drivers/ata/sata_highbank.c +--- linux-3.14.72.orig/drivers/ata/sata_highbank.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_highbank.c 2016-06-19 22:11:55.101153393 +0200 +@@ -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); +@@ -512,7 +512,7 @@ + return rc; + + +- ahci_save_initial_config(dev, hpriv, 0, 0); ++ ahci_save_initial_config(dev, hpriv); + + /* prepare host */ + if (hpriv->cap & HOST_CAP_NCQ) +diff -Nur linux-3.14.72.orig/drivers/ata/sata_inic162x.c linux-3.14.72/drivers/ata/sata_inic162x.c +--- linux-3.14.72.orig/drivers/ata/sata_inic162x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_inic162x.c 2016-06-19 22:11:55.101153393 +0200 +@@ -785,7 +785,7 @@ + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int inic_pci_device_resume(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -898,7 +898,7 @@ + static struct pci_driver inic_pci_driver = { + .name = DRV_NAME, + .id_table = inic_pci_tbl, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = inic_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/sata_mv.c linux-3.14.72/drivers/ata/sata_mv.c +--- linux-3.14.72.orig/drivers/ata/sata_mv.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_mv.c 2016-06-19 22:11:55.101153393 +0200 +@@ -4222,7 +4222,7 @@ + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int mv_platform_suspend(struct platform_device *pdev, pm_message_t state) + { + struct ata_host *host = platform_get_drvdata(pdev); +@@ -4289,7 +4289,7 @@ + #ifdef CONFIG_PCI + static int mv_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent); +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int mv_pci_device_resume(struct pci_dev *pdev); + #endif + +@@ -4299,7 +4299,7 @@ + .id_table = mv_pci_tbl, + .probe = mv_pci_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = mv_pci_device_resume, + #endif +@@ -4457,7 +4457,7 @@ + IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int mv_pci_device_resume(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +diff -Nur linux-3.14.72.orig/drivers/ata/sata_nv.c linux-3.14.72/drivers/ata/sata_nv.c +--- linux-3.14.72.orig/drivers/ata/sata_nv.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_nv.c 2016-06-19 22:11:55.101153393 +0200 +@@ -40,7 +40,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -296,7 +295,7 @@ + #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & (1 << (19 + (12 * (PORT))))) + + static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int nv_pci_device_resume(struct pci_dev *pdev); + #endif + static void nv_ck804_host_stop(struct ata_host *host); +@@ -380,7 +379,7 @@ + .name = DRV_NAME, + .id_table = nv_pci_tbl, + .probe = nv_init_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = nv_pci_device_resume, + #endif +@@ -2432,7 +2431,7 @@ + return ata_pci_sff_activate_host(host, ipriv->irq_handler, ipriv->sht); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int nv_pci_device_resume(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +diff -Nur linux-3.14.72.orig/drivers/ata/sata_promise.c linux-3.14.72/drivers/ata/sata_promise.c +--- linux-3.14.72.orig/drivers/ata/sata_promise.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_promise.c 2016-06-19 22:11:55.101153393 +0200 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/sata_qstor.c linux-3.14.72/drivers/ata/sata_qstor.c +--- linux-3.14.72.orig/drivers/ata/sata_qstor.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_qstor.c 2016-06-19 22:11:55.101153393 +0200 +@@ -31,7 +31,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/sata_rcar.c linux-3.14.72/drivers/ata/sata_rcar.c +--- linux-3.14.72.orig/drivers/ata/sata_rcar.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_rcar.c 2016-06-19 22:11:55.101153393 +0200 +@@ -947,7 +947,7 @@ + return 0; + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sata_rcar_suspend(struct device *dev) + { + struct ata_host *host = dev_get_drvdata(dev); +@@ -1001,7 +1001,7 @@ + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = sata_rcar_match, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .pm = &sata_rcar_pm_ops, + #endif + }, +diff -Nur linux-3.14.72.orig/drivers/ata/sata_sil24.c linux-3.14.72/drivers/ata/sata_sil24.c +--- linux-3.14.72.orig/drivers/ata/sata_sil24.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_sil24.c 2016-06-19 22:11:55.105153131 +0200 +@@ -353,8 +353,10 @@ + static void sil24_post_internal_cmd(struct ata_queued_cmd *qc); + static int sil24_port_start(struct ata_port *ap); + static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sil24_pci_device_resume(struct pci_dev *pdev); ++#endif ++#ifdef CONFIG_PM + static int sil24_port_resume(struct ata_port *ap); + #endif + +@@ -375,7 +377,7 @@ + .id_table = sil24_pci_tbl, + .probe = sil24_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = sil24_pci_device_resume, + #endif +@@ -1350,7 +1352,7 @@ + &sil24_sht); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sil24_pci_device_resume(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +@@ -1370,7 +1372,9 @@ + + return 0; + } ++#endif + ++#ifdef CONFIG_PM + static int sil24_port_resume(struct ata_port *ap) + { + sil24_config_pmp(ap, ap->nr_pmp_links); +diff -Nur linux-3.14.72.orig/drivers/ata/sata_sil.c linux-3.14.72/drivers/ata/sata_sil.c +--- linux-3.14.72.orig/drivers/ata/sata_sil.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_sil.c 2016-06-19 22:11:55.105153131 +0200 +@@ -37,7 +37,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -113,7 +112,7 @@ + }; + + static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sil_pci_device_resume(struct pci_dev *pdev); + #endif + static void sil_dev_config(struct ata_device *dev); +@@ -167,7 +166,7 @@ + .id_table = sil_pci_tbl, + .probe = sil_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = sil_pci_device_resume, + #endif +@@ -806,7 +805,7 @@ + &sil_sht); + } + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + static int sil_pci_device_resume(struct pci_dev *pdev) + { + struct ata_host *host = pci_get_drvdata(pdev); +diff -Nur linux-3.14.72.orig/drivers/ata/sata_sis.c linux-3.14.72/drivers/ata/sata_sis.c +--- linux-3.14.72.orig/drivers/ata/sata_sis.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_sis.c 2016-06-19 22:11:55.105153131 +0200 +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -83,7 +82,7 @@ + .id_table = sis_pci_tbl, + .probe = sis_init_one, + .remove = ata_pci_remove_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/sata_svw.c linux-3.14.72/drivers/ata/sata_svw.c +--- linux-3.14.72.orig/drivers/ata/sata_svw.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_svw.c 2016-06-19 22:11:55.105153131 +0200 +@@ -39,7 +39,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/sata_sx4.c linux-3.14.72/drivers/ata/sata_sx4.c +--- linux-3.14.72.orig/drivers/ata/sata_sx4.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_sx4.c 2016-06-19 22:11:55.105153131 +0200 +@@ -82,7 +82,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -1021,8 +1020,7 @@ + idx++; + dist = ((long) (window_size - (offset + size))) >= 0 ? size : + (long) (window_size - offset); +- memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), +- dist); ++ memcpy_fromio(psource, dimm_mmio + offset / 4, dist); + + psource += dist; + size -= dist; +@@ -1031,8 +1029,7 @@ + readl(mmio + PDC_GENERAL_CTLR); + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); +- memcpy_fromio((char *) psource, (char *) (dimm_mmio), +- window_size / 4); ++ memcpy_fromio(psource, dimm_mmio, window_size / 4); + psource += window_size; + size -= window_size; + idx++; +@@ -1043,8 +1040,7 @@ + readl(mmio + PDC_GENERAL_CTLR); + writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); + readl(mmio + PDC_DIMM_WINDOW_CTLR); +- memcpy_fromio((char *) psource, (char *) (dimm_mmio), +- size / 4); ++ memcpy_fromio(psource, dimm_mmio, size / 4); + } + } + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/sata_uli.c linux-3.14.72/drivers/ata/sata_uli.c +--- linux-3.14.72.orig/drivers/ata/sata_uli.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_uli.c 2016-06-19 22:11:55.105153131 +0200 +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/ata/sata_via.c linux-3.14.72/drivers/ata/sata_via.c +--- linux-3.14.72.orig/drivers/ata/sata_via.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_via.c 2016-06-19 22:11:55.105153131 +0200 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -104,7 +103,7 @@ + .name = DRV_NAME, + .id_table = svia_pci_tbl, + .probe = svia_init_one, +-#ifdef CONFIG_PM ++#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, + #endif +diff -Nur linux-3.14.72.orig/drivers/ata/sata_vsc.c linux-3.14.72/drivers/ata/sata_vsc.c +--- linux-3.14.72.orig/drivers/ata/sata_vsc.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/ata/sata_vsc.c 2016-06-19 22:11:55.105153131 +0200 +@@ -37,7 +37,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/base/attribute_container.c linux-3.14.72/drivers/base/attribute_container.c +--- linux-3.14.72.orig/drivers/base/attribute_container.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/attribute_container.c 2016-06-19 22:11:55.105153131 +0200 +@@ -12,7 +12,6 @@ + */ + + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/base/dma-contiguous.c linux-3.14.72/drivers/base/dma-contiguous.c +--- linux-3.14.72.orig/drivers/base/dma-contiguous.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/dma-contiguous.c 2016-06-19 22:11:55.105153131 +0200 +@@ -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.72.orig/drivers/base/Kconfig linux-3.14.72/drivers/base/Kconfig +--- linux-3.14.72.orig/drivers/base/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/Kconfig 2016-06-19 22:11:55.105153131 +0200 +@@ -266,16 +266,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.72.orig/drivers/base/platform.c linux-3.14.72/drivers/base/platform.c +--- linux-3.14.72.orig/drivers/base/platform.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/platform.c 2016-06-19 22:11:55.105153131 +0200 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include "base.h" + #include "power/power.h" +@@ -487,12 +488,16 @@ + struct platform_device *dev = to_platform_device(_dev); + int ret; + +- if (ACPI_HANDLE(_dev)) +- acpi_dev_pm_attach(_dev, true); ++ ret = of_clk_set_defaults(_dev->of_node, false); ++ if (ret < 0) ++ return ret; + +- ret = drv->probe(dev); +- if (ret && ACPI_HANDLE(_dev)) +- acpi_dev_pm_detach(_dev, true); ++ ret = dev_pm_domain_attach(_dev, true); ++ if (ret != -EPROBE_DEFER) { ++ ret = drv->probe(dev); ++ if (ret) ++ dev_pm_domain_detach(_dev, true); ++ } + + if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { + dev_warn(_dev, "probe deferral not supported\n"); +@@ -514,8 +519,7 @@ + int ret; + + ret = drv->remove(dev); +- if (ACPI_HANDLE(_dev)) +- acpi_dev_pm_detach(_dev, true); ++ dev_pm_domain_detach(_dev, true); + + return ret; + } +@@ -526,8 +530,7 @@ + struct platform_device *dev = to_platform_device(_dev); + + drv->shutdown(dev); +- if (ACPI_HANDLE(_dev)) +- acpi_dev_pm_detach(_dev, true); ++ dev_pm_domain_detach(_dev, true); + } + + /** +diff -Nur linux-3.14.72.orig/drivers/base/power/clock_ops.c linux-3.14.72/drivers/base/power/clock_ops.c +--- linux-3.14.72.orig/drivers/base/power/clock_ops.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/power/clock_ops.c 2016-06-19 22:11:55.105153131 +0200 +@@ -6,7 +6,6 @@ + * This file is released under the GPLv2. + */ + +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/base/power/common.c linux-3.14.72/drivers/base/power/common.c +--- linux-3.14.72.orig/drivers/base/power/common.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/power/common.c 2016-06-19 22:11:55.105153131 +0200 +@@ -6,12 +6,13 @@ + * This file is released under the GPLv2. + */ + +-#include + #include + #include + #include + #include + #include ++#include ++#include + + /** + * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device. +@@ -83,3 +84,53 @@ + return ret; + } + EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); ++ ++/** ++ * dev_pm_domain_attach - Attach a device to its PM domain. ++ * @dev: Device to attach. ++ * @power_on: Used to indicate whether we should power on the device. ++ * ++ * The @dev may only be attached to a single PM domain. By iterating through ++ * the available alternatives we try to find a valid PM domain for the device. ++ * As attachment succeeds, the ->detach() callback in the struct dev_pm_domain ++ * should be assigned by the corresponding attach function. ++ * ++ * This function should typically be invoked from subsystem level code during ++ * the probe phase. Especially for those that holds devices which requires ++ * power management through PM domains. ++ * ++ * Callers must ensure proper synchronization of this function with power ++ * management callbacks. ++ * ++ * Returns 0 on successfully attached PM domain or negative error code. ++ */ ++int dev_pm_domain_attach(struct device *dev, bool power_on) ++{ ++ int ret; ++ ++ ret = acpi_dev_pm_attach(dev, power_on); ++ if (ret) ++ ret = genpd_dev_pm_attach(dev); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(dev_pm_domain_attach); ++ ++/** ++ * dev_pm_domain_detach - Detach a device from its PM domain. ++ * @dev: Device to attach. ++ * @power_off: Used to indicate whether we should power off the device. ++ * ++ * This functions will reverse the actions from dev_pm_domain_attach() and thus ++ * try to detach the @dev from its PM domain. Typically it should be invoked ++ * from subsystem level code during the remove phase. ++ * ++ * Callers must ensure proper synchronization of this function with power ++ * management callbacks. ++ */ ++void dev_pm_domain_detach(struct device *dev, bool power_off) ++{ ++ if (dev->pm_domain && dev->pm_domain->detach) ++ dev->pm_domain->detach(dev, power_off); ++} ++EXPORT_SYMBOL_GPL(dev_pm_domain_detach); +diff -Nur linux-3.14.72.orig/drivers/base/power/domain.c linux-3.14.72/drivers/base/power/domain.c +--- linux-3.14.72.orig/drivers/base/power/domain.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/power/domain.c 2016-06-19 22:11:55.105153131 +0200 +@@ -6,9 +6,9 @@ + * This file is released under the GPLv2. + */ + +-#include + #include + #include ++#include + #include + #include + #include +@@ -26,10 +26,6 @@ + __routine = genpd->dev_ops.callback; \ + if (__routine) { \ + __ret = __routine(dev); \ +- } else { \ +- __routine = dev_gpd_data(dev)->ops.callback; \ +- if (__routine) \ +- __ret = __routine(dev); \ + } \ + __ret; \ + }) +@@ -42,7 +38,7 @@ + struct gpd_timing_data *__td = &dev_gpd_data(dev)->td; \ + if (!__retval && __elapsed > __td->field) { \ + __td->field = __elapsed; \ +- dev_warn(dev, name " latency exceeded, new value %lld ns\n", \ ++ dev_dbg(dev, name " latency exceeded, new value %lld ns\n", \ + __elapsed); \ + genpd->max_off_time_changed = true; \ + __td->constraint_changed = true; \ +@@ -71,8 +67,6 @@ + return genpd; + } + +-#ifdef CONFIG_PM +- + struct generic_pm_domain *dev_to_genpd(struct device *dev) + { + if (IS_ERR_OR_NULL(dev->pm_domain)) +@@ -286,8 +280,6 @@ + return genpd ? pm_genpd_poweron(genpd) : -EINVAL; + } + +-#endif /* CONFIG_PM */ +- + #ifdef CONFIG_PM_RUNTIME + + static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd, +@@ -431,7 +423,7 @@ + * Queue up the execution of pm_genpd_poweroff() unless it's already been done + * before. + */ +-void genpd_queue_power_off_work(struct generic_pm_domain *genpd) ++static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) + { + queue_work(pm_wq, &genpd->power_off_work); + } +@@ -620,8 +612,6 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- might_sleep_if(!genpd->dev_irq_safe); +- + stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; + if (stop_ok && !stop_ok(dev)) + return -EBUSY; +@@ -666,8 +656,6 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- might_sleep_if(!genpd->dev_irq_safe); +- + /* If power.irq_safe, the PM domain is never powered off. */ + if (dev->power.irq_safe) + return genpd_start_dev_no_timing(genpd, dev); +@@ -706,6 +694,14 @@ + return 0; + } + ++static bool pd_ignore_unused; ++static int __init pd_ignore_unused_setup(char *__unused) ++{ ++ pd_ignore_unused = true; ++ return 1; ++} ++__setup("pd_ignore_unused", pd_ignore_unused_setup); ++ + /** + * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use. + */ +@@ -713,6 +709,11 @@ + { + struct generic_pm_domain *genpd; + ++ if (pd_ignore_unused) { ++ pr_warn("genpd: Not disabling unused power domains\n"); ++ return; ++ } ++ + mutex_lock(&gpd_list_lock); + + list_for_each_entry(genpd, &gpd_list, gpd_list_node) +@@ -721,6 +722,13 @@ + mutex_unlock(&gpd_list_lock); + } + ++static int __init genpd_poweroff_unused(void) ++{ ++ pm_genpd_poweroff_unused(); ++ return 0; ++} ++late_initcall(genpd_poweroff_unused); ++ + #else + + static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb, +@@ -729,6 +737,9 @@ + return NOTIFY_DONE; + } + ++static inline void ++genpd_queue_power_off_work(struct generic_pm_domain *genpd) {} ++ + static inline void genpd_power_off_work_fn(struct work_struct *work) {} + + #define pm_genpd_runtime_suspend NULL +@@ -762,46 +773,6 @@ + return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev); + } + +-static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, suspend, dev); +-} +- +-static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev); +-} +- +-static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev); +-} +- +-static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, resume, dev); +-} +- +-static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, freeze, dev); +-} +- +-static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev); +-} +- +-static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev); +-} +- +-static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev) +-{ +- return GENPD_DEV_CALLBACK(genpd, int, thaw, dev); +-} +- + /** + * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. + * @genpd: PM domain to power off, if possible. +@@ -983,7 +954,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev); + } + + /** +@@ -1004,7 +975,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_suspend_late(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_suspend_late(dev); + } + + /** +@@ -1028,6 +999,8 @@ + || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) + return 0; + ++ pm_generic_suspend_noirq(dev); ++ + genpd_stop_dev(genpd, dev); + + /* +@@ -1050,6 +1023,7 @@ + static int pm_genpd_resume_noirq(struct device *dev) + { + struct generic_pm_domain *genpd; ++ int ret; + + dev_dbg(dev, "%s()\n", __func__); + +@@ -1069,7 +1043,11 @@ + pm_genpd_sync_poweron(genpd); + genpd->suspended_count--; + +- return genpd_start_dev(genpd, dev); ++ ret = genpd_start_dev(genpd, dev); ++ ++ pm_generic_resume_noirq(dev); ++ ++ return ret; + } + + /** +@@ -1091,7 +1069,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_resume_early(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_resume_early(dev); + } + + /** +@@ -1112,7 +1090,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_resume(dev); + } + + /** +@@ -1133,7 +1111,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev); + } + + /** +@@ -1155,7 +1133,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_freeze_late(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_freeze_late(dev); + } + + /** +@@ -1219,7 +1197,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_thaw_early(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_thaw_early(dev); + } + + /** +@@ -1240,7 +1218,7 @@ + if (IS_ERR(genpd)) + return -EINVAL; + +- return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev); ++ return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev); + } + + /** +@@ -1332,13 +1310,13 @@ + } + + /** +- * pm_genpd_syscore_switch - Switch power during system core suspend or resume. ++ * genpd_syscore_switch - Switch power during system core suspend or resume. + * @dev: Device that normally is marked as "always on" to switch power for. + * + * This routine may only be called during the system core (syscore) suspend or + * resume phase for devices whose "always on" flags are set. + */ +-void pm_genpd_syscore_switch(struct device *dev, bool suspend) ++static void genpd_syscore_switch(struct device *dev, bool suspend) + { + struct generic_pm_domain *genpd; + +@@ -1354,7 +1332,18 @@ + genpd->suspended_count--; + } + } +-EXPORT_SYMBOL_GPL(pm_genpd_syscore_switch); ++ ++void pm_genpd_syscore_poweroff(struct device *dev) ++{ ++ genpd_syscore_switch(dev, true); ++} ++EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweroff); ++ ++void pm_genpd_syscore_poweron(struct device *dev) ++{ ++ genpd_syscore_switch(dev, false); ++} ++EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); + + #else + +@@ -1732,112 +1721,6 @@ + } + + /** +- * pm_genpd_add_callbacks - Add PM domain callbacks to a given device. +- * @dev: Device to add the callbacks to. +- * @ops: Set of callbacks to add. +- * @td: Timing data to add to the device along with the callbacks (optional). +- * +- * Every call to this routine should be balanced with a call to +- * __pm_genpd_remove_callbacks() and they must not be nested. +- */ +-int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops, +- struct gpd_timing_data *td) +-{ +- struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL; +- int ret = 0; +- +- if (!(dev && ops)) +- return -EINVAL; +- +- gpd_data_new = __pm_genpd_alloc_dev_data(dev); +- if (!gpd_data_new) +- return -ENOMEM; +- +- pm_runtime_disable(dev); +- device_pm_lock(); +- +- ret = dev_pm_get_subsys_data(dev); +- if (ret) +- goto out; +- +- spin_lock_irq(&dev->power.lock); +- +- if (dev->power.subsys_data->domain_data) { +- gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); +- } else { +- gpd_data = gpd_data_new; +- dev->power.subsys_data->domain_data = &gpd_data->base; +- } +- gpd_data->refcount++; +- gpd_data->ops = *ops; +- if (td) +- gpd_data->td = *td; +- +- spin_unlock_irq(&dev->power.lock); +- +- out: +- device_pm_unlock(); +- pm_runtime_enable(dev); +- +- if (gpd_data != gpd_data_new) +- __pm_genpd_free_dev_data(dev, gpd_data_new); +- +- return ret; +-} +-EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks); +- +-/** +- * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device. +- * @dev: Device to remove the callbacks from. +- * @clear_td: If set, clear the device's timing data too. +- * +- * This routine can only be called after pm_genpd_add_callbacks(). +- */ +-int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td) +-{ +- struct generic_pm_domain_data *gpd_data = NULL; +- bool remove = false; +- int ret = 0; +- +- if (!(dev && dev->power.subsys_data)) +- return -EINVAL; +- +- pm_runtime_disable(dev); +- device_pm_lock(); +- +- spin_lock_irq(&dev->power.lock); +- +- if (dev->power.subsys_data->domain_data) { +- gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); +- gpd_data->ops = (struct gpd_dev_ops){ NULL }; +- if (clear_td) +- gpd_data->td = (struct gpd_timing_data){ 0 }; +- +- if (--gpd_data->refcount == 0) { +- dev->power.subsys_data->domain_data = NULL; +- remove = true; +- } +- } else { +- ret = -EINVAL; +- } +- +- spin_unlock_irq(&dev->power.lock); +- +- device_pm_unlock(); +- pm_runtime_enable(dev); +- +- if (ret) +- return ret; +- +- dev_pm_put_subsys_data(dev); +- if (remove) +- __pm_genpd_free_dev_data(dev, gpd_data); +- +- return 0; +-} +-EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks); +- +-/** + * pm_genpd_attach_cpuidle - Connect the given PM domain with cpuidle. + * @genpd: PM domain to be connected with cpuidle. + * @state: cpuidle state this domain can disable/enable. +@@ -1958,17 +1841,13 @@ + /* Default device callbacks for generic PM domains. */ + + /** +- * pm_genpd_default_save_state - Default "save device state" for PM domians. ++ * pm_genpd_default_save_state - Default "save device state" for PM domains. + * @dev: Device to handle. + */ + static int pm_genpd_default_save_state(struct device *dev) + { + int (*cb)(struct device *__dev); + +- cb = dev_gpd_data(dev)->ops.save_state; +- if (cb) +- return cb(dev); +- + if (dev->type && dev->type->pm) + cb = dev->type->pm->runtime_suspend; + else if (dev->class && dev->class->pm) +@@ -1985,17 +1864,13 @@ + } + + /** +- * pm_genpd_default_restore_state - Default PM domians "restore device state". ++ * pm_genpd_default_restore_state - Default PM domains "restore device state". + * @dev: Device to handle. + */ + static int pm_genpd_default_restore_state(struct device *dev) + { + int (*cb)(struct device *__dev); + +- cb = dev_gpd_data(dev)->ops.restore_state; +- if (cb) +- return cb(dev); +- + if (dev->type && dev->type->pm) + cb = dev->type->pm->runtime_resume; + else if (dev->class && dev->class->pm) +@@ -2011,109 +1886,6 @@ + return cb ? cb(dev) : 0; + } + +-#ifdef CONFIG_PM_SLEEP +- +-/** +- * pm_genpd_default_suspend - Default "device suspend" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_suspend(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend; +- +- return cb ? cb(dev) : pm_generic_suspend(dev); +-} +- +-/** +- * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_suspend_late(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; +- +- return cb ? cb(dev) : pm_generic_suspend_late(dev); +-} +- +-/** +- * pm_genpd_default_resume_early - Default "early device resume" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_resume_early(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; +- +- return cb ? cb(dev) : pm_generic_resume_early(dev); +-} +- +-/** +- * pm_genpd_default_resume - Default "device resume" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_resume(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume; +- +- return cb ? cb(dev) : pm_generic_resume(dev); +-} +- +-/** +- * pm_genpd_default_freeze - Default "device freeze" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_freeze(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze; +- +- return cb ? cb(dev) : pm_generic_freeze(dev); +-} +- +-/** +- * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_freeze_late(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; +- +- return cb ? cb(dev) : pm_generic_freeze_late(dev); +-} +- +-/** +- * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_thaw_early(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; +- +- return cb ? cb(dev) : pm_generic_thaw_early(dev); +-} +- +-/** +- * pm_genpd_default_thaw - Default "device thaw" for PM domians. +- * @dev: Device to handle. +- */ +-static int pm_genpd_default_thaw(struct device *dev) +-{ +- int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw; +- +- return cb ? cb(dev) : pm_generic_thaw(dev); +-} +- +-#else /* !CONFIG_PM_SLEEP */ +- +-#define pm_genpd_default_suspend NULL +-#define pm_genpd_default_suspend_late NULL +-#define pm_genpd_default_resume_early NULL +-#define pm_genpd_default_resume NULL +-#define pm_genpd_default_freeze NULL +-#define pm_genpd_default_freeze_late NULL +-#define pm_genpd_default_thaw_early NULL +-#define pm_genpd_default_thaw NULL +- +-#endif /* !CONFIG_PM_SLEEP */ +- + /** + * pm_genpd_init - Initialize a generic I/O PM domain object. + * @genpd: PM domain object to initialize. +@@ -2165,15 +1937,295 @@ + genpd->domain.ops.complete = pm_genpd_complete; + genpd->dev_ops.save_state = pm_genpd_default_save_state; + genpd->dev_ops.restore_state = pm_genpd_default_restore_state; +- genpd->dev_ops.suspend = pm_genpd_default_suspend; +- genpd->dev_ops.suspend_late = pm_genpd_default_suspend_late; +- genpd->dev_ops.resume_early = pm_genpd_default_resume_early; +- genpd->dev_ops.resume = pm_genpd_default_resume; +- genpd->dev_ops.freeze = pm_genpd_default_freeze; +- genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late; +- genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early; +- genpd->dev_ops.thaw = pm_genpd_default_thaw; + mutex_lock(&gpd_list_lock); + list_add(&genpd->gpd_list_node, &gpd_list); + mutex_unlock(&gpd_list_lock); + } ++ ++#ifdef CONFIG_PM_GENERIC_DOMAINS_OF ++/* ++ * Device Tree based PM domain providers. ++ * ++ * The code below implements generic device tree based PM domain providers that ++ * bind device tree nodes with generic PM domains registered in the system. ++ * ++ * Any driver that registers generic PM domains and needs to support binding of ++ * devices to these domains is supposed to register a PM domain provider, which ++ * maps a PM domain specifier retrieved from the device tree to a PM domain. ++ * ++ * Two simple mapping functions have been provided for convenience: ++ * - __of_genpd_xlate_simple() for 1:1 device tree node to PM domain mapping. ++ * - __of_genpd_xlate_onecell() for mapping of multiple PM domains per node by ++ * index. ++ */ ++ ++/** ++ * struct of_genpd_provider - PM domain provider registration structure ++ * @link: Entry in global list of PM domain providers ++ * @node: Pointer to device tree node of PM domain provider ++ * @xlate: Provider-specific xlate callback mapping a set of specifier cells ++ * into a PM domain. ++ * @data: context pointer to be passed into @xlate callback ++ */ ++struct of_genpd_provider { ++ struct list_head link; ++ struct device_node *node; ++ genpd_xlate_t xlate; ++ void *data; ++}; ++ ++/* List of registered PM domain providers. */ ++static LIST_HEAD(of_genpd_providers); ++/* Mutex to protect the list above. */ ++static DEFINE_MUTEX(of_genpd_mutex); ++ ++/** ++ * __of_genpd_xlate_simple() - Xlate function for direct node-domain mapping ++ * @genpdspec: OF phandle args to map into a PM domain ++ * @data: xlate function private data - pointer to struct generic_pm_domain ++ * ++ * This is a generic xlate function that can be used to model PM domains that ++ * have their own device tree nodes. The private data of xlate function needs ++ * to be a valid pointer to struct generic_pm_domain. ++ */ ++struct generic_pm_domain *__of_genpd_xlate_simple( ++ struct of_phandle_args *genpdspec, ++ void *data) ++{ ++ if (genpdspec->args_count != 0) ++ return ERR_PTR(-EINVAL); ++ return data; ++} ++EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple); ++ ++/** ++ * __of_genpd_xlate_onecell() - Xlate function using a single index. ++ * @genpdspec: OF phandle args to map into a PM domain ++ * @data: xlate function private data - pointer to struct genpd_onecell_data ++ * ++ * This is a generic xlate function that can be used to model simple PM domain ++ * controllers that have one device tree node and provide multiple PM domains. ++ * A single cell is used as an index into an array of PM domains specified in ++ * the genpd_onecell_data struct when registering the provider. ++ */ ++struct generic_pm_domain *__of_genpd_xlate_onecell( ++ struct of_phandle_args *genpdspec, ++ void *data) ++{ ++ struct genpd_onecell_data *genpd_data = data; ++ unsigned int idx = genpdspec->args[0]; ++ ++ if (genpdspec->args_count != 1) ++ return ERR_PTR(-EINVAL); ++ ++ if (idx >= genpd_data->num_domains) { ++ pr_err("%s: invalid domain index %u\n", __func__, idx); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (!genpd_data->domains[idx]) ++ return ERR_PTR(-ENOENT); ++ ++ return genpd_data->domains[idx]; ++} ++EXPORT_SYMBOL_GPL(__of_genpd_xlate_onecell); ++ ++/** ++ * __of_genpd_add_provider() - Register a PM domain provider for a node ++ * @np: Device node pointer associated with the PM domain provider. ++ * @xlate: Callback for decoding PM domain from phandle arguments. ++ * @data: Context pointer for @xlate callback. ++ */ ++int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, ++ void *data) ++{ ++ struct of_genpd_provider *cp; ++ ++ cp = kzalloc(sizeof(*cp), GFP_KERNEL); ++ if (!cp) ++ return -ENOMEM; ++ ++ cp->node = of_node_get(np); ++ cp->data = data; ++ cp->xlate = xlate; ++ ++ mutex_lock(&of_genpd_mutex); ++ list_add(&cp->link, &of_genpd_providers); ++ mutex_unlock(&of_genpd_mutex); ++ pr_debug("Added domain provider from %s\n", np->full_name); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(__of_genpd_add_provider); ++ ++/** ++ * of_genpd_del_provider() - Remove a previously registered PM domain provider ++ * @np: Device node pointer associated with the PM domain provider ++ */ ++void of_genpd_del_provider(struct device_node *np) ++{ ++ struct of_genpd_provider *cp; ++ ++ mutex_lock(&of_genpd_mutex); ++ list_for_each_entry(cp, &of_genpd_providers, link) { ++ if (cp->node == np) { ++ list_del(&cp->link); ++ of_node_put(cp->node); ++ kfree(cp); ++ break; ++ } ++ } ++ mutex_unlock(&of_genpd_mutex); ++} ++EXPORT_SYMBOL_GPL(of_genpd_del_provider); ++ ++/** ++ * of_genpd_get_from_provider() - Look-up PM domain ++ * @genpdspec: OF phandle args to use for look-up ++ * ++ * Looks for a PM domain provider under the node specified by @genpdspec and if ++ * found, uses xlate function of the provider to map phandle args to a PM ++ * domain. ++ * ++ * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() ++ * on failure. ++ */ ++static struct generic_pm_domain *of_genpd_get_from_provider( ++ struct of_phandle_args *genpdspec) ++{ ++ struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); ++ struct of_genpd_provider *provider; ++ ++ mutex_lock(&of_genpd_mutex); ++ ++ /* Check if we have such a provider in our array */ ++ list_for_each_entry(provider, &of_genpd_providers, link) { ++ if (provider->node == genpdspec->np) ++ genpd = provider->xlate(genpdspec, provider->data); ++ if (!IS_ERR(genpd)) ++ break; ++ } ++ ++ mutex_unlock(&of_genpd_mutex); ++ ++ return genpd; ++} ++ ++/** ++ * genpd_dev_pm_detach - Detach a device from its PM domain. ++ * @dev: Device to attach. ++ * @power_off: Currently not used ++ * ++ * Try to locate a corresponding generic PM domain, which the device was ++ * attached to previously. If such is found, the device is detached from it. ++ */ ++static void genpd_dev_pm_detach(struct device *dev, bool power_off) ++{ ++ struct generic_pm_domain *pd = NULL, *gpd; ++ int ret = 0; ++ ++ if (!dev->pm_domain) ++ return; ++ ++ mutex_lock(&gpd_list_lock); ++ list_for_each_entry(gpd, &gpd_list, gpd_list_node) { ++ if (&gpd->domain == dev->pm_domain) { ++ pd = gpd; ++ break; ++ } ++ } ++ mutex_unlock(&gpd_list_lock); ++ ++ if (!pd) ++ return; ++ ++ dev_dbg(dev, "removing from PM domain %s\n", pd->name); ++ ++ while (1) { ++ ret = pm_genpd_remove_device(pd, dev); ++ if (ret != -EAGAIN) ++ break; ++ cond_resched(); ++ } ++ ++ if (ret < 0) { ++ dev_err(dev, "failed to remove from PM domain %s: %d", ++ pd->name, ret); ++ return; ++ } ++ ++ /* Check if PM domain can be powered off after removing this device. */ ++ genpd_queue_power_off_work(pd); ++} ++ ++/** ++ * genpd_dev_pm_attach - Attach a device to its PM domain using DT. ++ * @dev: Device to attach. ++ * ++ * Parse device's OF node to find a PM domain specifier. If such is found, ++ * attaches the device to retrieved pm_domain ops. ++ * ++ * Both generic and legacy Samsung-specific DT bindings are supported to keep ++ * backwards compatibility with existing DTBs. ++ * ++ * Returns 0 on successfully attached PM domain or negative error code. ++ */ ++int genpd_dev_pm_attach(struct device *dev) ++{ ++ struct of_phandle_args pd_args; ++ struct generic_pm_domain *pd; ++ int ret; ++ ++ if (!dev->of_node) ++ return -ENODEV; ++ ++ if (dev->pm_domain) ++ return -EEXIST; ++ ++ ret = of_parse_phandle_with_args(dev->of_node, "power-domains", ++ "#power-domain-cells", 0, &pd_args); ++ if (ret < 0) { ++ if (ret != -ENOENT) ++ return ret; ++ ++ /* ++ * Try legacy Samsung-specific bindings ++ * (for backwards compatibility of DT ABI) ++ */ ++ pd_args.args_count = 0; ++ pd_args.np = of_parse_phandle(dev->of_node, ++ "samsung,power-domain", 0); ++ if (!pd_args.np) ++ return -ENOENT; ++ } ++ ++ pd = of_genpd_get_from_provider(&pd_args); ++ if (IS_ERR(pd)) { ++ dev_dbg(dev, "%s() failed to find PM domain: %ld\n", ++ __func__, PTR_ERR(pd)); ++ of_node_put(dev->of_node); ++ return PTR_ERR(pd); ++ } ++ ++ dev_dbg(dev, "adding to PM domain %s\n", pd->name); ++ ++ while (1) { ++ ret = pm_genpd_add_device(pd, dev); ++ if (ret != -EAGAIN) ++ break; ++ cond_resched(); ++ } ++ ++ if (ret < 0) { ++ dev_err(dev, "failed to add to PM domain %s: %d", ++ pd->name, ret); ++ of_node_put(dev->of_node); ++ return ret; ++ } ++ ++ dev->pm_domain->detach = genpd_dev_pm_detach; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); ++#endif +diff -Nur linux-3.14.72.orig/drivers/base/power/domain_governor.c linux-3.14.72/drivers/base/power/domain_governor.c +--- linux-3.14.72.orig/drivers/base/power/domain_governor.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/power/domain_governor.c 2016-06-19 22:11:55.105153131 +0200 +@@ -6,7 +6,6 @@ + * This file is released under the GPLv2. + */ + +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/base/power/opp.c linux-3.14.72/drivers/base/power/opp.c +--- linux-3.14.72.orig/drivers/base/power/opp.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/power/opp.c 2016-06-19 22:11:55.105153131 +0200 +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/base/regmap/Kconfig linux-3.14.72/drivers/base/regmap/Kconfig +--- linux-3.14.72.orig/drivers/base/regmap/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/regmap/Kconfig 2016-06-19 22:11:55.105153131 +0200 +@@ -3,11 +3,14 @@ + # subsystems should select the appropriate symbols. + + config REGMAP +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ) ++ default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ || REGMAP_AC97) + select LZO_COMPRESS + select LZO_DECOMPRESS + select IRQ_DOMAIN if REGMAP_IRQ + bool ++ ++config REGMAP_AC97 ++ tristate + + config REGMAP_I2C + tristate +diff -Nur linux-3.14.72.orig/drivers/base/regmap/Makefile linux-3.14.72/drivers/base/regmap/Makefile +--- linux-3.14.72.orig/drivers/base/regmap/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/regmap/Makefile 2016-06-19 22:11:55.105153131 +0200 +@@ -6,3 +6,4 @@ + obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o + obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o + obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o ++obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o +diff -Nur linux-3.14.72.orig/drivers/base/regmap/regcache.c linux-3.14.72/drivers/base/regmap/regcache.c +--- linux-3.14.72.orig/drivers/base/regmap/regcache.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/regmap/regcache.c 2016-06-19 22:11:55.109152867 +0200 +@@ -636,10 +636,10 @@ + if (*data == NULL) + return 0; + +- count = cur - base; ++ count = (cur - base) / map->reg_stride; + + dev_dbg(map->dev, "Writing %zu bytes for %d registers from 0x%x-0x%x\n", +- count * val_bytes, count, base, cur - 1); ++ count * val_bytes, count, base, cur - map->reg_stride); + + map->cache_bypass = 1; + +diff -Nur linux-3.14.72.orig/drivers/base/regmap/regmap-ac97.c linux-3.14.72/drivers/base/regmap/regmap-ac97.c +--- linux-3.14.72.orig/drivers/base/regmap/regmap-ac97.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/base/regmap/regmap-ac97.c 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,113 @@ ++/* ++ * Register map access API - AC'97 support ++ * ++ * Copyright 2013 Linaro Ltd. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case AC97_RESET: ++ case AC97_POWERDOWN: ++ case AC97_INT_PAGING: ++ case AC97_EXTENDED_ID: ++ case AC97_EXTENDED_STATUS: ++ case AC97_EXTENDED_MID: ++ case AC97_EXTENDED_MSTATUS: ++ case AC97_GPIO_STATUS: ++ case AC97_MISC_AFE: ++ case AC97_VENDOR_ID1: ++ case AC97_VENDOR_ID2: ++ case AC97_CODEC_CLASS_REV: ++ case AC97_PCI_SVID: ++ case AC97_PCI_SID: ++ case AC97_FUNC_SELECT: ++ case AC97_FUNC_INFO: ++ case AC97_SENSE_INFO: ++ return true; ++ default: ++ return false; ++ } ++} ++EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile); ++ ++static int regmap_ac97_reg_read(void *context, unsigned int reg, ++ unsigned int *val) ++{ ++ struct snd_ac97 *ac97 = context; ++ *val = ac97->bus->ops->read(ac97, reg); ++ ++ return 0; ++} ++ ++static int regmap_ac97_reg_write(void *context, unsigned int reg, ++ unsigned int val) ++{ ++ struct snd_ac97 *ac97 = context; ++ ++ ac97->bus->ops->write(ac97, reg, val); ++ ++ return 0; ++} ++ ++static const struct regmap_bus ac97_regmap_bus = { ++ .reg_write = regmap_ac97_reg_write, ++ .reg_read = regmap_ac97_reg_read, ++}; ++ ++/** ++ * regmap_init_ac97(): Initialise AC'97 register map ++ * ++ * @ac97: Device that will be interacted with ++ * @config: Configuration for register map ++ * ++ * The return value will be an ERR_PTR() on error or a valid pointer to ++ * a struct regmap. ++ */ ++struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, ++ const struct regmap_config *config) ++{ ++ return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); ++} ++EXPORT_SYMBOL_GPL(regmap_init_ac97); ++ ++/** ++ * devm_regmap_init_ac97(): Initialise AC'97 register map ++ * ++ * @ac97: Device that will be interacted with ++ * @config: Configuration for register map ++ * ++ * The return value will be an ERR_PTR() on error or a valid pointer ++ * to a struct regmap. The regmap will be automatically freed by the ++ * device management code. ++ */ ++struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, ++ const struct regmap_config *config) ++{ ++ return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); ++} ++EXPORT_SYMBOL_GPL(devm_regmap_init_ac97); ++ ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.14.72.orig/drivers/base/regmap/regmap.c linux-3.14.72/drivers/base/regmap/regmap.c +--- linux-3.14.72.orig/drivers/base/regmap/regmap.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/regmap/regmap.c 2016-06-19 22:11:55.109152867 +0200 +@@ -35,10 +35,14 @@ + unsigned int mask, unsigned int val, + bool *change); + ++static int _regmap_bus_reg_read(void *context, unsigned int reg, ++ unsigned int *val); + static int _regmap_bus_read(void *context, unsigned int reg, + unsigned int *val); + static int _regmap_bus_formatted_write(void *context, unsigned int reg, + unsigned int val); ++static int _regmap_bus_reg_write(void *context, unsigned int reg, ++ unsigned int val); + static int _regmap_bus_raw_write(void *context, unsigned int reg, + unsigned int val); + +@@ -472,6 +476,11 @@ + + map->defer_caching = false; + goto skip_format_initialization; ++ } else if (!bus->read || !bus->write) { ++ map->reg_read = _regmap_bus_reg_read; ++ map->reg_write = _regmap_bus_reg_write; ++ map->defer_caching = false; ++ goto skip_format_initialization; + } else { + map->reg_read = _regmap_bus_read; + } +@@ -1266,6 +1275,14 @@ + return ret; + } + ++static int _regmap_bus_reg_write(void *context, unsigned int reg, ++ unsigned int val) ++{ ++ struct regmap *map = context; ++ ++ return map->bus->reg_write(map->bus_context, reg, val); ++} ++ + static int _regmap_bus_raw_write(void *context, unsigned int reg, + unsigned int val) + { +@@ -1707,6 +1724,14 @@ + return ret; + } + ++static int _regmap_bus_reg_read(void *context, unsigned int reg, ++ unsigned int *val) ++{ ++ struct regmap *map = context; ++ ++ return map->bus->reg_read(map->bus_context, reg, val); ++} ++ + static int _regmap_bus_read(void *context, unsigned int reg, + unsigned int *val) + { +diff -Nur linux-3.14.72.orig/drivers/base/regmap/regmap-i2c.c linux-3.14.72/drivers/base/regmap/regmap-i2c.c +--- linux-3.14.72.orig/drivers/base/regmap/regmap-i2c.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/regmap/regmap-i2c.c 2016-06-19 22:11:55.109152867 +0200 +@@ -13,7 +13,6 @@ + #include + #include + #include +-#include + + static int regmap_i2c_write(void *context, const void *data, size_t count) + { +diff -Nur linux-3.14.72.orig/drivers/base/regmap/regmap-mmio.c linux-3.14.72/drivers/base/regmap/regmap-mmio.c +--- linux-3.14.72.orig/drivers/base/regmap/regmap-mmio.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/regmap/regmap-mmio.c 2016-06-19 22:11:55.109152867 +0200 +@@ -18,7 +18,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -211,19 +210,15 @@ + ctx->val_bytes = config->val_bits / 8; + ctx->clk = ERR_PTR(-ENODEV); + +- if (clk_id == NULL) +- return ctx; +- + ctx->clk = clk_get(dev, clk_id); +- if (IS_ERR(ctx->clk)) { +- ret = PTR_ERR(ctx->clk); +- goto err_free; +- } +- +- ret = clk_prepare(ctx->clk); +- if (ret < 0) { +- clk_put(ctx->clk); +- goto err_free; ++ if (!IS_ERR(ctx->clk)) { ++ ret = clk_prepare(ctx->clk); ++ if (ret < 0) { ++ clk_put(ctx->clk); ++ goto err_free; ++ } ++ } else { ++ ctx->clk = NULL; + } + + return ctx; +diff -Nur linux-3.14.72.orig/drivers/base/regmap/regmap-spi.c linux-3.14.72/drivers/base/regmap/regmap-spi.c +--- linux-3.14.72.orig/drivers/base/regmap/regmap-spi.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/regmap/regmap-spi.c 2016-06-19 22:11:55.109152867 +0200 +@@ -12,7 +12,6 @@ + + #include + #include +-#include + #include + + #include "internal.h" +diff -Nur linux-3.14.72.orig/drivers/base/topology.c linux-3.14.72/drivers/base/topology.c +--- linux-3.14.72.orig/drivers/base/topology.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/base/topology.c 2016-06-19 22:11:55.109152867 +0200 +@@ -23,7 +23,6 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +-#include + #include + #include + #include +diff -Nur linux-3.14.72.orig/drivers/bcma/driver_pcie2.c linux-3.14.72/drivers/bcma/driver_pcie2.c +--- linux-3.14.72.orig/drivers/bcma/driver_pcie2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/bcma/driver_pcie2.c 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,175 @@ ++/* ++ * Broadcom specific AMBA ++ * PCIe Gen 2 Core ++ * ++ * Copyright 2014, Broadcom Corporation ++ * Copyright 2014, RafaÅ‚ MiÅ‚ecki ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include "bcma_private.h" ++#include ++ ++/************************************************** ++ * R/W ops. ++ **************************************************/ ++ ++#if 0 ++static u32 bcma_core_pcie2_cfg_read(struct bcma_drv_pcie2 *pcie2, u32 addr) ++{ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, addr); ++ pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR); ++ return pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA); ++} ++#endif ++ ++static void bcma_core_pcie2_cfg_write(struct bcma_drv_pcie2 *pcie2, u32 addr, ++ u32 val) ++{ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, addr); ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, val); ++} ++ ++/************************************************** ++ * Init. ++ **************************************************/ ++ ++static u32 bcma_core_pcie2_war_delay_perst_enab(struct bcma_drv_pcie2 *pcie2, ++ bool enable) ++{ ++ u32 val; ++ ++ /* restore back to default */ ++ val = pcie2_read32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL); ++ val |= PCIE2_CLKC_DLYPERST; ++ val &= ~PCIE2_CLKC_DISSPROMLD; ++ if (enable) { ++ val &= ~PCIE2_CLKC_DLYPERST; ++ val |= PCIE2_CLKC_DISSPROMLD; ++ } ++ pcie2_write32(pcie2, (BCMA_CORE_PCIE2_CLK_CONTROL), val); ++ /* flush */ ++ return pcie2_read32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL); ++} ++ ++static void bcma_core_pcie2_set_ltr_vals(struct bcma_drv_pcie2 *pcie2) ++{ ++ /* LTR0 */ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x844); ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x883c883c); ++ /* LTR1 */ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x848); ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x88648864); ++ /* LTR2 */ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x84C); ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x90039003); ++} ++ ++static void bcma_core_pcie2_hw_ltr_war(struct bcma_drv_pcie2 *pcie2) ++{ ++ u8 core_rev = pcie2->core->id.rev; ++ u32 devstsctr2; ++ ++ if (core_rev < 2 || core_rev == 10 || core_rev > 13) ++ return; ++ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, ++ PCIE2_CAP_DEVSTSCTRL2_OFFSET); ++ devstsctr2 = pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA); ++ if (devstsctr2 & PCIE2_CAP_DEVSTSCTRL2_LTRENAB) { ++ /* force the right LTR values */ ++ bcma_core_pcie2_set_ltr_vals(pcie2); ++ ++ /* TODO: ++ si_core_wrapperreg(pcie2, 3, 0x60, 0x8080, 0); */ ++ ++ /* enable the LTR */ ++ devstsctr2 |= PCIE2_CAP_DEVSTSCTRL2_LTRENAB; ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, ++ PCIE2_CAP_DEVSTSCTRL2_OFFSET); ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, devstsctr2); ++ ++ /* set the LTR state to be active */ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_LTR_STATE, ++ PCIE2_LTR_ACTIVE); ++ usleep_range(1000, 2000); ++ ++ /* set the LTR state to be sleep */ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_LTR_STATE, ++ PCIE2_LTR_SLEEP); ++ usleep_range(1000, 2000); ++ } ++} ++ ++static void pciedev_crwlpciegen2(struct bcma_drv_pcie2 *pcie2) ++{ ++ u8 core_rev = pcie2->core->id.rev; ++ bool pciewar160, pciewar162; ++ ++ pciewar160 = core_rev == 7 || core_rev == 9 || core_rev == 11; ++ pciewar162 = core_rev == 5 || core_rev == 7 || core_rev == 8 || ++ core_rev == 9 || core_rev == 11; ++ ++ if (!pciewar160 && !pciewar162) ++ return; ++ ++/* TODO */ ++#if 0 ++ pcie2_set32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL, ++ PCIE_DISABLE_L1CLK_GATING); ++#if 0 ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, ++ PCIEGEN2_COE_PVT_TL_CTRL_0); ++ pcie2_mask32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, ++ ~(1 << COE_PVT_TL_CTRL_0_PM_DIS_L1_REENTRY_BIT)); ++#endif ++#endif ++} ++ ++static void pciedev_crwlpciegen2_180(struct bcma_drv_pcie2 *pcie2) ++{ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, PCIE2_PMCR_REFUP); ++ pcie2_set32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x1f); ++} ++ ++static void pciedev_crwlpciegen2_182(struct bcma_drv_pcie2 *pcie2) ++{ ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, PCIE2_SBMBX); ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 1 << 0); ++} ++ ++static void pciedev_reg_pm_clk_period(struct bcma_drv_pcie2 *pcie2) ++{ ++ struct bcma_drv_cc *drv_cc = &pcie2->core->bus->drv_cc; ++ u8 core_rev = pcie2->core->id.rev; ++ u32 alp_khz, pm_value; ++ ++ if (core_rev <= 13) { ++ alp_khz = bcma_pmu_get_alp_clock(drv_cc) / 1000; ++ pm_value = (1000000 * 2) / alp_khz; ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, ++ PCIE2_PVT_REG_PM_CLK_PERIOD); ++ pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, pm_value); ++ } ++} ++ ++void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2) ++{ ++ struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo; ++ u32 tmp; ++ ++ tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54)); ++ if ((tmp & 0xe) >> 1 == 2) ++ bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17); ++ ++ /* TODO: Do we need pcie_reqsize? */ ++ ++ if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3) ++ bcma_core_pcie2_war_delay_perst_enab(pcie2, true); ++ bcma_core_pcie2_hw_ltr_war(pcie2); ++ pciedev_crwlpciegen2(pcie2); ++ pciedev_reg_pm_clk_period(pcie2); ++ pciedev_crwlpciegen2_180(pcie2); ++ pciedev_crwlpciegen2_182(pcie2); ++} +diff -Nur linux-3.14.72.orig/drivers/bcma/main.c linux-3.14.72/drivers/bcma/main.c +--- linux-3.14.72.orig/drivers/bcma/main.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/bcma/main.c 2016-06-19 22:11:55.109152867 +0200 +@@ -132,6 +132,7 @@ + case BCMA_CORE_CHIPCOMMON: + case BCMA_CORE_PCI: + case BCMA_CORE_PCIE: ++ case BCMA_CORE_PCIE2: + case BCMA_CORE_MIPS_74K: + case BCMA_CORE_4706_MAC_GBIT_COMMON: + continue; +@@ -281,6 +282,13 @@ + bcma_core_pci_init(&bus->drv_pci[1]); + } + ++ /* Init PCIe Gen 2 core */ ++ core = bcma_find_core_unit(bus, BCMA_CORE_PCIE2, 0); ++ if (core) { ++ bus->drv_pcie2.core = core; ++ bcma_core_pcie2_init(&bus->drv_pcie2); ++ } ++ + /* Init GBIT MAC COMMON core */ + core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); + if (core) { +diff -Nur linux-3.14.72.orig/drivers/bcma/Makefile linux-3.14.72/drivers/bcma/Makefile +--- linux-3.14.72.orig/drivers/bcma/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/bcma/Makefile 2016-06-19 22:11:55.109152867 +0200 +@@ -3,6 +3,7 @@ + bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o + bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o + bcma-y += driver_pci.o ++bcma-y += driver_pcie2.o + bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o + bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o + bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o +diff -Nur linux-3.14.72.orig/drivers/char/fsl_otp.c linux-3.14.72/drivers/char/fsl_otp.c +--- linux-3.14.72.orig/drivers/char/fsl_otp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/char/fsl_otp.c 2016-06-19 22:11:55.109152867 +0200 +@@ -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.72.orig/drivers/char/hw_random/imx-rng.c linux-3.14.72/drivers/char/hw_random/imx-rng.c +--- linux-3.14.72.orig/drivers/char/hw_random/imx-rng.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/char/hw_random/imx-rng.c 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,440 @@ ++/* ++ * RNG driver for Freescale RNG B/C ++ * ++ * Copyright (C) 2008-2015 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 ++ */ ++ ++/* ++ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) ++ * (c) Copyright 2003 Red Hat Inc ++ * ++ * derived from ++ * ++ * Hardware driver for the AMD 768 Random Number Generator (RNG) ++ * (c) Copyright 2001 Red Hat Inc ++ * ++ * derived from ++ * ++ * Hardware driver for Intel i810 Random Number Generator (RNG) ++ * Copyright 2000,2001 Jeff Garzik ++ * Copyright 2000,2001 Philipp Rumpf ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "imx-rng" ++ ++#define RNGC_VERSION_MAJOR3 3 ++ ++#define RNGC_VERSION_ID 0x0000 ++#define RNGC_COMMAND 0x0004 ++#define RNGC_CONTROL 0x0008 ++#define RNGC_STATUS 0x000C ++#define RNGC_ERROR 0x0010 ++#define RNGC_FIFO 0x0014 ++#define RNGC_VERIF_CTRL 0x0020 ++#define RNGC_OSC_CTRL_COUNT 0x0028 ++#define RNGC_OSC_COUNT 0x002C ++#define RNGC_OSC_COUNT_STATUS 0x0030 ++ ++#define RNGC_VERID_ZEROS_MASK 0x0f000000 ++#define RNGC_VERID_RNG_TYPE_MASK 0xf0000000 ++#define RNGC_VERID_RNG_TYPE_SHIFT 28 ++#define RNGC_VERID_CHIP_VERSION_MASK 0x00ff0000 ++#define RNGC_VERID_CHIP_VERSION_SHIFT 16 ++#define RNGC_VERID_VERSION_MAJOR_MASK 0x0000ff00 ++#define RNGC_VERID_VERSION_MAJOR_SHIFT 8 ++#define RNGC_VERID_VERSION_MINOR_MASK 0x000000ff ++#define RNGC_VERID_VERSION_MINOR_SHIFT 0 ++ ++#define RNGC_CMD_ZEROS_MASK 0xffffff8c ++#define RNGC_CMD_SW_RST 0x00000040 ++#define RNGC_CMD_CLR_ERR 0x00000020 ++#define RNGC_CMD_CLR_INT 0x00000010 ++#define RNGC_CMD_SEED 0x00000002 ++#define RNGC_CMD_SELF_TEST 0x00000001 ++ ++#define RNGC_CTRL_ZEROS_MASK 0xfffffc8c ++#define RNGC_CTRL_CTL_ACC 0x00000200 ++#define RNGC_CTRL_VERIF_MODE 0x00000100 ++#define RNGC_CTRL_MASK_ERROR 0x00000040 ++ ++#define RNGC_CTRL_MASK_DONE 0x00000020 ++#define RNGC_CTRL_AUTO_SEED 0x00000010 ++#define RNGC_CTRL_FIFO_UFLOW_MASK 0x00000003 ++#define RNGC_CTRL_FIFO_UFLOW_SHIFT 0 ++ ++#define RNGC_CTRL_FIFO_UFLOW_ZEROS_ERROR 0 ++#define RNGC_CTRL_FIFO_UFLOW_ZEROS_ERROR2 1 ++#define RNGC_CTRL_FIFO_UFLOW_BUS_XFR 2 ++#define RNGC_CTRL_FIFO_UFLOW_ZEROS_INTR 3 ++ ++#define RNGC_STATUS_ST_PF_MASK 0x00c00000 ++#define RNGC_STATUS_ST_PF_SHIFT 22 ++#define RNGC_STATUS_ST_PF_TRNG 0x00800000 ++#define RNGC_STATUS_ST_PF_PRNG 0x00400000 ++#define RNGC_STATUS_ERROR 0x00010000 ++#define RNGC_STATUS_FIFO_SIZE_MASK 0x0000f000 ++#define RNGC_STATUS_FIFO_SIZE_SHIFT 12 ++#define RNGC_STATUS_FIFO_LEVEL_MASK 0x00000f00 ++#define RNGC_STATUS_FIFO_LEVEL_SHIFT 8 ++#define RNGC_STATUS_NEXT_SEED_DONE 0x00000040 ++#define RNGC_STATUS_SEED_DONE 0x00000020 ++#define RNGC_STATUS_ST_DONE 0x00000010 ++#define RNGC_STATUS_RESEED 0x00000008 ++#define RNGC_STATUS_SLEEP 0x00000004 ++#define RNGC_STATUS_BUSY 0x00000002 ++#define RNGC_STATUS_SEC_STATE 0x00000001 ++ ++#define RNGC_ERROR_STATUS_ZEROS_MASK 0xffffffc0 ++#define RNGC_ERROR_STATUS_BAD_KEY 0x00000040 ++#define RNGC_ERROR_STATUS_RAND_ERR 0x00000020 ++#define RNGC_ERROR_STATUS_FIFO_ERR 0x00000010 ++#define RNGC_ERROR_STATUS_STAT_ERR 0x00000008 ++#define RNGC_ERROR_STATUS_ST_ERR 0x00000004 ++#define RNGC_ERROR_STATUS_OSC_ERR 0x00000002 ++#define RNGC_ERROR_STATUS_LFSR_ERR 0x00000001 ++ ++#define RNG_ADDR_RANGE 0x34 ++ ++static DECLARE_COMPLETION(rng_self_testing); ++static DECLARE_COMPLETION(rng_seed_done); ++ ++static struct platform_device *imx_rng_dev; ++ ++struct imx_rng_priv_data { ++ void __iomem *reg_base; ++}; ++ ++int irq_rng; ++ ++static int imx_rng_data_present(struct hwrng *rng, int wait) ++{ ++ int level; ++ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv; ++ ++ /* how many random numbers are in FIFO? [0-16] */ ++ level = (readl(prv->reg_base + RNGC_STATUS) & ++ RNGC_STATUS_FIFO_LEVEL_MASK) >> RNGC_STATUS_FIFO_LEVEL_SHIFT; ++ ++ return level > 0 ? 1 : 0; ++} ++ ++static int imx_rng_data_read(struct hwrng *rng, u32 * data) ++{ ++ int err; ++ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv; ++ ++ /* retrieve a random number from FIFO */ ++ *data = readl(prv->reg_base + RNGC_FIFO); ++ ++ /* is there some error while reading this random number? */ ++ err = readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR; ++ ++ /* if error happened doesn't return random number */ ++ return err ? 0 : 4; ++} ++ ++static irqreturn_t imx_rng_irq(int irq, void *dev) ++{ ++ int handled = 0; ++ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)dev; ++ ++ /* is the seed creation done? */ ++ if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_SEED_DONE) { ++ complete(&rng_seed_done); ++ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, ++ prv->reg_base + RNGC_COMMAND); ++ handled = 1; ++ } ++ ++ /* is the self test done? */ ++ if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ST_DONE) { ++ complete(&rng_self_testing); ++ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, ++ prv->reg_base + RNGC_COMMAND); ++ handled = 1; ++ } ++ ++ /* is there any error? */ ++ if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR) { ++ /* clear interrupt */ ++ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, ++ prv->reg_base + RNGC_COMMAND); ++ handled = 1; ++ } ++ ++ return handled; ++} ++ ++static int imx_rng_init(struct hwrng *rng) ++{ ++ int err; ++ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv; ++ u32 cmd, ctrl, osc; ++ ++ reinit_completion(&rng_self_testing); ++ reinit_completion(&rng_seed_done); ++ ++ err = readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR; ++ if (err) { ++ /* is this a bad keys error ? */ ++ if (readl(prv->reg_base + RNGC_ERROR) & ++ RNGC_ERROR_STATUS_BAD_KEY) { ++ dev_err(&imx_rng_dev->dev, "Can't start, Bad Keys.\n"); ++ return -EIO; ++ } ++ } ++ ++ /* mask all interrupts, will be unmasked soon */ ++ ctrl = readl(prv->reg_base + RNGC_CONTROL); ++ writel(ctrl | RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR, ++ prv->reg_base + RNGC_CONTROL); ++ ++ /* verify if oscillator is working */ ++ osc = readl(prv->reg_base + RNGC_ERROR); ++ if (osc & RNGC_ERROR_STATUS_OSC_ERR) { ++ dev_err(&imx_rng_dev->dev, "RNGC Oscillator is dead!\n"); ++ return -EIO; ++ } ++ ++ err = request_irq(irq_rng, imx_rng_irq, ++ 0, "imx-rng", (void *)rng->priv); ++ if (err) { ++ dev_err(&imx_rng_dev->dev, "Can't get interrupt working.\n"); ++ return -EIO; ++ } ++ ++ /* do self test, repeat until get success */ ++ do { ++ /* clear error */ ++ cmd = readl(prv->reg_base + RNGC_COMMAND); ++ writel(cmd | RNGC_CMD_CLR_ERR, prv->reg_base + RNGC_COMMAND); ++ ++ /* unmask all interrupt */ ++ ctrl = readl(prv->reg_base + RNGC_CONTROL); ++ writel(ctrl & ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR), ++ prv->reg_base + RNGC_CONTROL); ++ ++ /* run self test */ ++ cmd = readl(prv->reg_base + RNGC_COMMAND); ++ writel(cmd | RNGC_CMD_SELF_TEST, ++ prv->reg_base + RNGC_COMMAND); ++ ++ wait_for_completion(&rng_self_testing); ++ ++ } while (readl(prv->reg_base + RNGC_ERROR) & ++ RNGC_ERROR_STATUS_ST_ERR); ++ ++ /* clear interrupt. Is it really necessary here? */ ++ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, ++ prv->reg_base + RNGC_COMMAND); ++ ++ /* create seed, repeat while there is some statistical error */ ++ do { ++ /* clear error */ ++ cmd = readl(prv->reg_base + RNGC_COMMAND); ++ writel(cmd | RNGC_CMD_CLR_ERR, prv->reg_base + RNGC_COMMAND); ++ ++ /* seed creation */ ++ cmd = readl(prv->reg_base + RNGC_COMMAND); ++ writel(cmd | RNGC_CMD_SEED, prv->reg_base + RNGC_COMMAND); ++ ++ wait_for_completion(&rng_seed_done); ++ ++ } while (readl(prv->reg_base + RNGC_ERROR) & ++ RNGC_ERROR_STATUS_STAT_ERR); ++ ++ err = readl(prv->reg_base + RNGC_ERROR) & ++ (RNGC_ERROR_STATUS_STAT_ERR | ++ RNGC_ERROR_STATUS_RAND_ERR | ++ RNGC_ERROR_STATUS_FIFO_ERR | ++ RNGC_ERROR_STATUS_ST_ERR | ++ RNGC_ERROR_STATUS_OSC_ERR | ++ RNGC_ERROR_STATUS_LFSR_ERR); ++ ++ if (err) { ++ dev_err(&imx_rng_dev->dev, "iMX RNG appears inoperable.\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static struct hwrng imx_rng = { ++ .name = "imx-rng", ++ .init = imx_rng_init, ++ .data_present = imx_rng_data_present, ++ .data_read = imx_rng_data_read ++}; ++ ++static int __init imx_rng_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct clk *clk; ++ struct imx_rng_priv_data *priv; ++ int err = -ENODEV; ++ ++ if (imx_rng_dev) ++ return -EBUSY; ++ ++ /* Enable the clock */ ++ clk = of_clk_get(np, 0); ++ if (IS_ERR(clk)) { ++ dev_err(dev, "Can not get clock.\n"); ++ return PTR_ERR(clk); ++ } ++ clk_enable(clk); ++ ++ /* Allocate private data memory */ ++ priv = kzalloc(sizeof(struct imx_rng_priv_data), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ imx_rng.priv = (unsigned long)priv; ++ dev_set_drvdata(dev, priv); ++ ++ /* ioremap that register space */ ++ priv->reg_base = of_iomap(np, 0); ++ if (!priv->reg_base) { ++ kfree(priv); ++ dev_err(dev, "Failed to remap register space.\n"); ++ return -ENODEV; ++ } ++ ++ irq_rng = platform_get_irq(pdev, 0); ++ ++ err = hwrng_register(&imx_rng); ++ if (err) { ++ iounmap(priv->reg_base); ++ kfree(priv); ++ dev_err(dev, "failed to register hwrng (%d)\n", err); ++ return err; ++ } ++ ++ imx_rng_dev = pdev; ++ dev_info(dev, "iMX RNG Registered.\n"); ++ ++ return 0; ++} ++ ++static int __exit imx_rng_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct clk *clk; ++ struct imx_rng_priv_data *priv = dev_get_drvdata(dev); ++ ++ /* Disable the clock */ ++ clk = of_clk_get(np, 0); ++ ++ if (IS_ERR(clk)) ++ dev_err(dev, "Can not get clock.\n"); ++ else ++ clk_disable(clk); ++ ++ hwrng_unregister(&imx_rng); ++ ++ iounmap(priv->reg_base); ++ ++ kfree(priv); ++ ++ return 0; ++} ++ ++static int imx_rng_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++#ifdef CONFIG_PM ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct clk *clk = of_clk_get(np, 0); ++ ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "Can not get rng_clk\n"); ++ return PTR_ERR(clk); ++ } ++ ++ clk_disable(clk); ++#endif ++ ++ return 0; ++} ++ ++static int imx_rng_resume(struct platform_device *pdev) ++{ ++#ifdef CONFIG_PM ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct clk *clk = of_clk_get(np, 0); ++ ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "Can not get rng_clk\n"); ++ return PTR_ERR(clk); ++ } ++ ++ clk_enable(clk); ++#endif ++ ++ return 0; ++} ++ ++static struct of_device_id imx_rng_dt_ids[] = { ++ { .compatible = "imx-rng",}, ++ { .compatible = "fsl,imx-rng",}, ++ { .compatible = "fsl,imx6sl-rng",}, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, imx_rng_dt_ids); ++ ++static struct platform_driver imx_rng_driver = { ++ .driver = { ++ .name = MODULE_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = imx_rng_dt_ids, ++ }, ++ .remove = __exit_p(imx_rng_remove), ++ .suspend = imx_rng_suspend, ++ .resume = imx_rng_resume, ++}; ++ ++static int __init mod_init(void) ++{ ++ return platform_driver_probe(&imx_rng_driver, imx_rng_probe); ++} ++ ++static void __exit mod_exit(void) ++{ ++ platform_driver_unregister(&imx_rng_driver); ++} ++ ++module_init(mod_init); ++module_exit(mod_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("H/W RNG(B/C) driver for i.MX"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/char/hw_random/Kconfig linux-3.14.72/drivers/char/hw_random/Kconfig +--- linux-3.14.72.orig/drivers/char/hw_random/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/char/hw_random/Kconfig 2016-06-19 22:11:55.109152867 +0200 +@@ -239,6 +239,18 @@ + + If unsure, say Y. + ++config HW_RANDOM_IMX_RNG ++ tristate "Freescale RNG B/C Random Number Generator" ++ depends on HW_RANDOM && ARCH_MXC && HAVE_IMX_RNG ++ ---help--- ++ This driver provides kernel-side support for the Random Number ++ Generator (RNGBB and RNGC) hardware found on Freescale i.MX processors. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called fsl-rngc. ++ ++ If unsure, say Y. ++ + config HW_RANDOM_NOMADIK + tristate "ST-Ericsson Nomadik Random Number Generator support" + depends on HW_RANDOM && ARCH_NOMADIK +diff -Nur linux-3.14.72.orig/drivers/char/hw_random/Makefile linux-3.14.72/drivers/char/hw_random/Makefile +--- linux-3.14.72.orig/drivers/char/hw_random/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/char/hw_random/Makefile 2016-06-19 22:11:55.109152867 +0200 +@@ -20,6 +20,7 @@ + obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o + obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o + obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o ++obj-$(CONFIG_HW_RANDOM_IMX_RNG) += imx-rng.o + obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o + obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o + obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o +diff -Nur linux-3.14.72.orig/drivers/char/imx_amp/imx_mcc_test.c linux-3.14.72/drivers/char/imx_amp/imx_mcc_test.c +--- linux-3.14.72.orig/drivers/char/imx_amp/imx_mcc_test.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/char/imx_amp/imx_mcc_test.c 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,314 @@ ++/* ++ * Copyright (C) 2014-2015 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 ++ ++enum { ++ MCC_NODE_A9 = 0, ++ MCC_NODE_M4 = 0, ++ ++ MCC_A9_PORT = 1, ++ MCC_M4_PORT = 2, ++}; ++ ++/* mcc pingpong test */ ++MCC_ENDPOINT mcc_endpoint_a9_pingpong = {0, MCC_NODE_A9, MCC_A9_PORT}; ++MCC_ENDPOINT mcc_endpoint_m4_pingpong = {1, MCC_NODE_M4, MCC_M4_PORT}; ++/* mcc can test */ ++MCC_ENDPOINT mcc_endpoint_a9_can = {0, MCC_NODE_A9, MCC_A9_PORT}; ++MCC_ENDPOINT mcc_endpoint_m4_can = {1, MCC_NODE_A9, MCC_A9_PORT}; ++ ++struct mcc_pp_msg { ++ unsigned int data; ++}; ++ ++/* Set the max len of the can msg to be 1000 bytes */ ++struct mcc_can_msg { ++ char data[MCC_ATTR_BUFFER_SIZE_IN_BYTES - 24]; ++}; ++ ++static ssize_t imx_mcc_can_test_en(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ u32 can_test_en; ++ int i = 0, ret = 0; ++ struct mcc_can_msg msg; ++ MCC_MEM_SIZE num_of_received_bytes; ++ MCC_INFO_STRUCT mcc_info; ++ ++ sscanf(buf, "%d\n", &can_test_en); ++ ++ if (can_test_en) { ++ pr_info("imx mcc can communication test begin.\n"); ++ ret = mcc_get_info(MCC_NODE_A9, &mcc_info); ++ if (ret) { ++ pr_err("failed to get mcc info.\n"); ++ return -EINVAL; ++ } ++ ++ ret = mcc_create_endpoint(&mcc_endpoint_a9_can, MCC_A9_PORT); ++ if (ret) { ++ pr_err("failed to create a9 mcc ep.\n"); ++ return -EINVAL; ++ } ++ ++ pr_info("\nA9 mcc prepares run, MCC version is %s\n", ++ mcc_info.version_string); ++ ++ while (i < 0x10000) { ++ i++; ++ /* ++ * wait for the "sleep" msg from the remote ep. ++ */ ++ ret = mcc_recv(&mcc_endpoint_m4_can, ++ &mcc_endpoint_a9_can, &msg, ++ sizeof(struct mcc_can_msg), ++ &num_of_received_bytes, 0xffffffff); ++ if (ret < 0) { ++ pr_err("A9 Main task recv error: %d\n", ret); ++ break; ++ } ++ pr_info("%s", msg.data); ++ } ++ ++ ret = mcc_destroy_endpoint(&mcc_endpoint_a9_can); ++ if (ret) { ++ pr_err("failed to destory a9 mcc ep.\n"); ++ return -EINVAL; ++ } else { ++ pr_info("destory a9 mcc ep.\n"); ++ } ++ } ++ ++ pr_info("imx mcc test end after %08d times recv tests.\n", i); ++ return count; ++} ++ ++static ssize_t imx_mcc_pingpong_en(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ u32 pingpong_en; ++ int i = 0, ret = 0; ++ struct timeval tv1, tv2, tv3; ++ u32 tv_count1 = 0, tv_count2 = 0; ++ struct mcc_pp_msg msg; ++ MCC_MEM_SIZE num_of_received_bytes; ++ MCC_INFO_STRUCT mcc_info; ++ ++ sscanf(buf, "%d\n", &pingpong_en); ++ if (pingpong_en) { ++ pr_info("imx mcc pingpong test begin.\n"); ++ ret = mcc_get_info(MCC_NODE_A9, &mcc_info); ++ if (ret) { ++ pr_err("failed to get mcc info.\n"); ++ return -EINVAL; ++ } ++ ++ ret = mcc_create_endpoint(&mcc_endpoint_a9_pingpong, ++ MCC_A9_PORT); ++ if (ret) { ++ pr_err("failed to create a9 mcc ep.\n"); ++ return -EINVAL; ++ } ++ ++ pr_info("\nA9 mcc prepares run, MCC version is %s\n", ++ mcc_info.version_string); ++ msg.data = 1; ++ while (i < 0x50000) { ++ i++; ++ i++; ++ /* ++ * wait until the remote endpoint is created by ++ * the other core ++ */ ++ if (pingpong_en > 1) ++ do_gettimeofday(&tv1); ++ ++ ret = mcc_send(&mcc_endpoint_a9_pingpong, ++ &mcc_endpoint_m4_pingpong, &msg, ++ sizeof(struct mcc_pp_msg), ++ 0xffffffff); ++ if (ret < 0) { ++ pr_err("A9 Main task send error: %d\n", ret); ++ break; ++ } ++ ++ if (pingpong_en > 1) { ++ do_gettimeofday(&tv2); ++ tv_count1 = (tv2.tv_sec - tv1.tv_sec) ++ * USEC_PER_SEC ++ + tv2.tv_usec - tv1.tv_usec; ++ } ++ while (MCC_ERR_ENDPOINT == ret) { ++ pr_err("\n send err ret %d, re-send\n", ret); ++ ret = mcc_send(&mcc_endpoint_a9_pingpong, ++ &mcc_endpoint_m4_pingpong, &msg, ++ sizeof(struct mcc_pp_msg), ++ 0xffffffff); ++ msleep(5000); ++ } ++ ++ if (pingpong_en > 1) ++ do_gettimeofday(&tv2); ++ ++ ret = mcc_recv(&mcc_endpoint_m4_pingpong, ++ &mcc_endpoint_a9_pingpong, &msg, ++ sizeof(struct mcc_pp_msg), ++ &num_of_received_bytes, 0xffffffff); ++ ++ if (pingpong_en > 1) { ++ do_gettimeofday(&tv3); ++ tv_count2 = (tv3.tv_sec - tv2.tv_sec) ++ * USEC_PER_SEC ++ + tv3.tv_usec - tv2.tv_usec; ++ pr_info("imx mcc: Data transfer speed tests" ++ "in pingpong. a9 -> m4:%08dus." ++ "a9 <- m4:%08dus.\n", ++ tv_count1, tv_count2); ++ } ++ ++ if (MCC_SUCCESS != ret) { ++ pr_err("A9 Main task receive error: %d\n", ret); ++ break; ++ } else { ++ pr_info("%08x Main task received a msg" ++ " from [%d, %d, %d] endpoint\n", i, ++ mcc_endpoint_m4_pingpong.core, ++ mcc_endpoint_m4_pingpong.node, ++ mcc_endpoint_m4_pingpong.port); ++ pr_info("Message: Size=0x%08x, data = 0x%08x\n", ++ num_of_received_bytes, msg.data); ++ msg.data++; ++ } ++ } ++ ret = mcc_destroy_endpoint(&mcc_endpoint_a9_pingpong); ++ if (ret) { ++ pr_err("failed to destory a9 mcc ep.\n"); ++ return ret; ++ } else { ++ pr_info("destory a9 mcc ep.\n"); ++ } ++ pr_info("imx mcc test end after %08d times tests.\n", i/2); ++ } ++ ++ if (ret) ++ return ret; ++ else ++ return count; ++} ++ ++static DEVICE_ATTR(pingpong_en, S_IWUGO, NULL, imx_mcc_pingpong_en); ++static DEVICE_ATTR(can_test_en, S_IWUGO, NULL, imx_mcc_can_test_en); ++ ++static struct attribute *imx_mcc_attrs[] = { ++ &dev_attr_pingpong_en.attr, ++ &dev_attr_can_test_en.attr, ++ NULL ++}; ++ ++static struct attribute_group imx_mcc_attrgroup = { ++ .attrs = imx_mcc_attrs, ++}; ++ ++static int imx_mcc_test_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ MCC_INFO_STRUCT mcc_info; ++ ++ ret = mcc_initialize(MCC_NODE_A9); ++ if (ret) { ++ pr_err("failed to initialize mcc.\n"); ++ ret = -EINVAL; ++ return ret; ++ } ++ ++ ret = mcc_get_info(MCC_NODE_A9, &mcc_info); ++ if (ret) { ++ pr_err("failed to get mcc info.\n"); ++ ret = -EINVAL; ++ goto out_node; ++ } ++ pr_info("\nA9 mcc prepares run, MCC version is %s\n", ++ mcc_info.version_string); ++ ++ if (strcmp(mcc_info.version_string, MCC_VERSION_STRING) != 0) { ++ pr_err("\nError, different versions of the MCC library"); ++ pr_err("is used on each core!\n"); ++ pr_err("\nApplication is stopped now.\n"); ++ ret = -EINVAL; ++ goto out_node; ++ } ++ ++ /* add attributes for device. */ ++ ret = sysfs_create_group(&pdev->dev.kobj, &imx_mcc_attrgroup); ++ if (ret) ++ goto out_node; ++ ++ return ret; ++ ++out_node: ++ mcc_destroy(MCC_NODE_A9); ++ ++ return ret; ++} ++ ++static int imx_mcc_test_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id imx_mcc_test_dt_ids[] = { ++ { .compatible = "fsl,imx6sx-mcc-test", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx_mcc_test_dt_ids); ++ ++static struct platform_driver imx_mcc_test_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "imx6sx-mcc-test", ++ .of_match_table = imx_mcc_test_dt_ids, ++ }, ++ .probe = imx_mcc_test_probe, ++ .remove = imx_mcc_test_remove, ++}; ++ ++static int __init imx_mcc_test_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&imx_mcc_test_driver); ++ if (ret) ++ pr_err("failed to register imx mcc test driver.\n"); ++ else ++ pr_info("imx mcc test is registered.\n"); ++ return ret; ++} ++late_initcall(imx_mcc_test_init); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IMX MCC test driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/char/imx_amp/imx_mcc_tty.c linux-3.14.72/drivers/char/imx_amp/imx_mcc_tty.c +--- linux-3.14.72.orig/drivers/char/imx_amp/imx_mcc_tty.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/char/imx_amp/imx_mcc_tty.c 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,282 @@ ++/* ++ * imx_mcc_tty.c - tty demo driver used to test imx mcc ++ * posix tty interface. ++ * ++ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * struct mcctty_port - Wrapper struct for imx mcc tty port. ++ * @port: TTY port data ++ */ ++struct mcctty_port { ++ struct delayed_work read; ++ struct tty_port port; ++ spinlock_t rx_lock; ++}; ++ ++static struct mcctty_port mcc_tty_port; ++ ++enum { ++ MCC_NODE_A9 = 0, ++ MCC_NODE_M4 = 0, ++ ++ MCC_A9_PORT = 1, ++ MCC_M4_PORT = 2, ++}; ++ ++/* mcc tty/pingpong demo */ ++static MCC_ENDPOINT mcc_endpoint_a9_pingpong = {0, MCC_NODE_A9, MCC_A9_PORT}; ++static MCC_ENDPOINT mcc_endpoint_m4_pingpong = {1, MCC_NODE_M4, MCC_M4_PORT}; ++struct mcc_tty_msg { ++ char data[MCC_ATTR_BUFFER_SIZE_IN_BYTES - 24]; ++}; ++ ++static struct tty_port_operations mcctty_port_ops = { }; ++ ++static int mcctty_install(struct tty_driver *driver, struct tty_struct *tty) ++{ ++ return tty_port_install(&mcc_tty_port.port, driver, tty); ++} ++ ++static int mcctty_open(struct tty_struct *tty, struct file *filp) ++{ ++ return tty_port_open(tty->port, tty, filp); ++} ++ ++static void mcctty_close(struct tty_struct *tty, struct file *filp) ++{ ++ return tty_port_close(tty->port, tty, filp); ++} ++ ++static int mcctty_write(struct tty_struct *tty, const unsigned char *buf, ++ int total) ++{ ++ int i, count, ret = 0, space; ++ unsigned char *cbuf, *tmp; ++ MCC_MEM_SIZE num_of_received_bytes; ++ struct mcc_tty_msg tty_msg; ++ struct mcctty_port *cport = &mcc_tty_port; ++ ++ if (NULL == buf) { ++ pr_err("buf shouldn't be null.\n"); ++ return -ENOMEM; ++ } ++ ++ count = total; ++ tmp = (unsigned char *)buf; ++ for (i = 0; i <= count / 999; i++) { ++ strlcpy(tty_msg.data, tmp, count >= 1000 ? 1000 : count + 1); ++ if (count >= 1000) ++ count -= 999; ++ ++ /* ++ * wait until the remote endpoint is created by ++ * the other core ++ */ ++ ret = mcc_send(&mcc_endpoint_a9_pingpong, ++ &mcc_endpoint_m4_pingpong, &tty_msg, ++ sizeof(struct mcc_tty_msg), ++ 0xffffffff); ++ ++ while (MCC_ERR_ENDPOINT == ret) { ++ pr_err("\n send err ret %d, re-send\n", ret); ++ ret = mcc_send(&mcc_endpoint_a9_pingpong, ++ &mcc_endpoint_m4_pingpong, &tty_msg, ++ sizeof(struct mcc_tty_msg), ++ 0xffffffff); ++ msleep(5000); ++ } ++ ++ ret = mcc_recv(&mcc_endpoint_m4_pingpong, ++ &mcc_endpoint_a9_pingpong, &tty_msg, ++ sizeof(struct mcc_tty_msg), ++ &num_of_received_bytes, 0xffffffff); ++ ++ if (MCC_SUCCESS != ret) { ++ pr_err("A9 Main task receive error: %d\n", ret); ++ } else { ++ /* flush the recv-ed data to tty node */ ++ spin_lock_bh(&cport->rx_lock); ++ space = tty_prepare_flip_string(&cport->port, &cbuf, ++ strlen(tty_msg.data)); ++ if (space <= 0) ++ return -ENOMEM; ++ ++ memcpy(cbuf, &tty_msg.data, strlen(tty_msg.data)); ++ tty_flip_buffer_push(&cport->port); ++ spin_unlock_bh(&cport->rx_lock); ++ } ++ } ++ return total; ++} ++ ++static int mcctty_write_room(struct tty_struct *tty) ++{ ++ /* report the space in the mcc buffer */ ++ return MCC_ATTR_BUFFER_SIZE_IN_BYTES; ++} ++ ++static const struct tty_operations imxmcctty_ops = { ++ .install = mcctty_install, ++ .open = mcctty_open, ++ .close = mcctty_close, ++ .write = mcctty_write, ++ .write_room = mcctty_write_room, ++}; ++ ++static struct tty_driver *mcctty_driver; ++ ++static int imx_mcc_tty_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct mcctty_port *cport = &mcc_tty_port; ++ MCC_INFO_STRUCT mcc_info; ++ ++ mcctty_driver = tty_alloc_driver(1, ++ TTY_DRIVER_RESET_TERMIOS | ++ TTY_DRIVER_UNNUMBERED_NODE); ++ if (IS_ERR(mcctty_driver)) ++ return PTR_ERR(mcctty_driver); ++ ++ mcctty_driver->driver_name = "mcc_tty"; ++ mcctty_driver->name = "ttyMCC"; ++ mcctty_driver->major = TTYAUX_MAJOR; ++ mcctty_driver->minor_start = 3; ++ mcctty_driver->type = TTY_DRIVER_TYPE_CONSOLE; ++ mcctty_driver->init_termios = tty_std_termios; ++ mcctty_driver->init_termios.c_cflag |= CLOCAL; ++ ++ tty_set_operations(mcctty_driver, &imxmcctty_ops); ++ ++ tty_port_init(&cport->port); ++ cport->port.ops = &mcctty_port_ops; ++ spin_lock_init(&cport->rx_lock); ++ cport->port.low_latency = cport->port.flags | ASYNC_LOW_LATENCY; ++ ++ ret = tty_register_driver(mcctty_driver); ++ if (ret < 0) { ++ pr_err("Couldn't install mcc tty driver: err %d\n", ret); ++ goto error; ++ } else ++ pr_info("Install mcc tty driver!\n"); ++ ++ ret = mcc_initialize(MCC_NODE_A9); ++ if (ret) { ++ pr_err("failed to initialize mcc.\n"); ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ ret = mcc_get_info(MCC_NODE_A9, &mcc_info); ++ if (ret) { ++ pr_err("failed to get mcc info.\n"); ++ ret = -ENODEV; ++ goto error; ++ } else { ++ pr_info("\nA9 mcc prepares run, MCC version is %s\n", ++ mcc_info.version_string); ++ pr_info("imx mcc tty/pingpong test begin.\n"); ++ } ++ ++ ret = mcc_create_endpoint(&mcc_endpoint_a9_pingpong, ++ MCC_A9_PORT); ++ if (ret) { ++ pr_err("failed to create a9 mcc ep.\n"); ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ tty_unregister_driver(mcctty_driver); ++ put_tty_driver(mcctty_driver); ++ tty_port_destroy(&cport->port); ++ mcctty_driver = NULL; ++ ++ return ret; ++} ++ ++static int imx_mcc_tty_remove(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct mcctty_port *cport = &mcc_tty_port; ++ ++ /* destory the mcc tty endpoint here */ ++ ret = mcc_destroy_endpoint(&mcc_endpoint_a9_pingpong); ++ if (ret) ++ pr_err("failed to destory a9 mcc ep.\n"); ++ else ++ pr_info("destory a9 mcc ep.\n"); ++ ++ tty_unregister_driver(mcctty_driver); ++ tty_port_destroy(&cport->port); ++ put_tty_driver(mcctty_driver); ++ ++ return ret; ++} ++ ++static const struct of_device_id imx6sx_mcc_tty_ids[] = { ++ { .compatible = "fsl,imx6sx-mcc-tty", }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver imxmcctty_driver = { ++ .driver = { ++ .name = "imx6sx-mcc-tty", ++ .owner = THIS_MODULE, ++ .of_match_table = imx6sx_mcc_tty_ids, ++ }, ++ .probe = imx_mcc_tty_probe, ++ .remove = imx_mcc_tty_remove, ++}; ++ ++/*! ++ * Initialise the imxmcctty_driver. ++ * ++ * @return The function always returns 0. ++ */ ++ ++static int __init imxmcctty_init(void) ++{ ++ if (platform_driver_register(&imxmcctty_driver) != 0) ++ return -ENODEV; ++ ++ printk(KERN_INFO "IMX MCC TTY driver module loaded\n"); ++ return 0; ++} ++ ++static void __exit imxmcctty_exit(void) ++{ ++ /* Unregister the device structure */ ++ platform_driver_unregister(&imxmcctty_driver); ++} ++ ++module_init(imxmcctty_init); ++module_exit(imxmcctty_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("MCC TTY driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/char/imx_amp/imx_sema4.c linux-3.14.72/drivers/char/imx_amp/imx_sema4.c +--- linux-3.14.72.orig/drivers/char/imx_amp/imx_sema4.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/char/imx_amp/imx_sema4.c 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,419 @@ ++/* ++ * Copyright (C) 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct imx_sema4_mutex_device *imx6_sema4; ++ ++/*! ++ * \brief mutex create function. ++ * ++ * This function allocates imx_sema4_mutex structure and returns a handle ++ * to it. The mutex to be created is identified by SEMA4 device number and mutex ++ * (gate) number. The handle is used to reference the created mutex in calls to ++ * other imx_sema4_mutex API functions. This function is to be called only ++ * once for each mutex. ++ * ++ * \param[in] dev_num SEMA4 device (module) number. ++ * \param[in] mutex_num Mutex (gate) number. ++ * ++ * \return NULL (Failure.) ++ * \return imx_sema4_mutex (Success.) ++ */ ++struct imx_sema4_mutex * ++imx_sema4_mutex_create(u32 dev_num, u32 mutex_num) ++{ ++ struct imx_sema4_mutex *mutex_ptr = NULL; ++ ++ if ((mutex_num > SEMA4_NUM_GATES) || dev_num >= SEMA4_NUM_DEVICES) ++ goto out; ++ ++ if (imx6_sema4->cpine_val & (1 < mutex_num)) { ++ pr_err("Error: requiring a allocated sema4.\n"); ++ pr_err("mutex_num %d cpine_val 0x%08x.\n", ++ mutex_num, imx6_sema4->cpine_val); ++ } ++ mutex_ptr = kzalloc(sizeof(*mutex_ptr), GFP_KERNEL); ++ if (!mutex_ptr) ++ goto out; ++ imx6_sema4->mutex_ptr[mutex_num] = mutex_ptr; ++ imx6_sema4->alloced |= 1 < mutex_num; ++ imx6_sema4->cpine_val |= idx_sema4[mutex_num]; ++ writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE); ++ ++ mutex_ptr->valid = CORE_MUTEX_VALID; ++ mutex_ptr->gate_num = mutex_num; ++ init_waitqueue_head(&mutex_ptr->wait_q); ++ ++out: ++ return mutex_ptr; ++} ++EXPORT_SYMBOL(imx_sema4_mutex_create); ++ ++/*! ++ * \brief mutex destroy function. ++ * ++ * This function destroys a mutex. ++ * ++ * \param[in] mutex_ptr Pointer to mutex structure. ++ * ++ * \return MQX_COMPONENT_DOES_NOT_EXIST (mutex component not installed.) ++ * \return MQX_INVALID_PARAMETER (Wrong input parameter.) ++ * \return COREMUTEX_OK (Success.) ++ * ++ */ ++int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr) ++{ ++ u32 mutex_num; ++ ++ if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID)) ++ return -EINVAL; ++ ++ mutex_num = mutex_ptr->gate_num; ++ if ((imx6_sema4->cpine_val & idx_sema4[mutex_num]) == 0) { ++ pr_err("Error: trying to destory a un-allocated sema4.\n"); ++ pr_err("mutex_num %d cpine_val 0x%08x.\n", ++ mutex_num, imx6_sema4->cpine_val); ++ } ++ imx6_sema4->mutex_ptr[mutex_num] = NULL; ++ imx6_sema4->alloced &= ~(1 << mutex_num); ++ imx6_sema4->cpine_val &= ~(idx_sema4[mutex_num]); ++ writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE); ++ ++ kfree(mutex_ptr); ++ ++ return 0; ++} ++EXPORT_SYMBOL(imx_sema4_mutex_destroy); ++ ++/*! ++ * \brief Lock the mutex, shouldn't be interruted by INT. ++ * ++ * This function attempts to lock a mutex. If the mutex is already locked ++ * by another task the function return -EBUSY, and tell invoker wait until ++ * it is possible to lock the mutex. ++ * ++ * \param[in] mutex_ptr Pointer to mutex structure. ++ * ++ * \return MQX_INVALID_POINTER (Wrong pointer to the mutex structure provided.) ++ * \return COREMUTEX_OK (mutex successfully locked.) ++ * ++ * \see imx_sema4_mutex_unlock ++ */ ++int _imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr) ++{ ++ int ret = 0, i = mutex_ptr->gate_num; ++ ++ if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID)) ++ return -EINVAL; ++ ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= SEMA4_GATE_MASK; ++ /* Check to see if this core already own it */ ++ if (mutex_ptr->gate_val == SEMA4_A9_LOCK) { ++ /* return -EBUSY, invoker should be in sleep, and re-lock ag */ ++ pr_err("%s -> %s %d already locked, wait! num %d val %d.\n", ++ __FILE__, __func__, __LINE__, ++ i, mutex_ptr->gate_val); ++ ret = -EBUSY; ++ goto out; ++ } else { ++ /* try to lock the mutex */ ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); ++ mutex_ptr->gate_val |= SEMA4_A9_LOCK; ++ writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= SEMA4_GATE_MASK; ++ /* double check the mutex is locked, otherwise, return -EBUSY */ ++ if (mutex_ptr->gate_val != SEMA4_A9_LOCK) { ++ pr_debug("wait-locked num %d val %d.\n", ++ i, mutex_ptr->gate_val); ++ ret = -EBUSY; ++ } ++ } ++out: ++ return ret; ++} ++ ++/* ! ++ * \brief Try to lock the core mutex. ++ * ++ * This function attempts to lock a mutex. If the mutex is successfully locked ++ * for the calling task, SEMA4_A9_LOCK is returned. If the mutex is already ++ * locked by another task, the function does not block but rather returns ++ * negative immediately. ++ * ++ * \param[in] mutex_ptr Pointer to core_mutex structure. ++ * ++ * \return SEMA4_A9_LOCK (mutex successfully locked.) ++ * \return negative (mutex not locked.) ++ * ++ */ ++int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr) ++{ ++ int ret = 0; ++ ++ ret = _imx_sema4_mutex_lock(mutex_ptr); ++ if (ret == 0) ++ return SEMA4_A9_LOCK; ++ else ++ return ret; ++} ++EXPORT_SYMBOL(imx_sema4_mutex_trylock); ++ ++/*! ++ * \brief Invoke _imx_sema4_mutex_lock to lock the mutex. ++ * ++ * This function attempts to lock a mutex. If the mutex is already locked ++ * by another task the function, sleep itself and schedule out. ++ * Wait until it is possible to lock the mutex. ++ * ++ * Invoker should add its own wait queue into the wait queue header of the ++ * required semaphore, set TASK_INTERRUPTIBLE and sleep on itself by ++ * schedule() when the lock is failed. Re-try to lock the semaphore when ++ * it is woke up by the sema4 isr. ++ * ++ * \param[in] mutex_ptr Pointer to mutex structure. ++ * ++ * \return SEMA4_A9_LOCK (mutex successfully locked.) ++ * ++ * \see imx_sema4_mutex_unlock ++ */ ++int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr) ++{ ++ int ret = 0; ++ unsigned long flags; ++ unsigned long timeout_j; /* jiffies */ ++ ++ spin_lock_irqsave(&imx6_sema4->lock, flags); ++ ret = _imx_sema4_mutex_lock(mutex_ptr); ++ spin_unlock_irqrestore(&imx6_sema4->lock, flags); ++ while (-EBUSY == ret) { ++ if (MCC_SHMEM_SEMAPHORE_NUMBER == mutex_ptr->gate_num) { ++ timeout_j = msecs_to_jiffies(1000); ++ wait_event_timeout(mutex_ptr->wait_q, ++ mutex_ptr->gate_val == 0, timeout_j); ++ pr_debug("wake up val %d.\n", mutex_ptr->gate_val); ++ } ++ spin_lock_irqsave(&imx6_sema4->lock, flags); ++ ret = _imx_sema4_mutex_lock(mutex_ptr); ++ spin_unlock_irqrestore(&imx6_sema4->lock, flags); ++ if (ret == 0) ++ break; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(imx_sema4_mutex_lock); ++ ++/*! ++ * \brief Unlock the mutex. ++ * ++ * This function unlocks the specified mutex. ++ * ++ * \param[in] mutex_ptr Pointer to mutex structure. ++ * ++ * \return -EINVAL (Wrong pointer to the mutex structure provided.) ++ * \return -EINVAL (This mutex has not been locked by this core.) ++ * \return 0 (mutex successfully unlocked.) ++ * ++ * \see imx_sema4_mutex_lock ++ */ ++int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr) ++{ ++ int ret = 0, i = mutex_ptr->gate_num; ++ ++ if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID)) ++ return -EINVAL; ++ ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= SEMA4_GATE_MASK; ++ /* make sure it is locked by this core */ ++ if (mutex_ptr->gate_val != SEMA4_A9_LOCK) { ++ pr_err("%d Trying to unlock an unlock mutex.\n", __LINE__); ++ ret = -EINVAL; ++ goto out; ++ } ++ /* unlock it */ ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); ++ writeb(mutex_ptr->gate_val | SEMA4_UNLOCK, imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= SEMA4_GATE_MASK; ++ /* make sure it is locked by this core */ ++ if (mutex_ptr->gate_val == SEMA4_A9_LOCK) ++ pr_err("%d ERROR, failed to unlock the mutex.\n", __LINE__); ++ ++out: ++ return ret; ++} ++EXPORT_SYMBOL(imx_sema4_mutex_unlock); ++ ++/* ++ * isr used by SEMA4, wake up the sleep tasks if there are the tasks waiting ++ * for locking semaphore. ++ * FIXME the bits order of the gatn, cpnie, cpnntf are not exact identified yet! ++ */ ++static irqreturn_t imx_sema4_isr(int irq, void *dev_id) ++{ ++ int i; ++ struct imx_sema4_mutex *mutex_ptr; ++ u32 mask; ++ struct imx_sema4_mutex_device *imx6_sema4 = dev_id; ++ ++ imx6_sema4->cpntf_val = readw(imx6_sema4->ioaddr + SEMA4_CP0NTF); ++ for (i = 0; i < SEMA4_NUM_GATES; i++) { ++ mask = idx_sema4[i]; ++ if ((imx6_sema4->cpntf_val) & mask) { ++ mutex_ptr = imx6_sema4->mutex_ptr[i]; ++ /* ++ * An interrupt is pending on this mutex, the only way ++ * to clear it is to lock it (either by this core or ++ * another). ++ */ ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); ++ mutex_ptr->gate_val |= SEMA4_A9_LOCK; ++ writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= SEMA4_GATE_MASK; ++ if (mutex_ptr->gate_val == SEMA4_A9_LOCK) { ++ /* ++ * wake up the wait queue, whatever there ++ * are wait task or not. ++ * NOTE: check gate is locted or not in ++ * sema4_lock func by wait task. ++ */ ++ mutex_ptr->gate_val = ++ readb(imx6_sema4->ioaddr + i); ++ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); ++ mutex_ptr->gate_val |= SEMA4_UNLOCK; ++ ++ writeb(mutex_ptr->gate_val, ++ imx6_sema4->ioaddr + i); ++ wake_up(&mutex_ptr->wait_q); ++ } else { ++ pr_debug("can't lock gate%d %s retry!\n", i, ++ mutex_ptr->gate_val ? ++ "locked by m4" : ""); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static const struct of_device_id imx_sema4_dt_ids[] = { ++ { .compatible = "fsl,imx6sx-sema4", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx_sema4_dt_ids); ++ ++static int imx_sema4_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int ret; ++ ++ imx6_sema4 = devm_kzalloc(&pdev->dev, sizeof(*imx6_sema4), GFP_KERNEL); ++ if (!imx6_sema4) ++ return -ENOMEM; ++ ++ imx6_sema4->dev = &pdev->dev; ++ imx6_sema4->cpine_val = 0; ++ spin_lock_init(&imx6_sema4->lock); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (IS_ERR(res)) { ++ dev_err(&pdev->dev, "unable to get imx sema4 resource 0\n"); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ imx6_sema4->ioaddr = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(imx6_sema4->ioaddr)) { ++ ret = PTR_ERR(imx6_sema4->ioaddr); ++ goto err; ++ } ++ ++ imx6_sema4->irq = platform_get_irq(pdev, 0); ++ if (!imx6_sema4->irq) { ++ dev_err(&pdev->dev, "failed to get irq\n"); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, imx6_sema4->irq, imx_sema4_isr, ++ IRQF_SHARED, "imx6sx-sema4", imx6_sema4); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request imx sema4 irq\n"); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ platform_set_drvdata(pdev, imx6_sema4); ++ ++err: ++ return ret; ++} ++ ++static int imx_sema4_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver imx_sema4_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "imx-sema4", ++ .of_match_table = imx_sema4_dt_ids, ++ }, ++ .probe = imx_sema4_probe, ++ .remove = imx_sema4_remove, ++}; ++ ++static int __init imx_sema4_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&imx_sema4_driver); ++ if (ret) ++ pr_err("Unable to initialize sema4 driver\n"); ++ else ++ pr_info("imx sema4 driver is registered.\n"); ++ ++ return ret; ++} ++ ++static void __exit imx_sema4_exit(void) ++{ ++ pr_info("imx sema4 driver is unregistered.\n"); ++ platform_driver_unregister(&imx_sema4_driver); ++} ++ ++module_exit(imx_sema4_exit); ++module_init(imx_sema4_init); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IMX SEMA4 driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/char/imx_amp/Kconfig linux-3.14.72/drivers/char/imx_amp/Kconfig +--- linux-3.14.72.orig/drivers/char/imx_amp/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/char/imx_amp/Kconfig 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,30 @@ ++# ++# imx mcc ++# ++ ++config IMX_SEMA4 ++ bool "IMX SEMA4 driver" ++ depends on SOC_IMX6SX ++ help ++ Support for IMX SEMA4 driver, most people should say N here. ++ ++config IMX_MCC_TEST ++ bool "IMX MCC test driver" ++ depends on SOC_IMX6SX && IMX_SEMA4 ++ default y ++ help ++ If you say Y here, you will get support for IMX MCC ping pong ++ test and CAN test. Say N here, if the IMX_MCC_TTY interface is ++ mandatory required. ++ ++ If unsure, it is safe to say Y. ++ ++config IMX_MCC_TTY ++ bool "IMX PTY for MCC interface" ++ depends on SOC_IMX6SX && IMX_SEMA4 && !IMX_MCC_TEST ++ help ++ This enables a PTY node for IMX6SX MCC, used as interface ++ between kernel space and user space. Say N here, if the ++ interface is not required. ++ ++#end imx mcc +diff -Nur linux-3.14.72.orig/drivers/char/imx_amp/Makefile linux-3.14.72/drivers/char/imx_amp/Makefile +--- linux-3.14.72.orig/drivers/char/imx_amp/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/char/imx_amp/Makefile 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,7 @@ ++# ++# Makefile for imx mcc ++# ++# ++obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o ++obj-$(CONFIG_IMX_MCC_TEST) += imx_mcc_test.o ++obj-$(CONFIG_IMX_MCC_TTY) += imx_mcc_tty.o +diff -Nur linux-3.14.72.orig/drivers/char/Kconfig linux-3.14.72/drivers/char/Kconfig +--- linux-3.14.72.orig/drivers/char/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/char/Kconfig 2016-06-19 22:11:55.109152867 +0200 +@@ -82,6 +82,33 @@ + + 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 FSL_OTP_WRITE_ENABLE ++ bool "Enable writing support of OTP pages on Freescale chips" ++ depends on FSL_OTP ++ default n ++ help ++ If you say Y here, you will enable support for writing of the ++ OTP pages. This is dangerous by nature as you can only program ++ the pages once, so only enable this option when you actually ++ need it so as to not inadvertently clobber data. ++ ++ If unsure, say N. ++ + config PRINTER + tristate "Parallel printer support" + depends on PARPORT +@@ -600,5 +627,6 @@ + device appear much like a simple EEPROM, and knows + how to partition a single ROM for multiple purposes. + ++source "drivers/char/imx_amp/Kconfig" + endmenu + +diff -Nur linux-3.14.72.orig/drivers/char/Makefile linux-3.14.72/drivers/char/Makefile +--- linux-3.14.72.orig/drivers/char/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/char/Makefile 2016-06-19 22:11:55.109152867 +0200 +@@ -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 + +@@ -61,3 +62,4 @@ + js-rtc-y = rtc.o + + obj-$(CONFIG_TILE_SROM) += tile-srom.o ++obj-$(CONFIG_HAVE_IMX_AMP) += imx_amp/ +diff -Nur linux-3.14.72.orig/drivers/clk/clk.c linux-3.14.72/drivers/clk/clk.c +--- linux-3.14.72.orig/drivers/clk/clk.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/clk/clk.c 2016-06-19 22:11:55.109152867 +0200 +@@ -10,6 +10,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -1707,6 +1708,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 +1735,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); +@@ -2429,6 +2443,7 @@ + void *data) + { + struct of_clk_provider *cp; ++ int ret; + + cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL); + if (!cp) +@@ -2443,7 +2458,11 @@ + mutex_unlock(&of_clk_mutex); + pr_debug("Added clock from %s\n", np->full_name); + +- return 0; ++ ret = of_clk_set_defaults(np, true); ++ if (ret < 0) ++ of_clk_del_provider(np); ++ ++ return ret; + } + EXPORT_SYMBOL_GPL(of_clk_add_provider); + +@@ -2543,6 +2562,7 @@ + for_each_matching_node_and_match(np, matches, &match) { + of_clk_init_cb_t clk_init_cb = match->data; + clk_init_cb(np); ++ of_clk_set_defaults(np, true); + } + } + #endif +diff -Nur linux-3.14.72.orig/drivers/clk/clk-conf.c linux-3.14.72/drivers/clk/clk-conf.c +--- linux-3.14.72.orig/drivers/clk/clk-conf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/clk/clk-conf.c 2016-06-19 22:11:55.109152867 +0200 +@@ -0,0 +1,143 @@ ++/* ++ * Copyright (C) 2014 Samsung Electronics Co., Ltd. ++ * Sylwester Nawrocki ++ * ++ * This program is free software; you can 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 "clk.h" ++ ++static int __set_clk_parents(struct device_node *node, bool clk_supplier) ++{ ++ struct of_phandle_args clkspec; ++ int index, rc, num_parents; ++ struct clk *clk, *pclk; ++ ++ num_parents = of_count_phandle_with_args(node, "assigned-clock-parents", ++ "#clock-cells"); ++ if (num_parents == -EINVAL) ++ pr_err("clk: invalid value of clock-parents property at %s\n", ++ node->full_name); ++ ++ for (index = 0; index < num_parents; index++) { ++ rc = of_parse_phandle_with_args(node, "assigned-clock-parents", ++ "#clock-cells", index, &clkspec); ++ if (rc < 0) { ++ /* skip empty (null) phandles */ ++ if (rc == -ENOENT) ++ continue; ++ else ++ return rc; ++ } ++ if (clkspec.np == node && !clk_supplier) ++ return 0; ++ pclk = of_clk_get_by_clkspec(&clkspec); ++ if (IS_ERR(pclk)) { ++ pr_warn("clk: couldn't get parent clock %d for %s\n", ++ index, node->full_name); ++ return PTR_ERR(pclk); ++ } ++ ++ rc = of_parse_phandle_with_args(node, "assigned-clocks", ++ "#clock-cells", index, &clkspec); ++ if (rc < 0) ++ goto err; ++ if (clkspec.np == node && !clk_supplier) { ++ rc = 0; ++ goto err; ++ } ++ clk = of_clk_get_by_clkspec(&clkspec); ++ if (IS_ERR(pclk)) { ++ pr_warn("clk: couldn't get parent clock %d for %s\n", ++ index, node->full_name); ++ rc = PTR_ERR(pclk); ++ goto err; ++ } ++ ++ rc = clk_set_parent(clk, pclk); ++ if (rc < 0) ++ pr_err("clk: failed to reparent %s to %s: %d\n", ++ __clk_get_name(clk), __clk_get_name(pclk), rc); ++ clk_put(clk); ++ clk_put(pclk); ++ } ++ return 0; ++err: ++ clk_put(pclk); ++ return rc; ++} ++ ++static int __set_clk_rates(struct device_node *node, bool clk_supplier) ++{ ++ struct of_phandle_args clkspec; ++ struct property *prop; ++ const __be32 *cur; ++ int rc, index = 0; ++ struct clk *clk; ++ u32 rate; ++ ++ of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) { ++ if (rate) { ++ rc = of_parse_phandle_with_args(node, "assigned-clocks", ++ "#clock-cells", index, &clkspec); ++ if (rc < 0) { ++ /* skip empty (null) phandles */ ++ if (rc == -ENOENT) ++ continue; ++ else ++ return rc; ++ } ++ if (clkspec.np == node && !clk_supplier) ++ return 0; ++ ++ clk = of_clk_get_by_clkspec(&clkspec); ++ if (IS_ERR(clk)) { ++ pr_warn("clk: couldn't get clock %d for %s\n", ++ index, node->full_name); ++ return PTR_ERR(clk); ++ } ++ ++ rc = clk_set_rate(clk, rate); ++ if (rc < 0) ++ pr_err("clk: couldn't set %s clock rate: %d\n", ++ __clk_get_name(clk), rc); ++ clk_put(clk); ++ } ++ index++; ++ } ++ return 0; ++} ++ ++/** ++ * of_clk_set_defaults() - parse and set assigned clocks configuration ++ * @node: device node to apply clock settings for ++ * @clk_supplier: true if clocks supplied by @node should also be considered ++ * ++ * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties ++ * and sets any specified clock parents and rates. The @clk_supplier argument ++ * should be set to true if @node may be also a clock supplier of any clock ++ * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties. ++ * If @clk_supplier is false the function exits returnning 0 as soon as it ++ * determines the @node is also a supplier of any of the clocks. ++ */ ++int of_clk_set_defaults(struct device_node *node, bool clk_supplier) ++{ ++ int rc; ++ ++ if (!node) ++ return 0; ++ ++ rc = __set_clk_parents(node, clk_supplier); ++ if (rc < 0) ++ return rc; ++ ++ return __set_clk_rates(node, clk_supplier); ++} +diff -Nur linux-3.14.72.orig/drivers/clk/clkdev.c linux-3.14.72/drivers/clk/clkdev.c +--- linux-3.14.72.orig/drivers/clk/clkdev.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/clk/clkdev.c 2016-06-19 22:11:55.109152867 +0200 +@@ -27,6 +27,32 @@ + static DEFINE_MUTEX(clocks_mutex); + + #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) ++ ++/** ++ * of_clk_get_by_clkspec() - Lookup a clock form a clock provider ++ * @clkspec: pointer to a clock specifier data structure ++ * ++ * This function looks up a struct clk from the registered list of clock ++ * providers, an input is a clock specifier data structure as returned ++ * from the of_parse_phandle_with_args() function call. ++ */ ++struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec) ++{ ++ struct clk *clk; ++ ++ if (!clkspec) ++ return ERR_PTR(-EINVAL); ++ ++ of_clk_lock(); ++ clk = __of_clk_get_from_provider(clkspec); ++ ++ if (!IS_ERR(clk) && !__clk_get(clk)) ++ clk = ERR_PTR(-ENOENT); ++ ++ of_clk_unlock(); ++ return clk; ++} ++ + struct clk *of_clk_get(struct device_node *np, int index) + { + struct of_phandle_args clkspec; +@@ -41,13 +67,7 @@ + if (rc) + return ERR_PTR(rc); + +- of_clk_lock(); +- clk = __of_clk_get_from_provider(&clkspec); +- +- if (!IS_ERR(clk) && !__clk_get(clk)) +- clk = ERR_PTR(-ENOENT); +- +- of_clk_unlock(); ++ clk = of_clk_get_by_clkspec(&clkspec); + of_node_put(clkspec.np); + return clk; + } +diff -Nur linux-3.14.72.orig/drivers/clk/clk.h linux-3.14.72/drivers/clk/clk.h +--- linux-3.14.72.orig/drivers/clk/clk.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/clk/clk.h 2016-06-19 22:11:55.113152605 +0200 +@@ -10,6 +10,7 @@ + */ + + #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) ++struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec); + struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec); + void of_clk_lock(void); + void of_clk_unlock(void); +diff -Nur linux-3.14.72.orig/drivers/clk/clk-mux.c linux-3.14.72/drivers/clk/clk-mux.c +--- linux-3.14.72.orig/drivers/clk/clk-mux.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/clk/clk-mux.c 2016-06-19 22:11:55.113152605 +0200 +@@ -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.72.orig/drivers/clk/Makefile linux-3.14.72/drivers/clk/Makefile +--- linux-3.14.72.orig/drivers/clk/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/clk/Makefile 2016-06-19 22:11:55.113152605 +0200 +@@ -8,6 +8,9 @@ + obj-$(CONFIG_COMMON_CLK) += clk-gate.o + obj-$(CONFIG_COMMON_CLK) += clk-mux.o + obj-$(CONFIG_COMMON_CLK) += clk-composite.o ++ifeq ($(CONFIG_OF), y) ++obj-$(CONFIG_COMMON_CLK) += clk-conf.o ++endif + + # hardware specific clock types + # please keep this section sorted lexicographically by file/directory path name +diff -Nur linux-3.14.72.orig/drivers/cpufreq/cpufreq_interactive.c linux-3.14.72/drivers/cpufreq/cpufreq_interactive.c +--- linux-3.14.72.orig/drivers/cpufreq/cpufreq_interactive.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/cpufreq/cpufreq_interactive.c 2016-06-19 22:11:55.113152605 +0200 +@@ -0,0 +1,1345 @@ ++/* ++ * 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) { ++ if (policy->governor->initialized == 1) { ++ cpufreq_unregister_notifier(&cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ idle_notifier_unregister(&cpufreq_interactive_idle_nb); ++ } ++ ++ sysfs_remove_group(get_governor_parent_kobj(policy), ++ get_sysfs_attr()); ++ 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.72.orig/drivers/cpufreq/cpufreq_ondemand.c linux-3.14.72/drivers/cpufreq/cpufreq_ondemand.c +--- linux-3.14.72.orig/drivers/cpufreq/cpufreq_ondemand.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/cpufreq/cpufreq_ondemand.c 2016-06-19 22:11:55.113152605 +0200 +@@ -50,7 +50,8 @@ + * efficient idling at a higher frequency/voltage is. + * Pavel Machek says this is not so for various generations of AMD and old + * Intel systems. +- * Mike Chan (android.com) claims this is also not true for ARM. ++ * ARM systems v7 and later generally good idle power management as well, so ++ * treat them the same. + * Because of this, whitelist specific known (series) of CPUs by default, and + * leave all others up to the user. + */ +@@ -65,6 +66,9 @@ + boot_cpu_data.x86_model >= 15) + return 1; + #endif ++#if defined(CONFIG_ARM) && defined(CPU_V7) ++ return 1; ++#endif + return 0; + } + +diff -Nur linux-3.14.72.orig/drivers/cpufreq/imx6q-cpufreq.c linux-3.14.72/drivers/cpufreq/imx6q-cpufreq.c +--- linux-3.14.72.orig/drivers/cpufreq/imx6q-cpufreq.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/cpufreq/imx6q-cpufreq.c 2016-06-19 22:11:55.113152605 +0200 +@@ -1,11 +1,12 @@ + /* +- * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * Copyright (C) 2013-2015 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 +@@ -16,10 +17,12 @@ + #include + #include + #include ++#include + + #define PU_SOC_VOLTAGE_NORMAL 1250000 + #define PU_SOC_VOLTAGE_HIGH 1275000 + #define FREQ_1P2_GHZ 1200000000 ++#define FREQ_396_MHZ 396000 + + static struct regulator *arm_reg; + static struct regulator *pu_reg; +@@ -30,11 +33,14 @@ + static struct clk *pll1_sw_clk; + static struct clk *step_clk; + static struct clk *pll2_pfd2_396m_clk; ++static struct clk *pll1_bypass; ++static struct clk *pll1_bypass_src; ++static struct clk *pll1; + + 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; + +@@ -44,6 +50,9 @@ + unsigned long freq_hz, volt, volt_old; + unsigned int old_freq, new_freq; + int ret; ++ int tol = 25000; /* 25mv tollerance */ ++ ++ mutex_lock(&set_cpufreq_lock); + + new_freq = freq_table[index].frequency; + freq_hz = new_freq * 1000; +@@ -54,6 +63,7 @@ + if (IS_ERR(opp)) { + rcu_read_unlock(); + dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); ++ mutex_unlock(&set_cpufreq_lock); + return PTR_ERR(opp); + } + +@@ -61,26 +71,39 @@ + rcu_read_unlock(); + volt_old = regulator_get_voltage(arm_reg); + +- dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", ++ dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld/%d mV\n", + old_freq / 1000, volt_old / 1000, +- new_freq / 1000, volt / 1000); ++ new_freq / 1000, volt / 1000, imx6_soc_volt[index] / 1000); ++ /* ++ * CPU freq is increasing, so need to ensure ++ * that bus frequency is increased too. ++ */ ++ if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ) ++ request_bus_freq(BUS_FREQ_HIGH); + + /* 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; ++ if (!IS_ERR(pu_reg) && regulator_is_enabled(pu_reg)) { ++ ret = regulator_set_voltage_tol(pu_reg, ++ imx6_soc_volt[index], tol); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddpu up: %d\n", ret); ++ mutex_unlock(&set_cpufreq_lock); ++ return ret; ++ } + } +- ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); ++ ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], tol); + if (ret) { + dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); ++ mutex_unlock(&set_cpufreq_lock); + return ret; + } +- ret = regulator_set_voltage_tol(arm_reg, volt, 0); ++ ret = regulator_set_voltage_tol(arm_reg, volt, tol); + if (ret) { + dev_err(cpu_dev, + "failed to scale vddarm up: %d\n", ret); ++ mutex_unlock(&set_cpufreq_lock); + return ret; + } + } +@@ -97,45 +120,79 @@ + 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_rate(pll1, new_freq * 1000); ++ /* ++ * Ensure pll1_bypass is set back to pll1. ++ */ ++ clk_set_parent(pll1_bypass, pll1); + clk_set_parent(pll1_sw_clk, pll1_sys_clk); +- } ++ } else ++ /* ++ * Need to ensure that PLL1 is bypassed and enabled ++ * before ARM-PODF is set. ++ */ ++ clk_set_parent(pll1_bypass, pll1_bypass_src); ++ + + /* 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); ++ regulator_set_voltage_tol(arm_reg, volt_old, tol); ++ mutex_unlock(&set_cpufreq_lock); + return ret; + } + + /* scaling down? scale voltage after frequency */ + if (new_freq < old_freq) { +- ret = regulator_set_voltage_tol(arm_reg, volt, 0); ++ ret = regulator_set_voltage_tol(arm_reg, volt, tol); + 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); ++ ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], tol); + 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; ++ if (!IS_ERR(pu_reg) && regulator_is_enabled(pu_reg)) { ++ ret = regulator_set_voltage_tol(pu_reg, ++ imx6_soc_volt[index], tol); ++ if (ret) { ++ dev_warn(cpu_dev, ++ "failed to scale vddpu down: %d\n", ++ ret); ++ ret = 0; ++ } + } + } ++ /* ++ * If CPU is dropped to the lowest level, release the need ++ * for a high bus frequency. ++ */ ++ if (old_freq > FREQ_396_MHZ && new_freq <= FREQ_396_MHZ) ++ release_bus_freq(BUS_FREQ_HIGH); + ++ mutex_unlock(&set_cpufreq_lock); + return 0; + } + + static int imx6q_cpufreq_init(struct cpufreq_policy *policy) + { ++ int ret; ++ + policy->clk = arm_clk; +- return cpufreq_generic_init(policy, freq_table, transition_latency); ++ policy->cur = clk_get_rate(arm_clk) / 1000; ++ ++ ret = cpufreq_generic_init(policy, freq_table, transition_latency); ++ if (ret) { ++ dev_err(cpu_dev, "imx6 cpufreq init failed!\n"); ++ return ret; ++ } ++ if (policy->cur > FREQ_396_MHZ) ++ request_bus_freq(BUS_FREQ_HIGH); ++ return 0; + } + + static struct cpufreq_driver imx6q_cpufreq_driver = { +@@ -149,6 +206,40 @@ + .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 imx6q_cpufreq_probe(struct platform_device *pdev) + { + struct device_node *np; +@@ -157,7 +248,7 @@ + int num, ret; + const struct property *prop; + const __be32 *val; +- u32 nr, i, j; ++ u32 nr, j, i = 0; + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) { +@@ -176,23 +267,39 @@ + 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"); ++ pll1_bypass = devm_clk_get(cpu_dev, "pll1_bypass"); ++ pll1 = devm_clk_get(cpu_dev, "pll1"); ++ pll1_bypass_src = devm_clk_get(cpu_dev, "pll1_bypass_src"); ++ + 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)) { ++ IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk) || ++ IS_ERR(pll1_bypass) || IS_ERR(pll1) || ++ IS_ERR(pll1_bypass_src)) { + 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)) { ++ arm_reg = devm_regulator_get_optional(cpu_dev, "arm"); ++ pu_reg = devm_regulator_get_optional(cpu_dev, "pu"); ++ soc_reg = devm_regulator_get_optional(cpu_dev, "soc"); ++ if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) { + dev_err(cpu_dev, "failed to get regulators\n"); + ret = -ENOENT; + goto put_node; + } + + /* ++ * soc_reg sync with arm_reg if arm shares the same regulator ++ * with soc. Otherwise, regulator common framework will refuse to update ++ * this consumer's voltage right now while another consumer voltage ++ * still keep in old one. For example, imx6sx-sdb with pfuze200 in ++ * ldo-bypass mode. ++ */ ++ of_property_read_u32(np, "fsl,arm-soc-shared", &i); ++ if (i == 1) ++ soc_reg = arm_reg; ++ /* + * We expect an OPP table supplied by platform. + * Just, incase the platform did not supply the OPP + * table, it will try to get it. +@@ -245,6 +352,12 @@ + unsigned long volt = be32_to_cpup(val++); + if (freq_table[j].frequency == freq) { + imx6_soc_volt[soc_opp_count++] = volt; ++#ifdef CONFIG_MX6_VPU_352M ++ if (freq == 792000) { ++ pr_info("increase SOC/PU voltage for VPU352MHz\n"); ++ imx6_soc_volt[soc_opp_count - 1] = 1250000; ++ } ++#endif + break; + } + } +@@ -270,9 +383,12 @@ + 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; ++ if (!IS_ERR(pu_reg)) { ++ 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 +@@ -291,6 +407,9 @@ + if (ret > 0) + transition_latency += ret * 1000; + ++ mutex_init(&set_cpufreq_lock); ++ register_pm_notifier(&imx6_cpufreq_pm_notifier); ++ + ret = cpufreq_register_driver(&imx6q_cpufreq_driver); + if (ret) { + dev_err(cpu_dev, "failed register driver: %d\n", ret); +diff -Nur linux-3.14.72.orig/drivers/cpufreq/Kconfig linux-3.14.72/drivers/cpufreq/Kconfig +--- linux-3.14.72.orig/drivers/cpufreq/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/cpufreq/Kconfig 2016-06-19 22:11:55.113152605 +0200 +@@ -102,6 +102,16 @@ + Be aware that not all cpufreq drivers support the conservative + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. ++ ++config CPU_FREQ_DEFAULT_GOV_INTERACTIVE ++ bool "interactive" ++ select CPU_FREQ_GOV_INTERACTIVE ++ 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. ++ + endchoice + + config CPU_FREQ_GOV_PERFORMANCE +@@ -159,6 +169,19 @@ + + If in doubt, say N. + ++config CPU_FREQ_GOV_INTERACTIVE ++ tristate "'interactive' cpufreq policy governor" ++ help ++ 'interactive' - This driver adds a dynamic cpufreq policy governor ++ designed for latency-sensitive workloads. ++ This governor attempts to reduce the latency of clock ++ increases so that the system is more responsive to ++ interactive workloads. ++ To compile this driver as a module, choose M here: the ++ module will be called cpufreq_interactive. ++ For details, take a look at linux/Documentation/cpu-freq. ++ If in doubt, say N. ++ + config CPU_FREQ_GOV_CONSERVATIVE + tristate "'conservative' cpufreq governor" + depends on CPU_FREQ +diff -Nur linux-3.14.72.orig/drivers/cpufreq/Makefile linux-3.14.72/drivers/cpufreq/Makefile +--- linux-3.14.72.orig/drivers/cpufreq/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/cpufreq/Makefile 2016-06-19 22:11:55.113152605 +0200 +@@ -9,6 +9,7 @@ + obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o + obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o + obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o ++obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o + obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o + + obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/caamalg.c linux-3.14.72/drivers/crypto/caam/caamalg.c +--- linux-3.14.72.orig/drivers/crypto/caam/caamalg.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/caamalg.c 2016-06-19 22:11:55.113152605 +0200 +@@ -1,7 +1,7 @@ + /* + * caam - Freescale FSL CAAM support for crypto API + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc. + * + * Based on talitos crypto API driver. + * +@@ -53,6 +53,7 @@ + #include "error.h" + #include "sg_sw_sec4.h" + #include "key_gen.h" ++#include + + /* + * crypto alg +@@ -287,6 +288,8 @@ + desc_bytes(desc), 1); + #endif + ++ dma_sync_single_for_cpu(jrdev, ctx->sh_desc_enc_dma, desc_bytes(desc), ++ DMA_TO_DEVICE); + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer +@@ -354,6 +357,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_cpu(jrdev, ctx->sh_desc_dec_dma, desc_bytes(desc), ++ DMA_TO_DEVICE); + + /* + * Job Descriptor and Shared Descriptors +@@ -437,6 +442,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_cpu(jrdev, ctx->sh_desc_givenc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } +@@ -505,11 +512,15 @@ + dev_err(jrdev, "unable to map key i/o memory\n"); + return -ENOMEM; + } ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len + keys.enckeylen, 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ++ ctx->split_key_pad_len + keys.enckeylen, ++ DMA_TO_DEVICE); + + ctx->enckeylen = keys.enckeylen; + +@@ -548,6 +559,7 @@ + return -ENOMEM; + } + ctx->enckeylen = keylen; ++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); + + /* ablkcipher_encrypt shared descriptor */ + desc = ctx->sh_desc_enc; +@@ -566,10 +578,15 @@ + /* Propagate errors from shared to job descriptor */ + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + +- /* Load iv */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | tfm->ivsize); +- ++ /* load IV */ ++ if (strncmp(ablkcipher->base.__crt_alg->cra_name, "ctr(aes)", 8) == 0) { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize | ++ (16 << LDST_OFFSET_SHIFT)); ++ } else { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize); ++ } + /* Load operation */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +@@ -590,6 +607,9 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ + /* ablkcipher_decrypt shared descriptor */ + desc = ctx->sh_desc_dec; + +@@ -610,11 +630,20 @@ + set_jump_tgt_here(desc, jump_cmd); + + /* load IV */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | tfm->ivsize); ++ if (strncmp(ablkcipher->base.__crt_alg->cra_name, "ctr(aes)", 8) == 0) { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize | ++ (16 << LDST_OFFSET_SHIFT)); + +- /* Choose operation */ +- append_dec_op1(desc, ctx->class1_alg_type); ++ append_operation(desc, ctx->class1_alg_type | ++ OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); ++ } else { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize); ++ ++ /* Choose operation */ ++ append_dec_op1(desc, ctx->class1_alg_type); ++ } + + /* Perform operation */ + ablkcipher_append_src_dst(desc); +@@ -636,6 +665,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return ret; + } +@@ -1153,7 +1184,7 @@ + } + + sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, +- DMA_TO_DEVICE, assoc_chained); ++ DMA_BIDIRECTIONAL, assoc_chained); + if (likely(req->src == req->dst)) { + sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, + DMA_BIDIRECTIONAL, src_chained); +@@ -1177,9 +1208,10 @@ + sec4_sg_len += dst_nents; + + sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); ++ dma_sync_single_for_device(jrdev, iv_dma, ivsize, DMA_TO_DEVICE); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + ++ edesc = kzalloc(sizeof(struct aead_edesc) + desc_bytes + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1220,6 +1252,8 @@ + sg_to_sec4_sg_last(req->dst, dst_nents, + edesc->sec4_sg + sec4_sg_index, 0); + } ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); + + return edesc; + } +@@ -1334,7 +1368,7 @@ + &dst_chained); + + sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, +- DMA_TO_DEVICE, assoc_chained); ++ DMA_BIDIRECTIONAL, assoc_chained); + if (likely(req->src == req->dst)) { + sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, + DMA_BIDIRECTIONAL, src_chained); +@@ -1367,8 +1401,10 @@ + + sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); + ++ dma_sync_single_for_device(jrdev, iv_dma, ivsize, DMA_TO_DEVICE); ++ + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + ++ edesc = kzalloc(sizeof(struct aead_edesc) + desc_bytes + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1410,6 +1446,8 @@ + sg_to_sec4_sg_last(req->dst, dst_nents, + edesc->sec4_sg + sec4_sg_index, 0); + } ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); + + return edesc; + } +@@ -1501,6 +1539,7 @@ + * If so, include it. If not, create scatterlist. + */ + iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); ++ dma_sync_single_for_device(jrdev, iv_dma, ivsize, DMA_TO_DEVICE); + if (!src_nents && iv_dma + ivsize == sg_dma_address(req->src)) + iv_contig = true; + else +@@ -1509,7 +1548,7 @@ + sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + ++ edesc = kzalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1539,8 +1578,12 @@ + + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); ++ + edesc->iv_dma = iv_dma; + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ablkcipher sec4_sg@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, +@@ -2004,6 +2047,70 @@ + }, + /* ablkcipher descriptor */ + { ++ .name = "ecb(des)", ++ .driver_name = "ecb-des-caam", ++ .blocksize = DES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = DES_KEY_SIZE, ++ .max_keysize = DES_KEY_SIZE, ++ .ivsize = DES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_ECB, ++ }, ++ { ++ .name = "ecb(arc4)", ++ .driver_name = "ecb-arc4-caam", ++ .blocksize = ARC4_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = ARC4_MIN_KEY_SIZE, ++ .max_keysize = ARC4_MAX_KEY_SIZE, ++ .ivsize = ARC4_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_ARC4 | OP_ALG_AAI_ECB ++ }, ++ { ++ .name = "ecb(aes)", ++ .driver_name = "ecb-aes-caam", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB, ++ }, ++ { ++ .name = "ctr(aes)", ++ .driver_name = "ctr-aes-caam", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, ++ }, ++ { + .name = "cbc(aes)", + .driver_name = "cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, +@@ -2020,6 +2127,22 @@ + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + }, + { ++ .name = "ecb(des3_ede)", ++ .driver_name = "ecb-des3-caam", ++ .blocksize = DES3_EDE_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = DES3_EDE_KEY_SIZE, ++ .max_keysize = DES3_EDE_KEY_SIZE, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_ECB, ++ }, ++ { + .name = "cbc(des3_ede)", + .driver_name = "cbc-3des-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, +@@ -2142,8 +2265,12 @@ + alg->cra_blocksize = template->blocksize; + alg->cra_alignmask = 0; + alg->cra_ctxsize = sizeof(struct caam_ctx); +- alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | +- template->type; ++ alg->cra_flags = CRYPTO_ALG_ASYNC | template->type; ++ ++#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY ++ alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY; ++#endif ++ + switch (template->type) { + case CRYPTO_ALG_TYPE_ABLKCIPHER: + alg->cra_type = &crypto_ablkcipher_type; +@@ -2164,14 +2291,83 @@ + + static int __init caam_algapi_init(void) + { +- int i = 0, err = 0; ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ struct device *ctrldev; ++ struct caam_drv_private *priv; ++ int i = 0, err = 0, md_limit = 0; ++ int des_inst, aes_inst, md_inst; ++ u64 cha_inst; ++ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ 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) { ++ of_node_put(dev_node); ++ return -ENODEV; ++ } ++ ++ ctrldev = &pdev->dev; ++ priv = dev_get_drvdata(ctrldev); ++ ++ /* ++ * If priv is NULL, it's probably because the caam driver wasn't ++ * properly initialized (e.g. RNG4 init failed). Thus, bail out here. ++ */ ++ if (!priv) { ++ of_node_put(dev_node); ++ return -ENODEV; ++ } + + INIT_LIST_HEAD(&alg_list); + +- /* register crypto algorithms the device supports */ ++ /* ++ * register crypto algorithms the device supports ++ * first, detect presence of DES, AES, and MD blocks. If MD present, ++ * determine limit of supported digest size ++ */ ++ cha_inst = rd_reg64(&priv->ctrl->perfmon.cha_num); ++ des_inst = (cha_inst & CHA_ID_DES_MASK) >> CHA_ID_DES_SHIFT; ++ aes_inst = (cha_inst & CHA_ID_AES_MASK) >> CHA_ID_AES_SHIFT; ++ md_inst = (cha_inst & CHA_ID_MD_MASK) >> CHA_ID_MD_SHIFT; ++ if (md_inst) { ++ md_limit = SHA512_DIGEST_SIZE; ++ if ((rd_reg64(&priv->ctrl->perfmon.cha_id) & CHA_ID_MD_MASK) ++ == CHA_ID_MD_LP256) /* LP256 limits digest size */ ++ md_limit = SHA256_DIGEST_SIZE; ++ } ++ + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { +- /* TODO: check if h/w supports alg */ + struct caam_crypto_alg *t_alg; ++ bool done = false; ++ ++authencesn: ++ /* ++ * All registrable algs in this module require a blockcipher ++ * All aead algs require message digests, so check them for ++ * instantiation and size. ++ */ ++ if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD) { ++ /* If no MD instantiated, or MD too small, skip */ ++ if ((!md_inst) || ++ (driver_algs[i].template_aead.maxauthsize > ++ md_limit)) ++ continue; ++ } ++ /* If DES alg, and CHA not instantiated, skip */ ++ if ((driver_algs[i].class1_alg_type & OP_ALG_ALGSEL_3DES) || ++ (driver_algs[i].class1_alg_type & OP_ALG_ALGSEL_DES)) ++ if (!des_inst) ++ continue; ++ /* If AES alg, and CHA not instantiated, skip */ ++ if (driver_algs[i].class1_alg_type & OP_ALG_ALGSEL_AES) ++ if (!aes_inst) ++ continue; + + t_alg = caam_alg_alloc(&driver_algs[i]); + if (IS_ERR(t_alg)) { +@@ -2186,12 +2382,36 @@ + pr_warn("%s alg registration failed\n", + t_alg->crypto_alg.cra_driver_name); + kfree(t_alg); +- } else ++ } else { + list_add_tail(&t_alg->entry, &alg_list); ++#ifdef DEBUG ++ dev_info(ctrldev, "%s\n", ++ t_alg->crypto_alg.cra_driver_name); ++#endif ++ ++ if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD && ++ !memcmp(driver_algs[i].name, "authenc", 7) && ++ !done) { ++ char *name; ++ ++ name = driver_algs[i].name; ++ memmove(name + 10, name + 7, strlen(name) - 7); ++ memcpy(name + 7, "esn", 3); ++ ++ name = driver_algs[i].driver_name; ++ memmove(name + 10, name + 7, strlen(name) - 7); ++ memcpy(name + 7, "esn", 3); ++ ++ done = true; ++ goto authencesn; ++ } ++ } + } ++ + if (!list_empty(&alg_list)) + pr_info("caam algorithms registered in /proc/crypto\n"); + ++ of_node_put(dev_node); + return err; + } + +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/caamhash.c linux-3.14.72/drivers/crypto/caam/caamhash.c +--- linux-3.14.72.orig/drivers/crypto/caam/caamhash.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/caamhash.c 2016-06-19 22:11:55.113152605 +0200 +@@ -1,7 +1,7 @@ + /* + * caam - Freescale FSL CAAM support for ahash functions of crypto API + * +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011-2015 Freescale Semiconductor, Inc. + * + * Based on caamalg.c crypto API driver. + * +@@ -62,6 +62,7 @@ + #include "error.h" + #include "sg_sw_sec4.h" + #include "key_gen.h" ++#include + + #define CAAM_CRA_PRIORITY 3000 + +@@ -115,6 +116,7 @@ + u8 key[CAAM_MAX_HASH_KEY_SIZE]; + dma_addr_t key_dma; + int ctx_len; ++ unsigned int key_len; + unsigned int split_key_len; + unsigned int split_key_pad_len; + }; +@@ -127,13 +129,22 @@ + int buflen_0; + u8 buf_1[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned; + int buflen_1; +- u8 caam_ctx[MAX_CTX_LEN]; ++ u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned; + int (*update)(struct ahash_request *req); + int (*final)(struct ahash_request *req); + int (*finup)(struct ahash_request *req); + int current_buf; + }; + ++struct caam_export_state { ++ u8 buf[CAAM_MAX_HASH_BLOCK_SIZE]; ++ u8 caam_ctx[MAX_CTX_LEN]; ++ int buflen; ++ int (*update)(struct ahash_request *req); ++ int (*final)(struct ahash_request *req); ++ int (*finup)(struct ahash_request *req); ++}; ++ + /* Common job descriptor seq in/out ptr routines */ + + /* Map state->caam_ctx, and append seq_out_ptr command that points to it */ +@@ -166,6 +177,7 @@ + dma_addr_t buf_dma; + + buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE); ++ dma_sync_single_for_device(jrdev, buf_dma, buflen, DMA_TO_DEVICE); + dma_to_sec4_sg_one(sec4_sg, buf_dma, buflen, 0); + + return buf_dma; +@@ -208,6 +220,9 @@ + u32 flag) + { + state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, ctx_len, flag); ++ if ((flag == DMA_TO_DEVICE) || (flag == DMA_BIDIRECTIONAL)) ++ dma_sync_single_for_device(jrdev, state->ctx_dma, ctx_len, ++ flag); + dma_to_sec4_sg_one(sec4_sg, state->ctx_dma, ctx_len, 0); + } + +@@ -219,6 +234,13 @@ + KEY_DEST_MDHA_SPLIT | KEY_ENC); + } + ++static inline void append_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx) ++{ ++ append_key_as_imm(desc, ctx->key, ctx->key_len, ++ ctx->key_len, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++} ++ + /* Append key if it has been set */ + static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) + { +@@ -240,6 +262,25 @@ + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + } + ++static inline void init_sh_desc_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx) ++{ ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ if (ctx->key_len) { ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ append_key_axcbc(desc, ctx); ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ } ++ ++ /* Propagate errors from shared to job descriptor */ ++ append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); ++ ++} + /* + * For ahash read data from seqin following state->caam_ctx, + * and write resulting class2 context to seqout, which may be state->caam_ctx +@@ -259,6 +300,20 @@ + LDST_SRCDST_BYTE_CONTEXT); + } + ++static inline void axcbc_append_load_str(u32 *desc, int digestsize) ++{ ++ /* Calculate remaining bytes to read */ ++ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Read remaining bytes */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 | ++ FIFOLD_TYPE_MSG | KEY_VLF); ++ ++ /* Store class1 context bytes */ ++ append_seq_store(desc, digestsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++} ++ + /* + * For ahash update, final and finup, import context, read and write to seqout + */ +@@ -281,6 +336,27 @@ + ahash_append_load_str(desc, digestsize); + } + ++/* ++ * For ahash update, final and finup, import context, read and write to seqout ++ */ ++static inline void axcbc_ctx_data_to_out(u32 *desc, u32 op, u32 state, ++ int digestsize, ++ struct caam_hash_ctx *ctx) ++{ ++ init_sh_desc_key_axcbc(desc, ctx); ++ ++ /* Import context from software */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | ctx->ctx_len); ++ ++ /* Class 1 operation */ ++ append_operation(desc, op | state | OP_ALG_ENCRYPT); ++ ++ /* ++ * Load from buf and/or src and write to req->result or state->context ++ */ ++ axcbc_append_load_str(desc, digestsize); ++} + /* For ahash firsts and digest, read and write to seqout */ + static inline void ahash_data_to_out(u32 *desc, u32 op, u32 state, + int digestsize, struct caam_hash_ctx *ctx) +@@ -296,6 +372,21 @@ + ahash_append_load_str(desc, digestsize); + } + ++/* For ahash firsts and digest, read and write to seqout */ ++static inline void axcbc_data_to_out(u32 *desc, u32 op, u32 state, ++ int digestsize, struct caam_hash_ctx *ctx) ++{ ++ init_sh_desc_key_axcbc(desc, ctx); ++ ++ /* Class 1 operation */ ++ append_operation(desc, op | state | OP_ALG_ENCRYPT); ++ ++ /* ++ * Load from buf and/or src and write to req->result or state->context ++ */ ++ axcbc_append_load_str(desc, digestsize); ++} ++ + static int ahash_set_sh_desc(struct crypto_ahash *ahash) + { + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); +@@ -353,6 +444,8 @@ + "ahash update first shdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_final shared descriptor */ + desc = ctx->sh_desc_fin; +@@ -371,6 +464,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_finup shared descriptor */ + desc = ctx->sh_desc_finup; +@@ -389,6 +484,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_finup_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_digest shared descriptor */ + desc = ctx->sh_desc_digest; +@@ -409,10 +506,130 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } + ++static int axcbc_set_sh_desc(struct crypto_ahash *ahash) ++{ ++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); ++ int digestsize = crypto_ahash_digestsize(ahash); ++ struct device *jrdev = ctx->jrdev; ++ u32 have_key = 0; ++ u32 *desc; ++ ++ /* ahash_update shared descriptor */ ++ desc = ctx->sh_desc_update; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Import context from software */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | ctx->ctx_len); ++ ++ /* Class 1 operation */ ++ append_operation(desc, ctx->alg_type | OP_ALG_AS_UPDATE | ++ OP_ALG_ENCRYPT); ++ ++ /* Load data and write to result or context */ ++ axcbc_append_load_str(desc, ctx->ctx_len); ++ ++ ctx->sh_desc_update_dma = dma_map_single(jrdev, desc, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_update_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash update shdesc@"__stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++ ++ /* ahash_update_first shared descriptor */ ++ desc = ctx->sh_desc_update_first; ++ ++ axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INIT, ++ ctx->ctx_len, ctx); ++ ++ ctx->sh_desc_update_first_dma = dma_map_single(jrdev, desc, ++ desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_update_first_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash update first shdesc@"__stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ /* ahash_final shared descriptor */ ++ desc = ctx->sh_desc_fin; ++ ++ axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type, ++ OP_ALG_AS_FINALIZE, digestsize, ctx); ++ ++ ctx->sh_desc_fin_dma = dma_map_single(jrdev, desc, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_fin_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ /* ahash_finup shared descriptor */ ++ desc = ctx->sh_desc_finup; ++ ++ axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type, ++ OP_ALG_AS_FINALIZE, digestsize, ctx); ++ ++ ctx->sh_desc_finup_dma = dma_map_single(jrdev, desc, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_finup_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash finup shdesc@"__stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_finup_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ /* ahash_digest shared descriptor */ ++ desc = ctx->sh_desc_digest; ++ ++ axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INITFINAL, ++ digestsize, ctx); ++ ++ ctx->sh_desc_digest_dma = dma_map_single(jrdev, desc, ++ desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_digest_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash digest shdesc@"__stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ return 0; ++} + static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in, + u32 keylen) + { +@@ -446,6 +663,8 @@ + kfree(desc); + return -ENOMEM; + } ++ dma_sync_single_for_device(jrdev, src_dma, *keylen, DMA_TO_DEVICE); ++ + dst_dma = dma_map_single(jrdev, (void *)key_out, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, dst_dma)) { +@@ -490,6 +709,7 @@ + *keylen = digestsize; + + dma_unmap_single(jrdev, src_dma, *keylen, DMA_TO_DEVICE); ++ dma_sync_single_for_cpu(jrdev, dst_dma, digestsize, DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dst_dma, digestsize, DMA_FROM_DEVICE); + + kfree(desc); +@@ -547,6 +767,10 @@ + dev_err(jrdev, "unable to map key i/o memory\n"); + return -ENOMEM; + } ++ ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->split_key_pad_len, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, +@@ -567,6 +791,25 @@ + return -EINVAL; + } + ++static int axcbc_setkey(struct crypto_ahash *ahash, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); ++ int ret = 0; ++ ++ ctx->key_len = keylen; ++ memcpy(ctx->key, key, keylen); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ++ ctx->key_len, 1); ++#endif ++ ++ ret = axcbc_set_sh_desc(ahash); ++ ++ return ret; ++} + /* + * ahash_edesc - s/w-extended ahash descriptor + * @dst_dma: physical mapped address of req->result +@@ -594,8 +837,11 @@ + if (edesc->src_nents) + dma_unmap_sg_chained(dev, req->src, edesc->src_nents, + DMA_TO_DEVICE, edesc->chained); +- if (edesc->dst_dma) ++ if (edesc->dst_dma) { ++ dma_sync_single_for_cpu(dev, edesc->dst_dma, dst_len, ++ DMA_FROM_DEVICE); + dma_unmap_single(dev, edesc->dst_dma, dst_len, DMA_FROM_DEVICE); ++ } + + if (edesc->sec4_sg_bytes) + dma_unmap_single(dev, edesc->sec4_sg_dma, +@@ -610,8 +856,12 @@ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + +- if (state->ctx_dma) ++ if (state->ctx_dma) { ++ if ((flag == DMA_FROM_DEVICE) || (flag == DMA_BIDIRECTIONAL)) ++ dma_sync_single_for_cpu(dev, state->ctx_dma, ++ ctx->ctx_len, flag); + dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag); ++ } + ahash_unmap(dev, edesc, req, dst_len); + } + +@@ -805,7 +1055,7 @@ + * allocate space for base edesc and hw desc commands, + * link tables + */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, +@@ -855,6 +1105,9 @@ + + append_seq_out_ptr(desc, state->ctx_dma, ctx->ctx_len, 0); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ sec4_sg_bytes, DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, +@@ -910,7 +1163,7 @@ + sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -942,6 +1195,9 @@ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -986,7 +1242,7 @@ + sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1021,6 +1277,9 @@ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -1061,7 +1320,7 @@ + sec4_sg_bytes = src_nents * sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + sec4_sg_bytes + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + sec4_sg_bytes + + DESC_JOB_IO_LEN, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1071,6 +1330,7 @@ + DESC_JOB_IO_LEN; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); ++ edesc->sec4_sg_bytes = sec4_sg_bytes; + edesc->src_nents = src_nents; + edesc->chained = chained; + +@@ -1088,6 +1348,9 @@ + } + append_seq_in_ptr(desc, src_dma, req->nbytes, options); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ edesc->sec4_sg_bytes, DMA_TO_DEVICE); ++ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + +@@ -1126,7 +1389,7 @@ + int sh_len; + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN, ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN, + GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1145,6 +1408,8 @@ + digestsize); + edesc->src_nents = 0; + ++ dma_sync_single_for_device(jrdev, state->buf_dma, buflen, ++ DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -1197,7 +1462,7 @@ + * allocate space for base edesc and hw desc commands, + * link tables + */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, +@@ -1234,6 +1499,8 @@ + + map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ sec4_sg_bytes, DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, +@@ -1296,7 +1563,7 @@ + sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1328,6 +1595,9 @@ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -1382,7 +1652,7 @@ + * allocate space for base edesc and hw desc commands, + * link tables + */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, +@@ -1422,6 +1692,8 @@ + + map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ sec4_sg_bytes, DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, +@@ -1470,6 +1742,9 @@ + state->final = ahash_final_no_ctx; + + state->current_buf = 0; ++ state->buf_dma = 0; ++ state->buflen_0 = 0; ++ state->buflen_1 = 0; + + return 0; + } +@@ -1497,25 +1772,42 @@ + + static int ahash_export(struct ahash_request *req, void *out) + { +- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); +- struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); ++ struct caam_export_state *export = out; ++ int len; ++ u8 *buf; ++ ++ if (state->current_buf) { ++ buf = state->buf_1; ++ len = state->buflen_1; ++ } else { ++ buf = state->buf_0; ++ len = state->buflen_1; ++ } ++ ++ memcpy(export->buf, buf, len); ++ memcpy(export->caam_ctx, state->caam_ctx, sizeof(export->caam_ctx)); ++ export->buflen = len; ++ export->update = state->update; ++ export->final = state->final; ++ export->finup = state->finup; + +- memcpy(out, ctx, sizeof(struct caam_hash_ctx)); +- memcpy(out + sizeof(struct caam_hash_ctx), state, +- sizeof(struct caam_hash_state)); + return 0; + } + + static int ahash_import(struct ahash_request *req, const void *in) + { +- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); +- struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); ++ const struct caam_export_state *export = in; ++ ++ memset(state, 0, sizeof(*state)); ++ memcpy(state->buf_0, export->buf, export->buflen); ++ memcpy(state->caam_ctx, export->caam_ctx, sizeof(state->caam_ctx)); ++ state->buflen_0 = export->buflen; ++ state->update = export->update; ++ state->final = export->final; ++ state->finup = export->finup; + +- memcpy(ctx, in, sizeof(struct caam_hash_ctx)); +- memcpy(state, in + sizeof(struct caam_hash_ctx), +- sizeof(struct caam_hash_state)); + return 0; + } + +@@ -1533,6 +1825,28 @@ + /* ahash descriptors */ + static struct caam_hash_template driver_hash[] = { + { ++ .name = "md5", ++ .driver_name = "md5-caam", ++ .hmac_name = "hmac(md5)", ++ .hmac_driver_name = "hmac-md5-caam", ++ .blocksize = MD5_BLOCK_WORDS * 4, ++ .template_ahash = { ++ .init = ahash_init, ++ .update = ahash_update, ++ .final = ahash_final, ++ .finup = ahash_finup, ++ .digest = ahash_digest, ++ .export = ahash_export, ++ .import = ahash_import, ++ .setkey = ahash_setkey, ++ .halg = { ++ .digestsize = MD5_DIGEST_SIZE, ++ .statesize = sizeof(struct caam_export_state), ++ }, ++ }, ++ .alg_type = OP_ALG_ALGSEL_MD5, ++ .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, ++ }, { + .name = "sha1", + .driver_name = "sha1-caam", + .hmac_name = "hmac(sha1)", +@@ -1549,8 +1863,9 @@ + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA1_DIGEST_SIZE, +- }, ++ .statesize = sizeof(struct caam_export_state), + }, ++ }, + .alg_type = OP_ALG_ALGSEL_SHA1, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, { +@@ -1570,8 +1885,9 @@ + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA224_DIGEST_SIZE, +- }, ++ .statesize = sizeof(struct caam_export_state), + }, ++ }, + .alg_type = OP_ALG_ALGSEL_SHA224, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, { +@@ -1591,8 +1907,9 @@ + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA256_DIGEST_SIZE, +- }, ++ .statesize = sizeof(struct caam_export_state), + }, ++ }, + .alg_type = OP_ALG_ALGSEL_SHA256, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, { +@@ -1612,8 +1929,9 @@ + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA384_DIGEST_SIZE, +- }, ++ .statesize = sizeof(struct caam_export_state), + }, ++ }, + .alg_type = OP_ALG_ALGSEL_SHA384, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, { +@@ -1633,16 +1951,17 @@ + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA512_DIGEST_SIZE, +- }, ++ .statesize = sizeof(struct caam_export_state), + }, ++ }, + .alg_type = OP_ALG_ALGSEL_SHA512, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, { +- .name = "md5", +- .driver_name = "md5-caam", +- .hmac_name = "hmac(md5)", +- .hmac_driver_name = "hmac-md5-caam", +- .blocksize = MD5_BLOCK_WORDS * 4, ++ .name = "xcbc(aes)", ++ .driver_name = "xcbc-aes-caam", ++ .hmac_name = "xcbc(aes)", ++ .hmac_driver_name = "xcbc-aes-caam", ++ .blocksize = XCBC_MAC_BLOCK_WORDS * 4, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, +@@ -1651,13 +1970,14 @@ + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, +- .setkey = ahash_setkey, ++ .setkey = axcbc_setkey, + .halg = { +- .digestsize = MD5_DIGEST_SIZE, +- }, ++ .digestsize = XCBC_MAC_DIGEST_SIZE, ++ .statesize = sizeof(struct caam_export_state), + }, +- .alg_type = OP_ALG_ALGSEL_MD5, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, ++ }, ++ .alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC, ++ .alg_op = OP_ALG_ALGSEL_AES, + }, + }; + +@@ -1712,6 +2032,41 @@ + return ret; + } + ++static int caam_axcbc_cra_init(struct crypto_tfm *tfm) ++{ ++ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); ++ struct crypto_alg *base = tfm->__crt_alg; ++ struct hash_alg_common *halg = ++ container_of(base, struct hash_alg_common, base); ++ struct ahash_alg *alg = ++ container_of(halg, struct ahash_alg, halg); ++ struct caam_hash_alg *caam_hash = ++ container_of(alg, struct caam_hash_alg, ahash_alg); ++ struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); ++ int ret = 0; ++ ++ /* ++ * Get a Job ring from Job Ring driver to ensure in-order ++ * crypto request processing per tfm ++ */ ++ ctx->jrdev = caam_jr_alloc(); ++ if (IS_ERR(ctx->jrdev)) { ++ pr_err("Job Ring Device allocation for transform failed\n"); ++ return PTR_ERR(ctx->jrdev); ++ } ++ ++ /* copy descriptor header template value */ ++ ctx->alg_type = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; ++ ctx->alg_op = OP_TYPE_CLASS1_ALG | caam_hash->alg_op; ++ ++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), ++ sizeof(struct caam_hash_state)); ++ ++ ret = axcbc_set_sh_desc(ahash); ++ ++ return ret; ++} ++ + static void caam_hash_cra_exit(struct crypto_tfm *tfm) + { + struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); +@@ -1787,7 +2142,11 @@ + template->driver_name); + } + alg->cra_module = THIS_MODULE; +- alg->cra_init = caam_hash_cra_init; ++ ++ if (strstr(alg->cra_name, "xcbc") > 0) ++ alg->cra_init = caam_axcbc_cra_init; ++ else ++ alg->cra_init = caam_hash_cra_init; + alg->cra_exit = caam_hash_cra_exit; + alg->cra_ctxsize = sizeof(struct caam_hash_ctx); + alg->cra_priority = CAAM_CRA_PRIORITY; +@@ -1804,15 +2163,56 @@ + + static int __init caam_algapi_hash_init(void) + { +- int i = 0, err = 0; ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ struct device *ctrldev; ++ struct caam_drv_private *priv; ++ int i = 0, err = 0, md_limit = 0, md_inst; ++ u64 cha_inst; ++ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); ++ if (!dev_node) ++ return -ENODEV; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ of_node_put(dev_node); ++ if (!pdev) ++ return -ENODEV; ++ ++ ctrldev = &pdev->dev; ++ priv = dev_get_drvdata(ctrldev); ++ ++ /* ++ * If priv is NULL, it's probably because the caam driver wasn't ++ * properly initialized (e.g. RNG4 init failed). Thus, bail out here. ++ */ ++ if (!priv) ++ return -ENODEV; + + INIT_LIST_HEAD(&hash_list); + +- /* register crypto algorithms the device supports */ ++ /* register algorithms the device supports */ ++ cha_inst = rd_reg64(&priv->ctrl->perfmon.cha_num); ++ md_inst = (cha_inst & CHA_ID_MD_MASK) >> CHA_ID_MD_SHIFT; ++ if (md_inst) { ++ md_limit = SHA512_DIGEST_SIZE; ++ if ((rd_reg64(&priv->ctrl->perfmon.cha_id) & CHA_ID_MD_MASK) ++ == CHA_ID_MD_LP256) /* LP256 limits digest size */ ++ md_limit = SHA256_DIGEST_SIZE; ++ } ++ + for (i = 0; i < ARRAY_SIZE(driver_hash); i++) { +- /* TODO: check if h/w supports alg */ + struct caam_hash_alg *t_alg; + ++ /* If no MD instantiated, or MD too small, skip */ ++ if ((!md_inst) || ++ (driver_hash[i].template_ahash.halg.digestsize > ++ md_limit)) ++ continue; ++ + /* register hmac version */ + t_alg = caam_hash_alloc(&driver_hash[i], true); + if (IS_ERR(t_alg)) { +@@ -1824,8 +2224,9 @@ + + err = crypto_register_ahash(&t_alg->ahash_alg); + if (err) { +- pr_warn("%s alg registration failed\n", +- t_alg->ahash_alg.halg.base.cra_driver_name); ++ pr_warn("%s alg registration failed: %d\n", ++ t_alg->ahash_alg.halg.base.cra_driver_name, ++ err); + kfree(t_alg); + } else + list_add_tail(&t_alg->entry, &hash_list); +@@ -1841,8 +2242,9 @@ + + err = crypto_register_ahash(&t_alg->ahash_alg); + if (err) { +- pr_warn("%s alg registration failed\n", +- t_alg->ahash_alg.halg.base.cra_driver_name); ++ pr_warn("%s alg registration failed: %d\n", ++ t_alg->ahash_alg.halg.base.cra_driver_name, ++ err); + kfree(t_alg); + } else + list_add_tail(&t_alg->entry, &hash_list); +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/caamrng.c linux-3.14.72/drivers/crypto/caam/caamrng.c +--- linux-3.14.72.orig/drivers/crypto/caam/caamrng.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/caamrng.c 2016-06-19 22:11:55.113152605 +0200 +@@ -1,7 +1,7 @@ + /* + * caam - Freescale FSL CAAM support for hw_random + * +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. + * + * Based on caamalg.c crypto API driver. + * +@@ -76,13 +76,16 @@ + struct buf_data bufs[2]; + }; + +-static struct caam_rng_ctx rng_ctx; ++static struct caam_rng_ctx *rng_ctx; + + static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd) + { +- if (bd->addr) ++ if (bd->addr) { ++ dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, ++ DMA_FROM_DEVICE); + dma_unmap_single(jrdev, bd->addr, RN_BUF_SIZE, + DMA_FROM_DEVICE); ++ } + } + + static inline void rng_unmap_ctx(struct caam_rng_ctx *ctx) +@@ -111,6 +114,10 @@ + + atomic_set(&bd->empty, BUF_NOT_EMPTY); + complete(&bd->filled); ++ ++ /* Buffer refilled, invalidate cache */ ++ dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "rng refreshed buf@: ", + DUMP_PREFIX_ADDRESS, 16, 4, bd->buf, RN_BUF_SIZE, 1); +@@ -137,7 +144,7 @@ + + static int caam_read(struct hwrng *rng, void *data, size_t max, bool wait) + { +- struct caam_rng_ctx *ctx = &rng_ctx; ++ struct caam_rng_ctx *ctx = rng_ctx; + struct buf_data *bd = &ctx->bufs[ctx->current_buf]; + int next_buf_idx, copied_idx; + int err; +@@ -206,6 +213,9 @@ + + ctx->sh_desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), + DMA_TO_DEVICE); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dma, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4, + desc, desc_bytes(desc), 1); +@@ -237,14 +247,57 @@ + struct buf_data *bd; + + for (i = 0; i < 2; i++) { +- bd = &rng_ctx.bufs[i]; ++ bd = &rng_ctx->bufs[i]; + if (atomic_read(&bd->empty) == BUF_PENDING) + wait_for_completion(&bd->filled); + } + +- rng_unmap_ctx(&rng_ctx); ++ rng_unmap_ctx(rng_ctx); ++} ++ ++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST ++static inline void test_len(struct hwrng *rng, size_t len, bool wait) ++{ ++ u8 *buf; ++ int real_len; ++ ++ buf = kzalloc(sizeof(u8) * len, GFP_KERNEL); ++ real_len = rng->read(rng, buf, len, wait); ++ if (real_len == 0 && wait) ++ pr_err("WAITING FAILED\n"); ++ pr_info("wanted %d bytes, got %d\n", len, real_len); ++ print_hex_dump(KERN_INFO, "random bytes@: ", DUMP_PREFIX_ADDRESS, ++ 16, 4, buf, real_len, 1); ++ kfree(buf); ++} ++ ++static inline void test_mode_once(struct hwrng *rng, bool wait) ++{ ++#define TEST_CHUNK (RN_BUF_SIZE / 4) ++ ++ test_len(rng, TEST_CHUNK, wait); ++ test_len(rng, RN_BUF_SIZE * 2, wait); ++ test_len(rng, RN_BUF_SIZE * 2 - TEST_CHUNK, wait); + } + ++static inline void test_mode(struct hwrng *rng, bool wait) ++{ ++#define TEST_PASS 1 ++ int i; ++ ++ for (i = 0; i < TEST_PASS; i++) ++ test_mode_once(rng, wait); ++} ++ ++static void self_test(struct hwrng *rng) ++{ ++ pr_info("testing without waiting\n"); ++ test_mode(rng, false); ++ pr_info("testing with waiting\n"); ++ test_mode(rng, true); ++} ++#endif ++ + static void caam_init_buf(struct caam_rng_ctx *ctx, int buf_id) + { + struct buf_data *bd = &ctx->bufs[buf_id]; +@@ -273,13 +326,14 @@ + + static void __exit caam_rng_exit(void) + { +- caam_jr_free(rng_ctx.jrdev); ++ caam_jr_free(rng_ctx->jrdev); + hwrng_unregister(&caam_rng); + } + + static int __init caam_rng_init(void) + { + struct device *dev; ++ rng_ctx = kmalloc(sizeof(struct caam_rng_ctx), GFP_KERNEL | GFP_DMA); + + dev = caam_jr_alloc(); + if (IS_ERR(dev)) { +@@ -287,7 +341,11 @@ + return PTR_ERR(dev); + } + +- caam_init_rng(&rng_ctx, dev); ++ caam_init_rng(rng_ctx, dev); ++ ++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST ++ self_test(&caam_rng); ++#endif + + dev_info(dev, "registering rng-caam\n"); + return hwrng_register(&caam_rng); +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/compat.h linux-3.14.72/drivers/crypto/caam/compat.h +--- linux-3.14.72.orig/drivers/crypto/caam/compat.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/compat.h 2016-06-19 22:11:55.113152605 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright 2008-2015 Freescale Semiconductor, Inc. + */ + + #ifndef CAAM_COMPAT_H +@@ -23,6 +23,10 @@ + #include + #include + #include ++ ++#ifdef CONFIG_ARM /* needs the clock control subsystem */ ++#include ++#endif + #include + + #include +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/ctrl.c linux-3.14.72/drivers/crypto/caam/ctrl.c +--- linux-3.14.72.orig/drivers/crypto/caam/ctrl.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/ctrl.c 2016-06-19 22:11:55.113152605 +0200 +@@ -2,7 +2,7 @@ + * CAAM control-plane driver backend + * Controller-level driver, kernel property detection, initialization + * +- * Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright 2008-2015 Freescale Semiconductor, Inc. + */ + + #include +@@ -15,6 +15,7 @@ + #include "desc_constr.h" + #include "error.h" + #include "ctrl.h" ++#include "sm.h" + + /* + * Descriptor to instantiate RNG State Handle 0 in normal mode and +@@ -296,6 +297,14 @@ + /* Unmap controller region */ + iounmap(&topregs->ctrl); + ++#ifdef CONFIG_ARM ++ /* shut clocks off before finalizing shutdown */ ++ clk_disable(ctrlpriv->caam_ipg); ++ clk_disable(ctrlpriv->caam_mem); ++ clk_disable(ctrlpriv->caam_aclk); ++ clk_disable(ctrlpriv->caam_emi_slow); ++#endif ++ + kfree(ctrlpriv->jrpdev); + kfree(ctrlpriv); + +@@ -344,8 +353,8 @@ + wr_reg32(&r4tst->rtsdctl, val); + /* min. freq. count, equal to 1/4 of the entropy sample length */ + wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2); +- /* max. freq. count, equal to 8 times the entropy sample length */ +- wr_reg32(&r4tst->rtfrqmax, ent_delay << 3); ++ /* max. freq. count, equal to 16 times the entropy sample length */ ++ wr_reg32(&r4tst->rtfrqmax, ent_delay << 4); + /* put RNG4 into run mode */ + clrbits32(&r4tst->rtmctl, RTMCTL_PRGM); + } +@@ -356,9 +365,9 @@ + * Returns the ERA number (1..4) or -ENOTSUPP if the ERA is unknown. + * @caam_id - the value of the SEC_VID register + **/ +-int caam_get_era(u64 caam_id) ++int caam_get_era(u32 caam_id) + { +- struct sec_vid *sec_vid = (struct sec_vid *)&caam_id; ++ struct sec_vid sec_vid; + static const struct { + u16 ip_id; + u8 maj_rev; +@@ -368,16 +377,38 @@ + {0x0A10, 2, 2}, + {0x0A12, 1, 3}, + {0x0A14, 1, 3}, ++ {0x0A10, 3, 4}, ++ {0x0A11, 1, 4}, + {0x0A14, 2, 4}, + {0x0A16, 1, 4}, +- {0x0A11, 1, 4} ++ {0x0A18, 1, 4}, ++ {0x0A11, 2, 5}, ++ {0x0A12, 2, 5}, ++ {0x0A13, 1, 5}, ++ {0x0A1C, 1, 5}, ++ {0x0A12, 4, 6}, ++ {0x0A13, 2, 6}, ++ {0x0A16, 2, 6}, ++ {0x0A17, 1, 6}, ++ {0x0A18, 2, 6}, ++ {0x0A1A, 1, 6}, ++ {0x0A1C, 2, 6}, ++ {0x0A14, 3, 7}, ++ {0x0A10, 4, 8}, ++ {0x0A11, 3, 8}, ++ {0x0A11, 4, 8}, ++ {0x0A12, 5, 8}, ++ {0x0A16, 3, 8}, + }; + int i; + ++ sec_vid.ip_id = caam_id >> SEC_VID_IPID_SHIFT; ++ sec_vid.maj_rev = (caam_id & SEC_VID_MAJ_MASK) >> SEC_VID_MAJ_SHIFT; ++ + for (i = 0; i < ARRAY_SIZE(caam_eras); i++) +- if (caam_eras[i].ip_id == sec_vid->ip_id && +- caam_eras[i].maj_rev == sec_vid->maj_rev) +- return caam_eras[i].era; ++ if (caam_eras[i].ip_id == sec_vid.ip_id && ++ caam_eras[i].maj_rev == sec_vid.maj_rev) ++ return caam_eras[i].era; + + return -ENOTSUPP; + } +@@ -387,7 +418,7 @@ + static int caam_probe(struct platform_device *pdev) + { + int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; +- u64 caam_id; ++ u32 caam_id; + struct device *dev; + struct device_node *nprop, *np; + struct caam_ctrl __iomem *ctrl; +@@ -419,8 +450,92 @@ + /* topregs used to derive pointers to CAAM sub-blocks only */ + topregs = (struct caam_full __iomem *)ctrl; + +- /* Get the IRQ of the controller (for security violations only) */ +- ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0); ++ /* Get CAAM-SM node and of_iomap() and save */ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm"); ++ ++ if (!np) ++ return -ENODEV; ++ ++ ctrlpriv->sm_base = of_iomap(np, 0); ++ ctrlpriv->sm_size = 0x3fff; ++ ++/* ++ * ARM targets tend to have clock control subsystems that can ++ * enable/disable clocking to our device. Turn clocking on to proceed ++ */ ++#ifdef CONFIG_ARM ++ ctrlpriv->caam_ipg = devm_clk_get(&ctrlpriv->pdev->dev, "caam_ipg"); ++ if (IS_ERR(ctrlpriv->caam_ipg)) { ++ ret = PTR_ERR(ctrlpriv->caam_ipg); ++ dev_err(&ctrlpriv->pdev->dev, ++ "can't identify CAAM ipg clk: %d\n", ret); ++ return -ENODEV; ++ } ++ ctrlpriv->caam_mem = devm_clk_get(&ctrlpriv->pdev->dev, "caam_mem"); ++ if (IS_ERR(ctrlpriv->caam_mem)) { ++ ret = PTR_ERR(ctrlpriv->caam_mem); ++ dev_err(&ctrlpriv->pdev->dev, ++ "can't identify CAAM secure mem clk: %d\n", ret); ++ return -ENODEV; ++ } ++ ctrlpriv->caam_aclk = devm_clk_get(&ctrlpriv->pdev->dev, "caam_aclk"); ++ if (IS_ERR(ctrlpriv->caam_aclk)) { ++ ret = PTR_ERR(ctrlpriv->caam_aclk); ++ dev_err(&ctrlpriv->pdev->dev, ++ "can't identify CAAM aclk clk: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ ctrlpriv->caam_emi_slow = devm_clk_get(&ctrlpriv->pdev->dev, ++ "caam_emi_slow"); ++ ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't prepare CAAM emi" ++ " slow clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ ret = clk_prepare(ctrlpriv->caam_ipg); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't prepare CAAM ipg clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ret = clk_prepare(ctrlpriv->caam_mem); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't prepare CAAM secure mem clock: %d\n", ++ ret); ++ return -ENODEV; ++ } ++ ret = clk_prepare(ctrlpriv->caam_aclk); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't prepare CAAM aclk clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ ret = clk_enable(ctrlpriv->caam_ipg); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't enable CAAM ipg clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ret = clk_enable(ctrlpriv->caam_mem); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n", ++ ret); ++ return -ENODEV; ++ } ++ ret = clk_enable(ctrlpriv->caam_aclk); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't enable CAAM aclk clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ pr_debug("%s caam_ipg clock:%d\n", __func__, ++ (int)clk_get_rate(ctrlpriv->caam_ipg)); ++ pr_debug("%s caam_mem clock:%d\n", __func__, ++ (int)clk_get_rate(ctrlpriv->caam_mem)); ++ pr_debug("%s caam_aclk clock:%d\n", __func__, ++ (int)clk_get_rate(ctrlpriv->caam_aclk)); ++#endif + + /* + * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, +@@ -429,6 +544,22 @@ + setbits32(&topregs->ctrl.mcr, MCFGR_WDENABLE | + (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); + ++#ifdef CONFIG_ARCH_MX6 ++ /* ++ * ERRATA: mx6 devices have an issue wherein AXI bus transactions ++ * may not occur in the correct order. This isn't a problem running ++ * single descriptors, but can be if running multiple concurrent ++ * descriptors. Reworking the driver to throttle to single requests ++ * is impractical, thus the workaround is to limit the AXI pipeline ++ * to a depth of 1 (from it's default of 4) to preclude this situation ++ * from occurring. ++ */ ++ wr_reg32(&topregs->ctrl.mcr, ++ (rd_reg32(&topregs->ctrl.mcr) & ~(MCFGR_AXIPIPE_MASK)) | ++ ((1 << MCFGR_AXIPIPE_SHIFT) & MCFGR_AXIPIPE_MASK)); ++#endif ++ ++ /* Set DMA masks according to platform ranging */ + if (sizeof(dma_addr_t) == sizeof(u64)) + if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) + dma_set_mask(dev, DMA_BIT_MASK(40)); +@@ -560,10 +691,10 @@ + + /* NOTE: RTIC detection ought to go here, around Si time */ + +- caam_id = rd_reg64(&topregs->ctrl.perfmon.caam_id); ++ caam_id = rd_reg32(&topregs->ctrl.perfmon.caam_id); + + /* Report "alive" for developer to see */ +- dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, ++ dev_info(dev, "device ID = 0x%08x (Era %d)\n", caam_id, + caam_get_era(caam_id)); + dev_info(dev, "job rings = %d, qi = %d\n", + ctrlpriv->total_jobrs, ctrlpriv->qi_present); +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/ctrl.h linux-3.14.72/drivers/crypto/caam/ctrl.h +--- linux-3.14.72.orig/drivers/crypto/caam/ctrl.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/ctrl.h 2016-06-19 22:11:55.117152342 +0200 +@@ -1,13 +1,13 @@ + /* + * CAAM control-plane driver backend public-level include definitions + * +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright (C) 2015 Freescale Semiconductor, Inc. + */ + + #ifndef CTRL_H + #define CTRL_H + + /* Prototypes for backend-level services exposed to APIs */ +-int caam_get_era(u64 caam_id); ++int caam_get_era(u32 caam_id); + + #endif /* CTRL_H */ +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/desc.h linux-3.14.72/drivers/crypto/caam/desc.h +--- linux-3.14.72.orig/drivers/crypto/caam/desc.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/desc.h 2016-06-19 22:11:55.117152342 +0200 +@@ -2,19 +2,35 @@ + * CAAM descriptor composition header + * Definitions to support CAAM descriptor instruction generation + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc. + */ + + #ifndef DESC_H + #define DESC_H + ++/* ++ * 16-byte hardware scatter/gather table ++ * An 8-byte table exists in the hardware spec, but has never been ++ * implemented to date. The 8/16 option is selected at RTL-compile-time. ++ * and this selection is visible in the Compile Time Parameters Register ++ */ ++ ++#define SEC4_SG_LEN_EXT 0x80000000 /* Entry points to table */ ++#define SEC4_SG_LEN_FIN 0x40000000 /* Last ent in table */ ++#define SEC4_SG_BPID_MASK 0x000000ff ++#define SEC4_SG_BPID_SHIFT 16 ++#define SEC4_SG_LEN_MASK 0x3fffffff /* Excludes EXT and FINAL */ ++#define SEC4_SG_OFFS_MASK 0x00001fff ++ + struct sec4_sg_entry { ++#ifdef CONFIG_64BIT + u64 ptr; +-#define SEC4_SG_LEN_FIN 0x40000000 +-#define SEC4_SG_LEN_EXT 0x80000000 ++#else ++ u32 reserved; ++ u32 ptr; ++#endif + u32 len; +- u8 reserved; +- u8 buf_pool_id; ++ u16 buf_pool_id; + u16 offset; + }; + +@@ -391,7 +407,10 @@ + #define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT) +-#define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT) ++#define FIFOST_TYPE_AF_SBOX_CCM_JKEK (0x10 << FIFOST_TYPE_SHIFT) ++#define FIFOST_TYPE_AF_SBOX_CCM_TKEK (0x11 << FIFOST_TYPE_SHIFT) ++#define FIFOST_TYPE_KEY_CCM_JKEK (0x14 << FIFOST_TYPE_SHIFT) ++#define FIFOST_TYPE_KEY_CCM_TKEK (0x15 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_E_TKEK (0x23 << FIFOST_TYPE_SHIFT) +@@ -1093,6 +1112,23 @@ + #define OP_PCL_PKPROT_ECC 0x0002 + #define OP_PCL_PKPROT_F2M 0x0001 + ++/* Blob protocol protinfo bits */ ++#define OP_PCL_BLOB_TK 0x0200 ++#define OP_PCL_BLOB_EKT 0x0100 ++ ++#define OP_PCL_BLOB_K2KR_MEM 0x0000 ++#define OP_PCL_BLOB_K2KR_C1KR 0x0010 ++#define OP_PCL_BLOB_K2KR_C2KR 0x0030 ++#define OP_PCL_BLOB_K2KR_AFHAS 0x0050 ++#define OP_PCL_BLOB_K2KR_C2KR_SPLIT 0x0070 ++ ++#define OP_PCL_BLOB_PTXT_SECMEM 0x0008 ++#define OP_PCL_BLOB_BLACK 0x0004 ++ ++#define OP_PCL_BLOB_FMT_NORMAL 0x0000 ++#define OP_PCL_BLOB_FMT_MSTR 0x0002 ++#define OP_PCL_BLOB_FMT_TEST 0x0003 ++ + /* For non-protocol/alg-only op commands */ + #define OP_ALG_TYPE_SHIFT 24 + #define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT) +@@ -1619,4 +1655,12 @@ + /* Frame Descriptor Command for Replacement Job Descriptor */ + #define FD_CMD_REPLACE_JOB_DESC 0x20000000 + ++#define ARC4_BLOCK_SIZE 1 ++#define ARC4_MAX_KEY_SIZE 256 ++#define ARC4_MIN_KEY_SIZE 1 ++ ++#define XCBC_MAC_DIGEST_SIZE 16 ++#define XCBC_MAC_BLOCK_WORDS 16 ++ ++ + #endif /* DESC_H */ +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/intern.h linux-3.14.72/drivers/crypto/caam/intern.h +--- linux-3.14.72.orig/drivers/crypto/caam/intern.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/intern.h 2016-06-19 22:11:55.117152342 +0200 +@@ -2,7 +2,7 @@ + * CAAM/SEC 4.x driver backend + * Private/internal definitions between modules + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright 2008-2015 Freescale Semiconductor, Inc. + * + */ + +@@ -66,6 +66,7 @@ + struct caam_drv_private { + + struct device *dev; ++ struct device *smdev; + struct platform_device **jrpdev; /* Alloc'ed array per sub-device */ + struct platform_device *pdev; + +@@ -74,6 +75,8 @@ + struct caam_deco **deco; /* DECO/CCB views */ + struct caam_assurance *ac; + struct caam_queue_if *qi; /* QI control region */ ++ dma_addr_t __iomem *sm_base; /* Secure memory storage base */ ++ u32 sm_size; + + /* + * Detected geometry block. Filled in from device tree if powerpc, +@@ -81,7 +84,6 @@ + */ + u8 total_jobrs; /* Total Job Rings in device */ + u8 qi_present; /* Nonzero if QI present in device */ +- int secvio_irq; /* Security violation interrupt number */ + + #define RNG4_MAX_HANDLES 2 + /* RNG4 block */ +@@ -89,6 +91,13 @@ + Handles of the RNG4 block are initialized + by this driver */ + ++#ifdef CONFIG_ARM ++ struct clk *caam_ipg; ++ struct clk *caam_mem; ++ struct clk *caam_aclk; ++ struct clk *caam_emi_slow; ++#endif ++ + /* + * debugfs entries for developer view into driver/device + * variables at runtime. +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/jr.c linux-3.14.72/drivers/crypto/caam/jr.c +--- linux-3.14.72.orig/drivers/crypto/caam/jr.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/jr.c 2016-06-19 22:11:55.117152342 +0200 +@@ -2,7 +2,7 @@ + * CAAM/SEC 4.x transport/backend driver + * JobR backend functionality + * +- * Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright 2008-2015 Freescale Semiconductor, Inc. + */ + + #include +@@ -168,6 +168,9 @@ + void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); + u32 *userdesc, userstatus; + void *userarg; ++ dma_addr_t outbusaddr; ++ ++ outbusaddr = rd_reg64(&jrp->rregs->outring_base); + + while (rd_reg32(&jrp->rregs->outring_used)) { + +@@ -177,6 +180,9 @@ + + sw_idx = tail = jrp->tail; + hw_idx = jrp->out_ring_read_index; ++ dma_sync_single_for_cpu(dev, outbusaddr, ++ sizeof(struct jr_outentry) * JOBR_DEPTH, ++ DMA_FROM_DEVICE); + + for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) { + sw_idx = (tail + i) & (JOBR_DEPTH - 1); +@@ -204,6 +210,8 @@ + userdesc = jrp->entinfo[sw_idx].desc_addr_virt; + userstatus = jrp->outring[hw_idx].jrstatus; + ++ smp_mb(); ++ + /* set done */ + wr_reg32(&jrp->rregs->outring_rmvd, 1); + +@@ -292,8 +300,7 @@ + * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK, + * -EBUSY if the queue is full, -EIO if it cannot map the caller's + * descriptor. +- * @dev: device of the job ring to be used. This device should have +- * been assigned prior by caam_jr_register(). ++ * @dev: device of the job ring to be used. + * @desc: points to a job descriptor that execute our request. All + * descriptors (and all referenced data) must be in a DMAable + * region, and all data references must be physical addresses +@@ -324,7 +331,7 @@ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + struct caam_jrentry_info *head_entry; + int head, tail, desc_size; +- dma_addr_t desc_dma; ++ dma_addr_t desc_dma, inpbusaddr; + + desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32); + desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE); +@@ -333,6 +340,13 @@ + return -EIO; + } + ++ dma_sync_single_for_device(dev, desc_dma, desc_size, DMA_TO_DEVICE); ++ ++ inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); ++ dma_sync_single_for_device(dev, inpbusaddr, ++ sizeof(dma_addr_t) * JOBR_DEPTH, ++ DMA_TO_DEVICE); ++ + spin_lock_bh(&jrp->inplock); + + head = jrp->head; +@@ -354,12 +368,18 @@ + + jrp->inpring[jrp->inp_ring_write_index] = desc_dma; + ++ dma_sync_single_for_device(dev, inpbusaddr, ++ sizeof(dma_addr_t) * JOBR_DEPTH, ++ DMA_TO_DEVICE); ++ + smp_wmb(); + + jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) & + (JOBR_DEPTH - 1); + jrp->head = (head + 1) & (JOBR_DEPTH - 1); + ++ wmb(); ++ + wr_reg32(&jrp->rregs->inpring_jobadd, 1); + + spin_unlock_bh(&jrp->inplock); +@@ -484,6 +504,10 @@ + + /* Identify the interrupt */ + jrpriv->irq = irq_of_parse_and_map(nprop, 0); ++ if (jrpriv->irq <= 0) { ++ kfree(jrpriv); ++ return -EINVAL; ++ } + + /* Now do the platform independent part */ + error = caam_jr_init(jrdev); /* now turn on hardware */ +@@ -497,9 +521,39 @@ + + atomic_set(&jrpriv->tfm_count, 0); + ++ device_init_wakeup(&pdev->dev, 1); ++ device_set_wakeup_enable(&pdev->dev, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int caam_jr_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev); ++ ++ if (device_may_wakeup(&pdev->dev)) ++ enable_irq_wake(jrpriv->irq); ++ ++ return 0; ++} ++ ++static int caam_jr_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev); ++ ++ if (device_may_wakeup(&pdev->dev)) ++ disable_irq_wake(jrpriv->irq); ++ + return 0; + } + ++static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, ++ caam_jr_resume); ++#endif ++ + static struct of_device_id caam_jr_match[] = { + { + .compatible = "fsl,sec-v4.0-job-ring", +@@ -516,6 +570,9 @@ + .name = "caam_jr", + .owner = THIS_MODULE, + .of_match_table = caam_jr_match, ++#ifdef CONFIG_PM ++ .pm = &caam_jr_pm_ops, ++#endif + }, + .probe = caam_jr_probe, + .remove = caam_jr_remove, +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/Kconfig linux-3.14.72/drivers/crypto/caam/Kconfig +--- linux-3.14.72.orig/drivers/crypto/caam/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/Kconfig 2016-06-19 22:11:55.117152342 +0200 +@@ -1,6 +1,6 @@ + config CRYPTO_DEV_FSL_CAAM + tristate "Freescale CAAM-Multicore driver backend" +- depends on FSL_SOC ++ depends on FSL_SOC || ARCH_MXC + help + Enables the driver module for Freescale's Cryptographic Accelerator + and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). +@@ -112,6 +112,56 @@ + To compile this as a module, choose M here: the module + will be called caamrng. + ++config CRYPTO_DEV_FSL_CAAM_RNG_TEST ++ boolean "Test caam rng" ++ depends on CRYPTO_DEV_FSL_CAAM_RNG_API ++ default n ++ help ++ Selecting this will enable a self-test to run for the ++ caam RNG. This test is several minutes long and executes ++ just before the RNG is registered with the hw_random API. ++ ++config CRYPTO_DEV_FSL_CAAM_SM ++ tristate "CAAM Secure Memory / Keystore API (EXPERIMENTAL)" ++ default n ++ help ++ Enables use of a prototype kernel-level Keystore API with CAAM ++ Secure Memory for insertion/extraction of bus-protected secrets. ++ ++config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE ++ int "Size of each keystore slot in Secure Memory" ++ depends on CRYPTO_DEV_FSL_CAAM_SM ++ range 5 9 ++ default 7 ++ help ++ Select size of allocation units to divide Secure Memory pages into ++ (the size of a "slot" as referenced inside the API code). ++ Established as powers of two. ++ Examples: ++ 5 => 32 bytes ++ 6 => 64 bytes ++ 7 => 128 bytes ++ 8 => 256 bytes ++ 9 => 512 bytes ++ ++config CRYPTO_DEV_FSL_CAAM_SM_TEST ++ tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)" ++ depends on CRYPTO_DEV_FSL_CAAM_SM ++ default n ++ help ++ Example thread to exercise the Keystore API and to verify that ++ stored and recovered secrets can be used for general purpose ++ encryption/decryption. ++ ++config CRYPTO_DEV_FSL_CAAM_SECVIO ++ tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)" ++ depends on CRYPTO_DEV_FSL_CAAM ++ default n ++ help ++ Enables installation of an interrupt handler with registrable ++ handler functions which can be specified to act on the consequences ++ of a security violation. ++ + config CRYPTO_DEV_FSL_CAAM_DEBUG + bool "Enable debug output in CAAM driver" + depends on CRYPTO_DEV_FSL_CAAM +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/key_gen.c linux-3.14.72/drivers/crypto/caam/key_gen.c +--- linux-3.14.72.orig/drivers/crypto/caam/key_gen.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/key_gen.c 2016-06-19 22:11:55.117152342 +0200 +@@ -1,7 +1,7 @@ + /* + * CAAM/SEC 4.x functions for handling key-generation jobs + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright 2008-2015 Freescale Semiconductor, Inc. + * + */ + #include "compat.h" +@@ -74,6 +74,9 @@ + } + + init_job_desc(desc, 0); ++ ++ dma_sync_single_for_device(jrdev, dma_addr_in, keylen, DMA_TO_DEVICE); ++ + append_key(desc, dma_addr_in, keylen, CLASS_2 | KEY_DEST_CLASS_REG); + + /* Sets MDHA up into an HMAC-INIT */ +@@ -114,7 +117,8 @@ + split_key_pad_len, 1); + #endif + } +- ++ dma_sync_single_for_cpu(jrdev, dma_addr_out, split_key_pad_len, ++ DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dma_addr_out, split_key_pad_len, + DMA_FROM_DEVICE); + out_unmap_in: +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/Makefile linux-3.14.72/drivers/crypto/caam/Makefile +--- linux-3.14.72.orig/drivers/crypto/caam/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/Makefile 2016-06-19 22:11:55.117152342 +0200 +@@ -10,6 +10,9 @@ + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o + + caam-objs := ctrl.o + caam_jr-objs := jr.o key_gen.o error.o +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/regs.h linux-3.14.72/drivers/crypto/caam/regs.h +--- linux-3.14.72.orig/drivers/crypto/caam/regs.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/regs.h 2016-06-19 22:11:55.117152342 +0200 +@@ -1,7 +1,7 @@ + /* + * CAAM hardware register-level view + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc. + */ + + #ifndef REGS_H +@@ -74,15 +74,21 @@ + #endif + #else + #ifdef __LITTLE_ENDIAN +-#define wr_reg32(reg, data) __raw_writel(reg, data) +-#define rd_reg32(reg) __raw_readl(reg) ++#define wr_reg32(reg, data) writel(data, reg) ++#define rd_reg32(reg) readl(reg) + #ifdef CONFIG_64BIT +-#define wr_reg64(reg, data) __raw_writeq(reg, data) +-#define rd_reg64(reg) __raw_readq(reg) ++#define wr_reg64(reg, data) writeq(data, reg) ++#define rd_reg64(reg) readq(reg) + #endif + #endif + #endif + ++#ifdef CONFIG_ARM ++/* These are common macros for Power, put here for ARMs */ ++#define setbits32(_addr, _v) writel((readl(_addr) | (_v)), (_addr)) ++#define clrbits32(_addr, _v) writel((readl(_addr) & ~(_v)), (_addr)) ++#endif ++ + #ifndef CONFIG_64BIT + static inline void wr_reg64(u64 __iomem *reg, u64 data) + { +@@ -107,52 +113,107 @@ + } __packed; + + /* +- * caam_perfmon - Performance Monitor/Secure Memory Status/ +- * CAAM Global Status/Component Version IDs +- * +- * Spans f00-fff wherever instantiated ++ * CHA version ID / instantiation bitfields ++ * Defined for use within cha_id in perfmon ++ * Note that the same shift/mask selectors can be used to pull out number ++ * of instantiated blocks within cha_num in perfmon, the locations are ++ * the same. + */ + +-/* Number of DECOs */ +-#define CHA_NUM_DECONUM_SHIFT 56 ++/* Job Ring */ ++#define CHA_ID_JR_SHIFT 60 ++#define CHA_ID_JR_MASK (0xfull << CHA_ID_JR_SHIFT) ++ ++/* DEscriptor COntroller */ ++#define CHA_ID_DECO_SHIFT 56 ++#define CHA_ID_DECO_MASK (0xfull << CHA_ID_DECO_SHIFT) ++#define CHA_NUM_DECONUM_SHIFT 56 /* legacy definition */ + #define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT) + +-/* CHA Version IDs */ +-#define CHA_ID_AES_SHIFT 0 +-#define CHA_ID_AES_MASK (0xfull << CHA_ID_AES_SHIFT) ++/* ZUC-Authentication */ ++#define CHA_ID_ZA_SHIFT 44 ++#define CHA_ID_ZA_MASK (0xfull << CHA_ID_ZA_SHIFT) ++ ++/* ZUC-Encryption */ ++#define CHA_ID_ZE_SHIFT 40 ++#define CHA_ID_ZE_MASK (0xfull << CHA_ID_ZE_SHIFT) + +-#define CHA_ID_DES_SHIFT 4 +-#define CHA_ID_DES_MASK (0xfull << CHA_ID_DES_SHIFT) ++/* SNOW f9 */ ++#define CHA_ID_SNW9_SHIFT 36 ++#define CHA_ID_SNW9_MASK (0xfull << CHA_ID_SNW9_SHIFT) + +-#define CHA_ID_ARC4_SHIFT 8 +-#define CHA_ID_ARC4_MASK (0xfull << CHA_ID_ARC4_SHIFT) ++/* CRC */ ++#define CHA_ID_CRC_SHIFT 32 ++#define CHA_ID_CRC_MASK (0xfull << CHA_ID_CRC_SHIFT) + +-#define CHA_ID_MD_SHIFT 12 +-#define CHA_ID_MD_MASK (0xfull << CHA_ID_MD_SHIFT) ++/* Public Key */ ++#define CHA_ID_PK_SHIFT 28 ++#define CHA_ID_PK_MASK (0xfull << CHA_ID_PK_SHIFT) + +-#define CHA_ID_RNG_SHIFT 16 +-#define CHA_ID_RNG_MASK (0xfull << CHA_ID_RNG_SHIFT) ++/* Kasumi */ ++#define CHA_ID_KAS_SHIFT 24 ++#define CHA_ID_KAS_MASK (0xfull << CHA_ID_KAS_SHIFT) + ++/* SNOW f8 */ + #define CHA_ID_SNW8_SHIFT 20 + #define CHA_ID_SNW8_MASK (0xfull << CHA_ID_SNW8_SHIFT) + +-#define CHA_ID_KAS_SHIFT 24 +-#define CHA_ID_KAS_MASK (0xfull << CHA_ID_KAS_SHIFT) ++/* ++ * Random Generator ++ * RNG4 = FIPS-verification-compliant, requires init kickstart for use ++ */ ++#define CHA_ID_RNG_SHIFT 16 ++#define CHA_ID_RNG_MASK (0xfull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_A (0x1ull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_B (0x2ull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_C (0x3ull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_4 (0x4ull << CHA_ID_RNG_SHIFT) + +-#define CHA_ID_PK_SHIFT 28 +-#define CHA_ID_PK_MASK (0xfull << CHA_ID_PK_SHIFT) ++/* ++ * Message Digest ++ * LP256 = Low Power (MD5/SHA1/SHA224/SHA256 + HMAC) ++ * LP512 = Low Power (LP256 + SHA384/SHA512) ++ * HP = High Power (LP512 + SMAC) ++ */ ++#define CHA_ID_MD_SHIFT 12 ++#define CHA_ID_MD_MASK (0xfull << CHA_ID_MD_SHIFT) ++#define CHA_ID_MD_LP256 (0x0ull << CHA_ID_MD_SHIFT) ++#define CHA_ID_MD_LP512 (0x1ull << CHA_ID_MD_SHIFT) ++#define CHA_ID_MD_HP (0x2ull << CHA_ID_MD_SHIFT) + +-#define CHA_ID_CRC_SHIFT 32 +-#define CHA_ID_CRC_MASK (0xfull << CHA_ID_CRC_SHIFT) ++/* ARC4 Streamcipher */ ++#define CHA_ID_ARC4_SHIFT 8 ++#define CHA_ID_ARC4_MASK (0xfull << CHA_ID_ARC4_SHIFT) ++#define CHA_ID_ARC4_LP (0x0ull << CHA_ID_ARC4_SHIFT) ++#define CHA_ID_ARC4_HP (0x1ull << CHA_ID_ARC4_SHIFT) + +-#define CHA_ID_SNW9_SHIFT 36 +-#define CHA_ID_SNW9_MASK (0xfull << CHA_ID_SNW9_SHIFT) ++/* DES Blockcipher Accelerator */ ++#define CHA_ID_DES_SHIFT 4 ++#define CHA_ID_DES_MASK (0xfull << CHA_ID_DES_SHIFT) + +-#define CHA_ID_DECO_SHIFT 56 +-#define CHA_ID_DECO_MASK (0xfull << CHA_ID_DECO_SHIFT) ++/* ++ * AES Blockcipher + Combo Mode Accelerator ++ * LP = Low Power (includes ECB/CBC/CFB128/OFB/CTR/CCM/CMAC/XCBC-MAC) ++ * HP = High Power (LP + CBCXCBC/CTRXCBC/XTS/GCM) ++ * DIFFPWR = ORed in if differential-power-analysis resistance implemented ++ */ ++#define CHA_ID_AES_SHIFT 0 ++#define CHA_ID_AES_MASK (0xfull << CHA_ID_AES_SHIFT) ++#define CHA_ID_AES_LP (0x3ull << CHA_ID_AES_SHIFT) ++#define CHA_ID_AES_HP (0x4ull << CHA_ID_AES_SHIFT) ++#define CHA_ID_AES_DIFFPWR (0x1ull << CHA_ID_AES_SHIFT) + +-#define CHA_ID_JR_SHIFT 60 +-#define CHA_ID_JR_MASK (0xfull << CHA_ID_JR_SHIFT) ++ ++/* ++ * caam_perfmon - Performance Monitor/Secure Memory Status/ ++ * CAAM Global Status/Component Version IDs ++ * ++ * Spans f00-fff wherever instantiated ++ */ ++ ++/* Number of DECOs */ ++#define CHA_NUM_DECONUM_SHIFT 56 ++#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT) + + struct sec_vid { + u16 ip_id; +@@ -160,6 +221,10 @@ + u8 min_rev; + }; + ++#define SEC_VID_IPID_SHIFT 16 ++#define SEC_VID_MAJ_SHIFT 8 ++#define SEC_VID_MAJ_MASK 0xFF00 ++ + struct caam_perfmon { + /* Performance Monitor Registers f00-f9f */ + u64 req_dequeued; /* PC_REQ_DEQ - Dequeued Requests */ +@@ -176,15 +241,21 @@ + #define CTPR_QI_SHIFT 57 + #define CTPR_QI_MASK (0x1ull << CTPR_QI_SHIFT) + u64 comp_parms; /* CTPR - Compile Parameters Register */ +- u64 rsvd1[2]; ++ ++ /* Secure Memory State Visibility */ ++ u32 rsvd1; ++ u32 smstatus; /* Secure memory status */ ++ u32 rsvd2; ++ u32 smpartown; /* Secure memory partition owner */ + + /* CAAM Global Status fc0-fdf */ + u64 faultaddr; /* FAR - Fault Address */ + u32 faultliodn; /* FALR - Fault Address LIODN */ + u32 faultdetail; /* FADR - Fault Addr Detail */ +- u32 rsvd2; ++ u32 rsvd3; + u32 status; /* CSTA - CAAM Status */ +- u64 rsvd3; ++ u32 smpart; /* Secure Memory Partition Parameters */ ++ u32 smvid; /* Secure Memory Version ID */ + + /* Component Instantiation Parameters fe0-fff */ + u32 rtic_id; /* RVID - RTIC Version ID */ +@@ -194,6 +265,62 @@ + u64 caam_id; /* CAAMVID - CAAM Version ID */ + }; + ++#define SMSTATUS_PART_SHIFT 28 ++#define SMSTATUS_PART_MASK (0xf << SMSTATUS_PART_SHIFT) ++#define SMSTATUS_PAGE_SHIFT 16 ++#define SMSTATUS_PAGE_MASK (0x7ff << SMSTATUS_PAGE_SHIFT) ++#define SMSTATUS_MID_SHIFT 8 ++#define SMSTATUS_MID_MASK (0x3f << SMSTATUS_MID_SHIFT) ++#define SMSTATUS_ACCERR_SHIFT 4 ++#define SMSTATUS_ACCERR_MASK (0xf << SMSTATUS_ACCERR_SHIFT) ++#define SMSTATUS_ACCERR_NONE 0 ++#define SMSTATUS_ACCERR_ALLOC 1 /* Page not allocated */ ++#define SMSTATUS_ACCESS_ID 2 /* Not granted by ID */ ++#define SMSTATUS_ACCESS_WRITE 3 /* Writes not allowed */ ++#define SMSTATUS_ACCESS_READ 4 /* Reads not allowed */ ++#define SMSTATUS_ACCESS_NONKEY 6 /* Non-key reads not allowed */ ++#define SMSTATUS_ACCESS_BLOB 9 /* Blob access not allowed */ ++#define SMSTATUS_ACCESS_DESCB 10 /* Descriptor Blob access spans pages */ ++#define SMSTATUS_ACCESS_NON_SM 11 /* Outside Secure Memory range */ ++#define SMSTATUS_ACCESS_XPAGE 12 /* Access crosses pages */ ++#define SMSTATUS_ACCESS_INITPG 13 /* Page still initializing */ ++#define SMSTATUS_STATE_SHIFT 0 ++#define SMSTATUS_STATE_MASK (0xf << SMSTATUS_STATE_SHIFT) ++#define SMSTATUS_STATE_RESET 0 ++#define SMSTATUS_STATE_INIT 1 ++#define SMSTATUS_STATE_NORMAL 2 ++#define SMSTATUS_STATE_FAIL 3 ++ ++/* up to 15 rings, 2 bits shifted by ring number */ ++#define SMPARTOWN_RING_SHIFT 2 ++#define SMPARTOWN_RING_MASK 3 ++#define SMPARTOWN_AVAILABLE 0 ++#define SMPARTOWN_NOEXIST 1 ++#define SMPARTOWN_UNAVAILABLE 2 ++#define SMPARTOWN_OURS 3 ++ ++/* Maximum number of pages possible */ ++#define SMPART_MAX_NUMPG_SHIFT 16 ++#define SMPART_MAX_NUMPG_MASK (0x3f << SMPART_MAX_NUMPG_SHIFT) ++ ++/* Maximum partition number */ ++#define SMPART_MAX_PNUM_SHIFT 12 ++#define SMPART_MAX_PNUM_MASK (0xf << SMPART_MAX_PNUM_SHIFT) ++ ++/* Highest possible page number */ ++#define SMPART_MAX_PG_SHIFT 0 ++#define SMPART_MAX_PG_MASK (0x3f << SMPART_MAX_PG_SHIFT) ++ ++/* Max size of a page */ ++#define SMVID_PG_SIZE_SHIFT 16 ++#define SMVID_PG_SIZE_MASK (0x7 << SMVID_PG_SIZE_SHIFT) ++ ++/* Major/Minor Version ID */ ++#define SMVID_MAJ_VERS_SHIFT 8 ++#define SMVID_MAJ_VERS (0xf << SMVID_MAJ_VERS_SHIFT) ++#define SMVID_MIN_VERS_SHIFT 0 ++#define SMVID_MIN_VERS (0xf << SMVID_MIN_VERS_SHIFT) ++ + /* LIODN programming for DMA configuration */ + #define MSTRID_LOCK_LIODN 0x80000000 + #define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */ +@@ -255,7 +382,7 @@ + }; + #define RTSDCTL_ENT_DLY_SHIFT 16 + #define RTSDCTL_ENT_DLY_MASK (0xffff << RTSDCTL_ENT_DLY_SHIFT) +-#define RTSDCTL_ENT_DLY_MIN 1200 ++#define RTSDCTL_ENT_DLY_MIN 3200 + #define RTSDCTL_ENT_DLY_MAX 12800 + u32 rtsdctl; /* seed control register */ + union { +@@ -407,7 +534,18 @@ + u32 rsvd11; + u32 jrcommand; /* JRCRx - JobR command */ + +- u32 rsvd12[932]; ++ u32 rsvd12[33]; ++ ++ /* Secure Memory Configuration - if you have it */ ++ u32 sm_cmd; /* SMCJRx - Secure memory command */ ++ u32 rsvd13; ++ u32 sm_status; /* SMCSJRx - Secure memory status */ ++ u32 rsvd14; ++ u32 sm_perm; /* SMAPJRx - Secure memory access perms */ ++ u32 sm_group2; /* SMAP2JRx - Secure memory access group 2 */ ++ u32 sm_group1; /* SMAP1JRx - Secure memory access group 1 */ ++ ++ u32 rsvd15[891]; + + /* Performance Monitor f00-fff */ + struct caam_perfmon perfmon; +@@ -530,6 +668,62 @@ + + #define JRCR_RESET 0x01 + ++/* secure memory command */ ++#define SMC_PAGE_SHIFT 16 ++#define SMC_PAGE_MASK (0xffff << SMC_PAGE_SHIFT) ++#define SMC_PART_SHIFT 8 ++#define SMC_PART_MASK (0x0f << SMC_PART_SHIFT) ++#define SMC_CMD_SHIFT 0 ++#define SMC_CMD_MASK (0x0f << SMC_CMD_SHIFT) ++ ++#define SMC_CMD_ALLOC_PAGE 0x01 /* allocate page to this partition */ ++#define SMC_CMD_DEALLOC_PAGE 0x02 /* deallocate page from partition */ ++#define SMC_CMD_DEALLOC_PART 0x03 /* deallocate partition */ ++#define SMC_CMD_PAGE_INQUIRY 0x05 /* find partition associate with page */ ++ ++/* secure memory (command) status */ ++#define SMCS_PAGE_SHIFT 16 ++#define SMCS_PAGE_MASK (0x0fff << SMCS_PAGE_SHIFT) ++#define SMCS_CMDERR_SHIFT 14 ++#define SMCS_CMDERR_MASK (3 << SMCS_CMDERR_SHIFT) ++#define SMCS_ALCERR_SHIFT 12 ++#define SMCS_ALCERR_MASK (3 << SMCS_ALCERR_SHIFT) ++#define SMCS_PGOWN_SHIFT 6 ++#define SMCS_PGWON_MASK (3 << SMCS_PGOWN_SHIFT) ++#define SMCS_PART_SHIFT 0 ++#define SMCS_PART_MASK (0xf << SMCS_PART_SHIFT) ++ ++#define SMCS_CMDERR_NONE 0 ++#define SMCS_CMDERR_INCOMP 1 /* Command not yet complete */ ++#define SMCS_CMDERR_SECFAIL 2 /* Security failure occurred */ ++#define SMCS_CMDERR_OVERFLOW 3 /* Command overflow */ ++ ++#define SMCS_ALCERR_NONE 0 ++#define SMCS_ALCERR_PSPERR 1 /* Partion marked PSP (dealloc only) */ ++#define SMCS_ALCERR_PAGEAVAIL 2 /* Page not available */ ++#define SMCS_ALCERR_PARTOWN 3 /* Partition ownership error */ ++ ++#define SMCS_PGOWN_AVAIL 0 /* Page is available */ ++#define SMCS_PGOWN_NOEXIST 1 /* Page initializing or nonexistent */ ++#define SMCS_PGOWN_NOOWN 2 /* Page owned by another processor */ ++#define SMCS_PGOWN_OWNED 3 /* Page belongs to this processor */ ++ ++/* secure memory access permissions */ ++#define SMCS_PERM_KEYMOD_SHIFT 16 ++#define SMCA_PERM_KEYMOD_MASK (0xff << SMCS_PERM_KEYMOD_SHIFT) ++#define SMCA_PERM_CSP_ZERO 0x8000 /* Zero when deallocated or released */ ++#define SMCA_PERM_PSP_LOCK 0x4000 /* Part./pages can't be deallocated */ ++#define SMCA_PERM_PERM_LOCK 0x2000 /* Lock permissions */ ++#define SMCA_PERM_GRP_LOCK 0x1000 /* Lock access groups */ ++#define SMCA_PERM_RINGID_SHIFT 10 ++#define SMCA_PERM_RINGID_MASK (3 << SMCA_PERM_RINGID_SHIFT) ++#define SMCA_PERM_G2_BLOB 0x0080 /* Group 2 blob import/export */ ++#define SMCA_PERM_G2_WRITE 0x0020 /* Group 2 write */ ++#define SMCA_PERM_G2_READ 0x0010 /* Group 2 read */ ++#define SMCA_PERM_G1_BLOB 0x0008 /* Group 1... */ ++#define SMCA_PERM_G1_WRITE 0x0002 ++#define SMCA_PERM_G1_READ 0x0001 ++ + /* + * caam_assurance - Assurance Controller View + * base + 0x6000 padded out to 0x1000 +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/secvio.c linux-3.14.72/drivers/crypto/caam/secvio.c +--- linux-3.14.72.orig/drivers/crypto/caam/secvio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/crypto/caam/secvio.c 2016-06-19 22:11:55.117152342 +0200 +@@ -0,0 +1,292 @@ ++ ++/* ++ * SNVS Security Violation Handler ++ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc., All Rights Reserved ++ */ ++ ++#include ++#include ++#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 Internal Security Violation", ++ "JTAG Alarm", ++ "Watchdog", ++ "(reserved)", ++ "External Boot", ++ "External Tamper Detect", ++}; ++ ++/* These names help describe security monitor state for the console */ ++static const u8 *snvs_ssm_state_name[] = { ++ "init", ++ "hard fail", ++ "(undef:2)", ++ "soft fail", ++ "(undef:4)", ++ "(undef:5)", ++ "(undef:6)", ++ "(undef:7)", ++ "transition", ++ "check", ++ "(undef:10)", ++ "non-secure", ++ "(undef:12)", ++ "trusted", ++ "(undef:14)", ++ "secure", ++}; ++ ++/* Top-level security violation interrupt */ ++static irqreturn_t snvs_secvio_interrupt(int irq, void *snvsdev) ++{ ++ struct device *dev = snvsdev; ++ struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev); ++ ++ /* Check the HP secvio status register */ ++ svpriv->irqcause = rd_reg32(&svpriv->svregs->hp.secvio_status) & ++ HP_SECVIOST_SECVIOMASK; ++ ++ if (!svpriv->irqcause) ++ return IRQ_NONE; ++ ++ /* Now ACK cause */ ++ setbits32(&svpriv->svregs->hp.secvio_status, svpriv->irqcause); ++ ++ /* 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 snvs_secvio_dispatch(unsigned long indev) ++{ ++ struct device *dev = (struct device *)indev; ++ struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev); ++ unsigned long flags; ++ int i; ++ ++ ++ /* Look through stored causes, call each handler if exists */ ++ for (i = 0; i < MAX_SECVIO_SOURCES; i++) ++ if (svpriv->irqcause & (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_intcfg, svpriv->irqcause); ++} ++ ++/* ++ * 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 snvs_secvio_default(struct device *dev, u32 cause, void *ext) ++{ ++ struct snvs_secvio_drv_private *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 snvs_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 snvs_secvio_drv_private *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(snvs_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 snvs_secvio_remove_handler(struct device *dev, enum secvio_cause cause) ++{ ++ unsigned long flags; ++ struct snvs_secvio_drv_private *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 = snvs_secvio_default; ++ svpriv->intsrc[cause].ext = NULL; ++ spin_unlock_irqrestore(&svpriv->svlock, flags); ++ return 0; ++} ++EXPORT_SYMBOL(snvs_secvio_remove_handler); ++ ++static int snvs_secvio_remove(struct platform_device *pdev) ++{ ++ struct device *svdev; ++ struct snvs_secvio_drv_private *svpriv; ++ int i; ++ ++ svdev = &pdev->dev; ++ svpriv = dev_get_drvdata(svdev); ++ ++ /* Set all sources to nonfatal */ ++ wr_reg32(&svpriv->svregs->hp.secvio_intcfg, 0); ++ ++ /* Remove tasklets and release interrupt */ ++ for_each_possible_cpu(i) ++ tasklet_kill(&svpriv->irqtask[i]); ++ ++ free_irq(svpriv->irq, svdev); ++ iounmap(svpriv->svregs); ++ kfree(svpriv); ++ ++ return 0; ++} ++ ++static int snvs_secvio_probe(struct platform_device *pdev) ++{ ++ struct device *svdev; ++ struct snvs_secvio_drv_private *svpriv; ++ struct device_node *np, *npirq; ++ struct snvs_full __iomem *snvsregs; ++ int i, error; ++ u32 hpstate; ++ ++ svpriv = kzalloc(sizeof(struct snvs_secvio_drv_private), GFP_KERNEL); ++ if (!svpriv) ++ return -ENOMEM; ++ ++ svdev = &pdev->dev; ++ dev_set_drvdata(svdev, svpriv); ++ svpriv->pdev = pdev; ++ np = pdev->dev.of_node; ++ ++ npirq = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-secvio"); ++ if (!npirq) { ++ dev_err(svdev, "can't identify secvio interrupt\n"); ++ kfree(svpriv); ++ return -EINVAL; ++ } ++ svpriv->irq = irq_of_parse_and_map(npirq, 0); ++ if (svpriv->irq <= 0) { ++ kfree(svpriv); ++ return -EINVAL; ++ } ++ ++ snvsregs = of_iomap(np, 0); ++ if (!snvsregs) { ++ dev_err(svdev, "register mapping failed\n"); ++ return -ENOMEM; ++ } ++ svpriv->svregs = (struct snvs_full __force *)snvsregs; ++ ++ /* Device data set up. Now init interrupt source descriptions */ ++ for (i = 0; i < MAX_SECVIO_SOURCES; i++) { ++ svpriv->intsrc[i].intname = violation_src_name[i]; ++ svpriv->intsrc[i].handler = snvs_secvio_default; ++ } ++ /* Connect main handler */ ++ for_each_possible_cpu(i) ++ tasklet_init(&svpriv->irqtask[i], snvs_secvio_dispatch, ++ (unsigned long)svdev); ++ ++ error = request_irq(svpriv->irq, snvs_secvio_interrupt, ++ IRQF_SHARED, "snvs-secvio", svdev); ++ if (error) { ++ dev_err(svdev, "can't connect secvio interrupt\n"); ++ irq_dispose_mapping(svpriv->irq); ++ svpriv->irq = 0; ++ iounmap(svpriv->svregs); ++ kfree(svpriv); ++ return -EINVAL; ++ } ++ ++ /* ++ * Configure all sources as fatal violations except LP section, ++ * source #5 (typically used as an external tamper detect), and ++ * source #3 (typically unused). Whenever the transition to ++ * secure mode has occurred, these will now be "fatal" violations ++ */ ++ wr_reg32(&svpriv->svregs->hp.secvio_intcfg, ++ HP_SECVIO_INTEN_SRC4 | HP_SECVIO_INTEN_SRC2 | ++ HP_SECVIO_INTEN_SRC1 | HP_SECVIO_INTEN_SRC0); ++ ++ hpstate = (rd_reg32(&svpriv->svregs->hp.status) & ++ HP_STATUS_SSM_ST_MASK) >> HP_STATUS_SSM_ST_SHIFT; ++ dev_info(svdev, "violation handlers armed - %s state\n", ++ snvs_ssm_state_name[hpstate]); ++ ++ return 0; ++} ++ ++static struct of_device_id snvs_secvio_match[] = { ++ { ++ .compatible = "fsl,imx6q-caam-snvs", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, snvs_secvio_match); ++ ++static struct platform_driver snvs_secvio_driver = { ++ .driver = { ++ .name = "snvs-secvio", ++ .owner = THIS_MODULE, ++ .of_match_table = snvs_secvio_match, ++ }, ++ .probe = snvs_secvio_probe, ++ .remove = snvs_secvio_remove, ++}; ++ ++module_platform_driver(snvs_secvio_driver); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("FSL SNVS Security Violation Handler"); ++MODULE_AUTHOR("Freescale Semiconductor - MCU"); ++ +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/secvio.h linux-3.14.72/drivers/crypto/caam/secvio.h +--- linux-3.14.72.orig/drivers/crypto/caam/secvio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/crypto/caam/secvio.h 2016-06-19 22:11:55.117152342 +0200 +@@ -0,0 +1,66 @@ ++ ++/* ++ * CAAM Security Violation Handler ++ * Copyright (C) 2012-2015 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 snvs_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 snvs_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 snvs_secvio_drv_private { ++ struct platform_device *pdev; ++ spinlock_t svlock ____cacheline_aligned; ++ struct tasklet_struct irqtask[NR_CPUS]; ++ struct snvs_full __iomem *svregs; /* both HP and LP domains */ ++ int irq; ++ u32 irqcause; /* stashed cause of violation interrupt */ ++ ++ /* Registered handlers for each violation */ ++ struct secvio_int_src intsrc[MAX_SECVIO_SOURCES]; ++ ++}; ++ ++#endif /* SECVIO_H */ +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/sg_sw_sec4.h linux-3.14.72/drivers/crypto/caam/sg_sw_sec4.h +--- linux-3.14.72.orig/drivers/crypto/caam/sg_sw_sec4.h 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/crypto/caam/sg_sw_sec4.h 2016-06-19 22:11:55.117152342 +0200 +@@ -1,7 +1,7 @@ + /* + * CAAM/SEC 4.x functions for using scatterlists in caam driver + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright 2008-2015 Freescale Semiconductor, Inc. + * + */ + +@@ -91,13 +91,22 @@ + { + if (unlikely(chained)) { + int i; ++ struct scatterlist *tsg = sg; ++ ++ /* We use a local copy of the sg pointer to avoid moving the ++ * head of the list pointed to by sg as we wall the list. ++ */ + for (i = 0; i < nents; i++) { +- dma_map_sg(dev, sg, 1, dir); +- sg = scatterwalk_sg_next(sg); ++ dma_map_sg(dev, tsg, 1, dir); ++ tsg = scatterwalk_sg_next(tsg); + } + } else { + dma_map_sg(dev, sg, nents, dir); + } ++ ++ if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) ++ dma_sync_sg_for_device(dev, sg, nents, dir); ++ + return nents; + } + +@@ -105,6 +114,9 @@ + unsigned int nents, enum dma_data_direction dir, + bool chained) + { ++ if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)) ++ dma_sync_sg_for_cpu(dev, sg, nents, dir); ++ + if (unlikely(chained)) { + int i; + for (i = 0; i < nents; i++) { +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/sm.h linux-3.14.72/drivers/crypto/caam/sm.h +--- linux-3.14.72.orig/drivers/crypto/caam/sm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/crypto/caam/sm.h 2016-06-19 22:11:55.117152342 +0200 +@@ -0,0 +1,122 @@ ++ ++/* ++ * CAAM Secure Memory/Keywrap API Definitions ++ * Copyright (C) 2008-2015 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 ++ ++/* Define treatment of secure memory vs. general memory blobs */ ++#define SM_SECMEM 0 ++#define SM_GENMEM 1 ++ ++/* Define treatment of red/black keys */ ++#define RED_KEY 0 ++#define BLACK_KEY 1 ++ ++/* Define key encryption/covering options */ ++#define KEY_COVER_ECB 0 /* cover key in AES-ECB */ ++#define KEY_COVER_CCM 1 /* cover key with AES-CCM */ ++ ++/* ++ * Round a key size up to an AES blocksize boundary so to allow for ++ * padding out to a full block ++ */ ++#define AES_BLOCK_PAD(x) ((x % 16) ? ((x >> 4) + 1) << 4 : x) ++ ++/* Define space required for BKEK + MAC tag storage in any blob */ ++#define BLOB_OVERHEAD (32 + 16) ++ ++/* 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_cover_key(struct device *dev, u32 unit, u32 slot, ++ u16 key_length, u8 keyauth); ++extern int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot, ++ u8 keycolor, u8 keyauth, u8 *outbuf, ++ u16 keylen, u8 *keymod); ++extern int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot, ++ u8 keycolor, u8 keyauth, u8 *inbuf, ++ u16 keylen, u8 *keymod); ++ ++/* Prior functions from legacy API, deprecated */ ++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; /* Virtual base of secure memory pages */ ++ void *phys_address; /* Physical base of secure memory pages */ ++ 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 */ ++ void *pg_phys; /* Calculated physical 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 */ ++ struct platform_device *sm_pdev; /* Secure Memory platform device */ ++ 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); ++ void *(*slot_get_physical)(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.72.orig/drivers/crypto/caam/sm_store.c linux-3.14.72/drivers/crypto/caam/sm_store.c +--- linux-3.14.72.orig/drivers/crypto/caam/sm_store.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/crypto/caam/sm_store.c 2016-06-19 22:11:55.117152342 +0200 +@@ -0,0 +1,1169 @@ ++ ++/* ++ * CAAM Secure Memory Storage Interface ++ * Copyright (C) 2008-2015 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" ++ ++#define SECMEM_KEYMOD_LEN 8 ++#define GENMEM_KEYMOD_LEN 16 ++ ++#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 ++ ++#define INITIAL_DESCSZ 16 /* size of tmp buffer for descriptor const. */ ++ ++/* ++ * Construct a black key conversion job descriptor ++ * ++ * This function constructs a job descriptor capable of performing ++ * a key blackening operation on a plaintext secure memory resident object. ++ * ++ * - desc pointer to a pointer to the descriptor generated by this ++ * function. Caller will be responsible to kfree() this ++ * descriptor after execution. ++ * - key physical pointer to the plaintext, which will also hold ++ * the result. Since encryption occurs in place, caller must ++ * ensure that the space is large enough to accommodate the ++ * blackened key ++ * - keysz size of the plaintext ++ * - auth if a CCM-covered key is required, use KEY_COVER_CCM, else ++ * use KEY_COVER_ECB. ++ * ++ * KEY to key1 from @key_addr LENGTH 16 BYTES; ++ * FIFO STORE from key1[ecb] TO @key_addr LENGTH 16 BYTES; ++ * ++ * Note that this variant uses the JDKEK only; it does not accommodate the ++ * trusted key encryption key at this time. ++ * ++ */ ++static int blacken_key_jobdesc(u32 **desc, void *key, u16 keysz, bool auth) ++{ ++ u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; ++ u16 dsize, idx; ++ ++ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); ++ idx = 1; ++ ++ /* Load key to class 1 key register */ ++ tmpdesc[idx++] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK); ++ tmpdesc[idx++] = (u32)key; ++ ++ /* ...and write back out via FIFO store*/ ++ tmpdesc[idx] = CMD_FIFO_STORE | CLASS_1 | (keysz & KEY_LENGTH_MASK); ++ ++ /* plus account for ECB/CCM option in FIFO_STORE */ ++ if (auth == KEY_COVER_ECB) ++ tmpdesc[idx] |= FIFOST_TYPE_KEY_KEK; ++ else ++ tmpdesc[idx] |= FIFOST_TYPE_KEY_CCM_JKEK; ++ ++ idx++; ++ tmpdesc[idx++] = (u32)key; ++ ++ /* finish off the job header */ ++ tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK); ++ dsize = idx * sizeof(u32); ++ ++ /* now allocate execution buffer and coat it with executable */ ++ tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA); ++ if (tdesc == NULL) ++ return 0; ++ ++ memcpy(tdesc, tmpdesc, dsize); ++ *desc = tdesc; ++ ++ return dsize; ++} ++ ++/* ++ * Construct a blob encapsulation job descriptor ++ * ++ * This function dynamically constructs a blob encapsulation job descriptor ++ * from the following arguments: ++ * ++ * - desc pointer to a pointer to the descriptor generated by this ++ * function. Caller will be responsible to kfree() this ++ * descriptor after execution. ++ * - keymod Physical pointer to a key modifier, which must reside in a ++ * contiguous piece of memory. Modifier will be assumed to be ++ * 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long ++ * for a blob of type SM_GENMEM (see blobtype argument). ++ * - secretbuf Physical pointer to a secret, normally a black or red key, ++ * possibly residing within an accessible secure memory page, ++ * of the secret to be encapsulated to an output blob. ++ * - outbuf Physical pointer to the destination buffer to receive the ++ * encapsulated output. This buffer will need to be 48 bytes ++ * larger than the input because of the added encapsulation data. ++ * The generated descriptor will account for the increase in size, ++ * but the caller must also account for this increase in the ++ * buffer allocator. ++ * - secretsz Size of input secret, in bytes. This is limited to 65536 ++ * less the size of blob overhead, since the length embeds into ++ * DECO pointer in/out instructions. ++ * - keycolor Determines if the source data is covered (black key) or ++ * plaintext (red key). RED_KEY or BLACK_KEY are defined in ++ * for this purpose. ++ * - blobtype Determine if encapsulated blob should be a secure memory ++ * blob (SM_SECMEM), with partition data embedded with key ++ * material, or a general memory blob (SM_GENMEM). ++ * - auth If BLACK_KEY source is covered via AES-CCM, specify ++ * KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB). ++ * ++ * Upon completion, desc points to a buffer containing a CAAM job ++ * descriptor which encapsulates data into an externally-storable blob ++ * suitable for use across power cycles. ++ * ++ * This is an example of a black key encapsulation job into a general memory ++ * blob. Notice the 16-byte key modifier in the LOAD instruction. Also note ++ * the output 48 bytes longer than the input: ++ * ++ * [00] B0800008 jobhdr: stidx=0 len=8 ++ * [01] 14400010 ld: ccb2-key len=16 offs=0 ++ * [02] 08144891 ptr->@0x08144891 ++ * [03] F800003A seqoutptr: len=58 ++ * [04] 01000000 out_ptr->@0x01000000 ++ * [05] F000000A seqinptr: len=10 ++ * [06] 09745090 in_ptr->@0x09745090 ++ * [07] 870D0004 operation: encap blob reg=memory, black, format=normal ++ * ++ * This is an example of a red key encapsulation job for storing a red key ++ * into a secure memory blob. Note the 8 byte modifier on the 12 byte offset ++ * in the LOAD instruction; this accounts for blob permission storage: ++ * ++ * [00] B0800008 jobhdr: stidx=0 len=8 ++ * [01] 14400C08 ld: ccb2-key len=8 offs=12 ++ * [02] 087D0784 ptr->@0x087d0784 ++ * [03] F8000050 seqoutptr: len=80 ++ * [04] 09251BB2 out_ptr->@0x09251bb2 ++ * [05] F0000020 seqinptr: len=32 ++ * [06] 40000F31 in_ptr->@0x40000f31 ++ * [07] 870D0008 operation: encap blob reg=memory, red, sec_mem, ++ * format=normal ++ * ++ * Note: this function only generates 32-bit pointers at present, and should ++ * be refactored using a scheme that allows both 32 and 64 bit addressing ++ */ ++ ++static int blob_encap_jobdesc(u32 **desc, dma_addr_t keymod, ++ void *secretbuf, dma_addr_t outbuf, ++ u16 secretsz, u8 keycolor, u8 blobtype, u8 auth) ++{ ++ u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; ++ u16 dsize, idx; ++ ++ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); ++ idx = 1; ++ ++ /* ++ * Key modifier works differently for secure/general memory blobs ++ * This accounts for the permission/protection data encapsulated ++ * within the blob if a secure memory blob is requested ++ */ ++ if (blobtype == SM_SECMEM) ++ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_KEY | ++ ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) ++ | (8 & LDST_LEN_MASK); ++ else /* is general memory blob */ ++ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK); ++ ++ tmpdesc[idx++] = (u32)keymod; ++ ++ /* ++ * Encapsulation output must include space for blob key encryption ++ * key and MAC tag ++ */ ++ tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (secretsz + BLOB_OVERHEAD); ++ tmpdesc[idx++] = (u32)outbuf; ++ ++ /* Input data, should be somewhere in secure memory */ ++ tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz; ++ tmpdesc[idx++] = (u32)secretbuf; ++ ++ /* Set blob encap, then color */ ++ tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB; ++ ++ if (blobtype == SM_SECMEM) ++ tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM; ++ ++ if (auth == KEY_COVER_CCM) ++ tmpdesc[idx] |= OP_PCL_BLOB_EKT; ++ ++ if (keycolor == BLACK_KEY) ++ tmpdesc[idx] |= OP_PCL_BLOB_BLACK; ++ ++ 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 blob decapsulation job descriptor ++ * ++ * This function dynamically constructs a blob decapsulation job descriptor ++ * from the following arguments: ++ * ++ * - desc pointer to a pointer to the descriptor generated by this ++ * function. Caller will be responsible to kfree() this ++ * descriptor after execution. ++ * - keymod Physical pointer to a key modifier, which must reside in a ++ * contiguous piece of memory. Modifier will be assumed to be ++ * 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long ++ * for a blob of type SM_GENMEM (see blobtype argument). ++ * - blobbuf Physical pointer (into external memory) of the blob to ++ * be decapsulated. Blob must reside in a contiguous memory ++ * segment. ++ * - outbuf Physical pointer of the decapsulated output, possibly into ++ * a location within a secure memory page. Must be contiguous. ++ * - secretsz Size of encapsulated secret in bytes (not the size of the ++ * input blob). ++ * - keycolor Determines if decapsulated content is encrypted (BLACK_KEY) ++ * or left as plaintext (RED_KEY). ++ * - blobtype Determine if encapsulated blob should be a secure memory ++ * blob (SM_SECMEM), with partition data embedded with key ++ * material, or a general memory blob (SM_GENMEM). ++ * - auth If decapsulation path is specified by BLACK_KEY, then if ++ * AES-CCM is requested for key covering use KEY_COVER_CCM, else ++ * use AES-ECB (KEY_COVER_ECB). ++ * ++ * Upon completion, desc points to a buffer containing a CAAM job descriptor ++ * that decapsulates a key blob from external memory into a black (encrypted) ++ * key or red (plaintext) content. ++ * ++ * This is an example of a black key decapsulation job from a general memory ++ * blob. Notice the 16-byte key modifier in the LOAD instruction. ++ * ++ * [00] B0800008 jobhdr: stidx=0 len=8 ++ * [01] 14400010 ld: ccb2-key len=16 offs=0 ++ * [02] 08A63B7F ptr->@0x08a63b7f ++ * [03] F8000010 seqoutptr: len=16 ++ * [04] 01000000 out_ptr->@0x01000000 ++ * [05] F000003A seqinptr: len=58 ++ * [06] 01000010 in_ptr->@0x01000010 ++ * [07] 860D0004 operation: decap blob reg=memory, black, format=normal ++ * ++ * This is an example of a red key decapsulation job for restoring a red key ++ * from a secure memory blob. Note the 8 byte modifier on the 12 byte offset ++ * in the LOAD instruction: ++ * ++ * [00] B0800008 jobhdr: stidx=0 len=8 ++ * [01] 14400C08 ld: ccb2-key len=8 offs=12 ++ * [02] 01000000 ptr->@0x01000000 ++ * [03] F8000020 seqoutptr: len=32 ++ * [04] 400000E6 out_ptr->@0x400000e6 ++ * [05] F0000050 seqinptr: len=80 ++ * [06] 08F0C0EA in_ptr->@0x08f0c0ea ++ * [07] 860D0008 operation: decap blob reg=memory, red, sec_mem, ++ * format=normal ++ * ++ * Note: this function only generates 32-bit pointers at present, and should ++ * be refactored using a scheme that allows both 32 and 64 bit addressing ++ */ ++ ++static int blob_decap_jobdesc(u32 **desc, dma_addr_t keymod, dma_addr_t blobbuf, ++ u8 *outbuf, u16 secretsz, u8 keycolor, ++ u8 blobtype, u8 auth) ++{ ++ u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; ++ u16 dsize, idx; ++ ++ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); ++ idx = 1; ++ ++ /* Load key modifier */ ++ if (blobtype == SM_SECMEM) ++ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_KEY | ++ ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) ++ | (8 & LDST_LEN_MASK); ++ else /* is general memory blob */ ++ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK); ++ ++ tmpdesc[idx++] = (u32)keymod; ++ ++ /* Compensate BKEK + MAC tag over size of encapsulated secret */ ++ tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + BLOB_OVERHEAD); ++ tmpdesc[idx++] = (u32)blobbuf; ++ tmpdesc[idx++] = CMD_SEQ_OUT_PTR | secretsz; ++ tmpdesc[idx++] = (u32)outbuf; ++ ++ /* Decapsulate from secure memory partition to black blob */ ++ tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB; ++ ++ if (blobtype == SM_SECMEM) ++ tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM; ++ ++ if (auth == KEY_COVER_CCM) ++ tmpdesc[idx] |= OP_PCL_BLOB_EKT; ++ ++ if (keycolor == BLACK_KEY) ++ tmpdesc[idx] |= OP_PCL_BLOB_BLACK; ++ ++ 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; ++} ++ ++void *slot_get_physical(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_physical(): slot %d is 0x%08x\n", slot, ++ (u32)ksdata->phys_address + slot * smpriv->slot_size); ++#endif ++ ++ return ksdata->phys_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; ++ smpriv->pagedesc[unit].ksdata->phys_address = ++ smpriv->pagedesc[unit].pg_phys; ++ ++ 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_physical = slot_get_physical; ++ 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); ++ ++/* ++ * Blacken a clear key in a slot. Operates "in place". ++ * Limited to class 1 keys at the present time ++ */ ++int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot, ++ u16 key_length, u8 keyauth) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = 0; ++ u8 __iomem *slotaddr; ++ void *slotphys; ++ u32 dsize, jstat; ++ u32 __iomem *coverdesc = NULL; ++ ++ /* Get the address of the object in the slot */ ++ slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot); ++ slotphys = (u8 *)smpriv->slot_get_physical(dev, unit, slot); ++ ++ dsize = blacken_key_jobdesc(&coverdesc, slotphys, key_length, keyauth); ++ if (!dsize) ++ return -ENOMEM; ++ jstat = sm_key_job(dev, coverdesc); ++ if (jstat) ++ retval = -EIO; ++ ++ kfree(coverdesc); ++ return retval; ++} ++EXPORT_SYMBOL(sm_keystore_cover_key); ++ ++/* Export a black/red key to a blob in external memory */ ++int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot, u8 keycolor, ++ u8 keyauth, u8 *outbuf, u16 keylen, u8 *keymod) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = 0; ++ u8 __iomem *slotaddr, *lkeymod; ++ u8 __iomem *slotphys; ++ dma_addr_t keymod_dma, outbuf_dma; ++ u32 dsize, jstat; ++ u32 __iomem *encapdesc = NULL; ++ ++ /* Get the base address(es) of the specified slot */ ++ slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot); ++ slotphys = smpriv->slot_get_physical(dev, unit, slot); ++ ++ /* Build/map/flush the key modifier */ ++ lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA); ++ memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN); ++ keymod_dma = dma_map_single(dev, lkeymod, SECMEM_KEYMOD_LEN, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(dev, keymod_dma, SECMEM_KEYMOD_LEN, ++ DMA_TO_DEVICE); ++ ++ outbuf_dma = dma_map_single(dev, outbuf, keylen + BLOB_OVERHEAD, ++ DMA_FROM_DEVICE); ++ ++ /* Build the encapsulation job descriptor */ ++ dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, slotphys, outbuf_dma, ++ keylen, keycolor, SM_SECMEM, keyauth); ++ if (!dsize) { ++ dev_err(dev, "can't alloc an encapsulation descriptor\n"); ++ retval = -ENOMEM; ++ goto out; ++ } ++ jstat = sm_key_job(dev, encapdesc); ++ dma_sync_single_for_cpu(dev, outbuf_dma, keylen + BLOB_OVERHEAD, ++ DMA_FROM_DEVICE); ++ if (jstat) ++ retval = -EIO; ++ ++out: ++ dma_unmap_single(dev, outbuf_dma, keylen + BLOB_OVERHEAD, ++ DMA_FROM_DEVICE); ++ dma_unmap_single(dev, keymod_dma, SECMEM_KEYMOD_LEN, DMA_TO_DEVICE); ++ kfree(encapdesc); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sm_keystore_slot_export); ++ ++/* Import a black/red key from a blob residing in external memory */ ++int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot, u8 keycolor, ++ u8 keyauth, u8 *inbuf, u16 keylen, u8 *keymod) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = 0; ++ u8 __iomem *slotaddr, *lkeymod; ++ u8 __iomem *slotphys; ++ dma_addr_t keymod_dma, inbuf_dma; ++ u32 dsize, jstat; ++ u32 __iomem *decapdesc = NULL; ++ ++ /* Get the base address(es) of the specified slot */ ++ slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot); ++ slotphys = smpriv->slot_get_physical(dev, unit, slot); ++ ++ /* Build/map/flush the key modifier */ ++ lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA); ++ memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN); ++ keymod_dma = dma_map_single(dev, lkeymod, SECMEM_KEYMOD_LEN, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(dev, keymod_dma, SECMEM_KEYMOD_LEN, ++ DMA_TO_DEVICE); ++ ++ inbuf_dma = dma_map_single(dev, inbuf, keylen + BLOB_OVERHEAD, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(dev, inbuf_dma, keylen + BLOB_OVERHEAD, ++ DMA_TO_DEVICE); ++ ++ /* Build the encapsulation job descriptor */ ++ dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, inbuf_dma, slotphys, ++ keylen, keycolor, SM_SECMEM, keyauth); ++ if (!dsize) { ++ dev_err(dev, "can't alloc a decapsulation descriptor\n"); ++ retval = -ENOMEM; ++ goto out; ++ } ++ ++ jstat = sm_key_job(dev, decapdesc); ++ ++ /* ++ * May want to expand upon error meanings a bit. Any CAAM status ++ * is reported as EIO, but we might want to look for something more ++ * meaningful for something like an ICV error on restore, otherwise ++ * the caller is left guessing. ++ */ ++ if (jstat) ++ retval = -EIO; ++ ++out: ++ dma_unmap_single(dev, inbuf_dma, keylen + BLOB_OVERHEAD, ++ DMA_TO_DEVICE); ++ dma_unmap_single(dev, keymod_dma, SECMEM_KEYMOD_LEN, DMA_TO_DEVICE); ++ kfree(decapdesc); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sm_keystore_slot_import); ++ ++/* ++ * 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; ++ } ++ ++ /* Save a pointer to the platform device for Secure Memory */ ++ smpriv->sm_pdev = sm_pdev; ++ 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->jrpdev[0]->dev; ++ 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)); ++ /* FIXME: get base address from platform property... */ ++ lpagedesc[page].pg_phys = (u32 *)0x00100000 + ++ ((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; ++ ++ /* Return if resource not initialized by startup */ ++ if (smdev == NULL) ++ return; ++ ++ smpriv = dev_get_drvdata(smdev); ++ ++ /* Remove Secure Memory Platform Device */ ++ of_device_unregister(smpriv->sm_pdev); ++ ++ 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.72.orig/drivers/crypto/caam/sm_test.c linux-3.14.72/drivers/crypto/caam/sm_test.c +--- linux-3.14.72.orig/drivers/crypto/caam/sm_test.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/crypto/caam/sm_test.c 2016-06-19 22:11:55.117152342 +0200 +@@ -0,0 +1,517 @@ ++ ++/* ++ * Secure Memory / Keystore Exemplification Module ++ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved ++ * ++ * This module has been overloaded as an example to show: ++ * - Secure memory subsystem initialization/shutdown ++ * - Allocation/deallocation of "slots" in a secure memory page ++ * - Loading and unloading of key material into slots ++ * - Covering of secure memory objects into "black keys" (ECB only at present) ++ * - Verification of key covering (by differentiation only) ++ * - Exportation of keys into secure memory blobs (with display of result) ++ * - Importation of keys from secure memory blobs (with display of result) ++ * - Verification of re-imported keys where possible. ++ * ++ * The module does not show the use of key objects as working key register ++ * source material at this time. ++ * ++ * 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" ++ ++/* Fixed known pattern for a key modifier */ ++static u8 skeymod[] = { ++ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, ++ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 ++}; ++ ++/* Fixed known pattern for a key */ ++static u8 clrkey[] = { ++ 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 void key_display(struct device *dev, u8 *label, u16 size, u8 *key) ++{ ++ unsigned i; ++ ++ dev_info(dev, label); ++ for (i = 0; i < size; i += 8) ++ dev_info(dev, ++ "[%04d] %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ i, key[i], key[i + 1], key[i + 2], key[i + 3], ++ key[i + 4], key[i + 5], key[i + 6], key[i + 7]); ++} ++ ++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; ++ int rtnval = 0; ++ u8 clrkey8[8], clrkey16[16], clrkey24[24], clrkey32[32]; ++ u8 blkkey8[AES_BLOCK_PAD(8)], blkkey16[AES_BLOCK_PAD(16)]; ++ u8 blkkey24[AES_BLOCK_PAD(24)], blkkey32[AES_BLOCK_PAD(32)]; ++ u8 rstkey8[AES_BLOCK_PAD(8)], rstkey16[AES_BLOCK_PAD(16)]; ++ u8 rstkey24[AES_BLOCK_PAD(24)], rstkey32[AES_BLOCK_PAD(32)]; ++ u8 __iomem *blob8, *blob16, *blob24, *blob32; ++ u32 keyslot8, keyslot16, keyslot24, keyslot32 = 0; ++ ++ blob8 = blob16 = blob24 = blob32 = NULL; ++ ++ /* ++ * 3.5.x and later revs for MX6 should be able to ditch this ++ * and detect via dts property ++ */ ++ ctrldev = &pdev->dev; ++ ctrlpriv = dev_get_drvdata(ctrldev); ++ ksdev = ctrlpriv->smdev; ++ kspriv = dev_get_drvdata(ksdev); ++ if (kspriv == NULL) ++ return -ENODEV; ++ ++ /* What keystores are available ? */ ++ units = sm_detect_keystore_units(ksdev); ++ if (!units) ++ dev_err(ksdev, "blkkey_ex: 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, "blkkey_ex: insufficient keystore units\n"); ++ return -ENODEV; ++ } ++ unit = 1; ++ ++ dev_info(ksdev, "blkkey_ex: %d keystore units available\n", units); ++ ++ /* Initialize/Establish Keystore */ ++ sm_establish_keystore(ksdev, unit); /* Initalize store in #1 */ ++ ++ /* ++ * Now let's set up buffers for blobs in DMA-able memory. All are ++ * larger than need to be so that blob size can be seen. ++ */ ++ blob8 = kzalloc(128, GFP_KERNEL | GFP_DMA); ++ blob16 = kzalloc(128, GFP_KERNEL | GFP_DMA); ++ blob24 = kzalloc(128, GFP_KERNEL | GFP_DMA); ++ blob32 = kzalloc(128, GFP_KERNEL | GFP_DMA); ++ ++ if ((blob8 == NULL) || (blob16 == NULL) || (blob24 == NULL) || ++ (blob32 == NULL)) { ++ rtnval = -ENOMEM; ++ dev_err(ksdev, "blkkey_ex: can't get blob buffers\n"); ++ goto freemem; ++ } ++ ++ /* Initialize clear keys with a known and recognizable pattern */ ++ memcpy(clrkey8, clrkey, 8); ++ memcpy(clrkey16, clrkey, 16); ++ memcpy(clrkey24, clrkey, 24); ++ memcpy(clrkey32, clrkey, 32); ++ ++ memset(blkkey8, 0, AES_BLOCK_PAD(8)); ++ memset(blkkey16, 0, AES_BLOCK_PAD(16)); ++ memset(blkkey24, 0, AES_BLOCK_PAD(24)); ++ memset(blkkey32, 0, AES_BLOCK_PAD(32)); ++ ++ memset(rstkey8, 0, AES_BLOCK_PAD(8)); ++ memset(rstkey16, 0, AES_BLOCK_PAD(16)); ++ memset(rstkey24, 0, AES_BLOCK_PAD(24)); ++ memset(rstkey32, 0, AES_BLOCK_PAD(32)); ++ ++ /* ++ * Allocate keyslots. Since we're going to blacken keys in-place, ++ * we want slots big enough to pad out to the next larger AES blocksize ++ * so pad them out. ++ */ ++ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(8), &keyslot8)) ++ goto dealloc; ++ ++ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(16), &keyslot16)) ++ goto dealloc; ++ ++ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(24), &keyslot24)) ++ goto dealloc; ++ ++ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(32), &keyslot32)) ++ goto dealloc; ++ ++ ++ /* Now load clear key data into the newly allocated slots */ ++ if (sm_keystore_slot_load(ksdev, unit, keyslot8, clrkey8, 8)) ++ goto dealloc; ++ ++ if (sm_keystore_slot_load(ksdev, unit, keyslot16, clrkey16, 16)) ++ goto dealloc; ++ ++ if (sm_keystore_slot_load(ksdev, unit, keyslot24, clrkey24, 24)) ++ goto dealloc; ++ ++ if (sm_keystore_slot_load(ksdev, unit, keyslot32, clrkey32, 32)) ++ goto dealloc; ++ ++ /* ++ * All cleartext keys are loaded into slots (in an unprotected ++ * partition at this time) ++ * ++ * Cover keys in-place ++ */ ++ if (sm_keystore_cover_key(ksdev, unit, keyslot8, 8, KEY_COVER_ECB)) { ++ dev_info(ksdev, "blkkey_ex: can't cover 64-bit key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_cover_key(ksdev, unit, keyslot16, 16, KEY_COVER_ECB)) { ++ dev_info(ksdev, "blkkey_ex: can't cover 128-bit key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_cover_key(ksdev, unit, keyslot24, 24, KEY_COVER_ECB)) { ++ dev_info(ksdev, "blkkey_ex: can't cover 192-bit key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_cover_key(ksdev, unit, keyslot32, 32, KEY_COVER_ECB)) { ++ dev_info(ksdev, "blkkey_ex: can't cover 256-bit key\n"); ++ goto dealloc; ++ } ++ ++ /* ++ * Keys should be covered and appear sufficiently "random" ++ * as a result of the covering (blackening) process. Assuming ++ * non-secure mode, read them back out for examination; they should ++ * appear as random data, completely differing from the clear ++ * inputs. So, this will read them back from secure memory and ++ * compare them. If they match the clear key, then the covering ++ * operation didn't occur. ++ */ ++ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8), ++ blkkey8)) { ++ dev_info(ksdev, "blkkey_ex: can't read 64-bit black key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot16, AES_BLOCK_PAD(16), ++ blkkey16)) { ++ dev_info(ksdev, "blkkey_ex: can't read 128-bit black key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot24, AES_BLOCK_PAD(24), ++ blkkey24)) { ++ dev_info(ksdev, "blkkey_ex: can't read 192-bit black key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot32, AES_BLOCK_PAD(32), ++ blkkey32)) { ++ dev_info(ksdev, "blkkey_ex: can't read 256-bit black key\n"); ++ goto dealloc; ++ } ++ ++ ++ if (!memcmp(blkkey8, clrkey8, 8)) { ++ dev_info(ksdev, "blkkey_ex: 64-bit key cover failed\n"); ++ goto dealloc; ++ } ++ ++ if (!memcmp(blkkey16, clrkey16, 16)) { ++ dev_info(ksdev, "blkkey_ex: 128-bit key cover failed\n"); ++ goto dealloc; ++ } ++ ++ if (!memcmp(blkkey24, clrkey24, 24)) { ++ dev_info(ksdev, "blkkey_ex: 192-bit key cover failed\n"); ++ goto dealloc; ++ } ++ ++ if (!memcmp(blkkey32, clrkey32, 32)) { ++ dev_info(ksdev, "blkkey_ex: 256-bit key cover failed\n"); ++ goto dealloc; ++ } ++ ++ ++ key_display(ksdev, "64-bit clear key:", 8, clrkey8); ++ key_display(ksdev, "64-bit black key:", AES_BLOCK_PAD(8), blkkey8); ++ ++ key_display(ksdev, "128-bit clear key:", 16, clrkey16); ++ key_display(ksdev, "128-bit black key:", AES_BLOCK_PAD(16), blkkey16); ++ ++ key_display(ksdev, "192-bit clear key:", 24, clrkey24); ++ key_display(ksdev, "192-bit black key:", AES_BLOCK_PAD(24), blkkey24); ++ ++ key_display(ksdev, "256-bit clear key:", 32, clrkey32); ++ key_display(ksdev, "256-bit black key:", AES_BLOCK_PAD(32), blkkey32); ++ ++ /* ++ * Now encapsulate all keys as SM blobs out to external memory ++ * Blobs will appear as random-looking blocks of data different ++ * from the original source key, and 48 bytes longer than the ++ * original key, to account for the extra data encapsulated within. ++ */ ++ key_display(ksdev, "64-bit unwritten blob:", 96, blob8); ++ key_display(ksdev, "128-bit unwritten blob:", 96, blob16); ++ key_display(ksdev, "196-bit unwritten blob:", 96, blob24); ++ key_display(ksdev, "256-bit unwritten blob:", 96, blob32); ++ ++ if (sm_keystore_slot_export(ksdev, unit, keyslot8, BLACK_KEY, ++ KEY_COVER_ECB, blob8, 8, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't encapsulate 64-bit key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_export(ksdev, unit, keyslot16, BLACK_KEY, ++ KEY_COVER_ECB, blob16, 16, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't encapsulate 128-bit key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_export(ksdev, unit, keyslot24, BLACK_KEY, ++ KEY_COVER_ECB, blob24, 24, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't encapsulate 192-bit key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_export(ksdev, unit, keyslot32, BLACK_KEY, ++ KEY_COVER_ECB, blob32, 32, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't encapsulate 256-bit key\n"); ++ goto dealloc; ++ } ++ ++ key_display(ksdev, "64-bit black key in blob:", 96, blob8); ++ key_display(ksdev, "128-bit black key in blob:", 96, blob16); ++ key_display(ksdev, "192-bit black key in blob:", 96, blob24); ++ key_display(ksdev, "256-bit black key in blob:", 96, blob32); ++ ++ /* ++ * Now re-import black keys from secure-memory blobs stored ++ * in general memory from the previous operation. Since we are ++ * working with black keys, and since power has not cycled, the ++ * restored black keys should match the original blackened keys ++ * (this would not be true if the blobs were save in some non-volatile ++ * store, and power was cycled between the save and restore) ++ */ ++ if (sm_keystore_slot_import(ksdev, unit, keyslot8, BLACK_KEY, ++ KEY_COVER_ECB, blob8, 8, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't decapsulate 64-bit blob\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_import(ksdev, unit, keyslot16, BLACK_KEY, ++ KEY_COVER_ECB, blob16, 16, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't decapsulate 128-bit blob\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_import(ksdev, unit, keyslot24, BLACK_KEY, ++ KEY_COVER_ECB, blob24, 24, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't decapsulate 196-bit blob\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_import(ksdev, unit, keyslot32, BLACK_KEY, ++ KEY_COVER_ECB, blob32, 32, skeymod)) { ++ dev_info(ksdev, "blkkey_ex: can't decapsulate 256-bit blob\n"); ++ goto dealloc; ++ } ++ ++ ++ /* ++ * Blobs are now restored as black keys. Read those black keys back ++ * for a comparison with the original black key, they should match ++ */ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8), ++ rstkey8)) { ++ dev_info(ksdev, ++ "blkkey_ex: can't read restored 64-bit black key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot16, AES_BLOCK_PAD(16), ++ rstkey16)) { ++ dev_info(ksdev, ++ "blkkey_ex: can't read restored 128-bit black key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot24, AES_BLOCK_PAD(24), ++ rstkey24)) { ++ dev_info(ksdev, ++ "blkkey_ex: can't read restored 196-bit black key\n"); ++ goto dealloc; ++ } ++ ++ if (sm_keystore_slot_read(ksdev, unit, keyslot32, AES_BLOCK_PAD(32), ++ rstkey32)) { ++ dev_info(ksdev, ++ "blkkey_ex: can't read restored 256-bit black key\n"); ++ goto dealloc; ++ } ++ ++ key_display(ksdev, "restored 64-bit black key:", AES_BLOCK_PAD(8), ++ rstkey8); ++ key_display(ksdev, "restored 128-bit black key:", AES_BLOCK_PAD(16), ++ rstkey16); ++ key_display(ksdev, "restored 192-bit black key:", AES_BLOCK_PAD(24), ++ rstkey24); ++ key_display(ksdev, "restored 256-bit black key:", AES_BLOCK_PAD(32), ++ rstkey32); ++ ++ /* ++ * Compare the restored black keys with the original blackened keys ++ * As long as we're operating within the same power cycle, a black key ++ * restored from a blob should match the original black key IF the ++ * key happens to be of a size that matches a multiple of the AES ++ * blocksize. Any key that is padded to fill the block size will not ++ * match, excepting a key that exceeds a block; only the first full ++ * blocks will match (assuming ECB). ++ * ++ * Therefore, compare the 16 and 32 bit keys, they should match. ++ * The 24 bit key can only match within the first 16 byte block. ++ */ ++ ++ if (memcmp(rstkey16, blkkey16, AES_BLOCK_PAD(16))) { ++ dev_info(ksdev, "blkkey_ex: 128-bit restored key mismatch\n"); ++ rtnval--; ++ } ++ ++ /* Only first AES block will match, remainder subject to padding */ ++ if (memcmp(rstkey24, blkkey24, 16)) { ++ dev_info(ksdev, "blkkey_ex: 192-bit restored key mismatch\n"); ++ rtnval--; ++ } ++ ++ if (memcmp(rstkey32, blkkey32, AES_BLOCK_PAD(32))) { ++ dev_info(ksdev, "blkkey_ex: 256-bit restored key mismatch\n"); ++ rtnval--; ++ } ++ ++ ++ /* Remove keys from keystore */ ++dealloc: ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot8); ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot16); ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot24); ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot32); ++ ++ ++ /* Free resources */ ++freemem: ++ kfree(blob8); ++ kfree(blob16); ++ kfree(blob24); ++ kfree(blob32); ++ ++ /* 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 Black Key Usage Example"); ++MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); ++#endif +diff -Nur linux-3.14.72.orig/drivers/crypto/caam/snvsregs.h linux-3.14.72/drivers/crypto/caam/snvsregs.h +--- linux-3.14.72.orig/drivers/crypto/caam/snvsregs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/crypto/caam/snvsregs.h 2016-06-19 22:11:55.117152342 +0200 +@@ -0,0 +1,237 @@ ++/* ++ * SNVS hardware register-level view ++ * ++ * Copyright (C) 2012-2015 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; /* HPLR - HP Lock */ ++ u32 cmd; /* HPCOMR - HP Command */ ++ u32 ctl; /* HPCR - HP Control */ ++ u32 secvio_intcfg; /* HPSICR - Security Violation Int Config */ ++ u32 secvio_ctl; /* HPSVCR - Security Violation Control */ ++ u32 status; /* HPSR - HP Status */ ++ u32 secvio_status; /* HPSVSR - 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.72.orig/drivers/dma/imx-sdma.c linux-3.14.72/drivers/dma/imx-sdma.c +--- linux-3.14.72.orig/drivers/dma/imx-sdma.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/dma/imx-sdma.c 2016-06-19 22:11:55.121152080 +0200 +@@ -7,7 +7,7 @@ + * + * Based on code from Freescale: + * +- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2004-2015 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 +@@ -25,10 +25,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -39,6 +41,8 @@ + #include + + #include ++#include ++#include + #include + #include + +@@ -229,6 +233,7 @@ + } __attribute__ ((packed)); + + #define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor)) ++#define SDMA_BD_MAX_CNT 0xfffc /* align with 4 bytes */ + + struct sdma_engine; + +@@ -244,6 +249,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,11 +261,15 @@ + 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 int device_to_device; ++ unsigned int pc_to_pc; + unsigned long flags; +- dma_addr_t per_address; ++ dma_addr_t per_address, per_address2; + unsigned long event_mask[2]; + unsigned long watermark_level; + u32 shp_addr, per_addr; +@@ -270,6 +280,7 @@ + unsigned int chn_count; + unsigned int chn_real_count; + struct tasklet_struct tasklet; ++ struct imx_dma_data data; + }; + + #define IMX_DMA_SG_LOOP BIT(0) +@@ -278,6 +289,14 @@ + #define MXC_SDMA_DEFAULT_PRIORITY 1 + #define MXC_SDMA_MIN_PRIORITY 1 + #define MXC_SDMA_MAX_PRIORITY 7 ++/* ++ * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are reserved and ++ * can't be accessed. Skip these register touch in suspend/resume. Also below ++ * two macros are only used on i.mx6sx. ++ */ ++#define MXC_SDMA_RESERVED_REG (SDMA_CHNPRI_0 - SDMA_XTRIG_CONF2 - 4) ++#define MXC_SDMA_SAVED_REG_NUM (((SDMA_CHNENBL0_IMX35 + 4 * 48) - \ ++ MXC_SDMA_RESERVED_REG) / 4) + + #define SDMA_FIRMWARE_MAGIC 0x414d4453 + +@@ -316,6 +335,8 @@ + struct device_dma_parameters dma_parms; + struct sdma_channel channel[MAX_DMA_CHANNELS]; + struct sdma_channel_control *channel_control; ++ u32 save_regs[MXC_SDMA_SAVED_REG_NUM]; ++ const char *fw_name; + void __iomem *regs; + struct sdma_context_data *context; + dma_addr_t context_phys; +@@ -326,6 +347,7 @@ + u32 script_number; + struct sdma_script_start_addrs *script_addrs; + const struct sdma_driver_data *drvdata; ++ struct gen_pool *iram_pool; + }; + + static struct sdma_driver_data sdma_imx31 = { +@@ -403,7 +425,6 @@ + .ap_2_ap_addr = 642, + .uart_2_mcu_addr = 817, + .mcu_2_app_addr = 747, +- .per_2_per_addr = 6331, + .uartsh_2_mcu_addr = 1032, + .mcu_2_shp_addr = 960, + .app_2_mcu_addr = 683, +@@ -418,6 +439,24 @@ + .script_addrs = &sdma_script_imx6q, + }; + ++static struct sdma_script_start_addrs sdma_script_imx6sx = { ++ .ap_2_ap_addr = 642, ++ .uart_2_mcu_addr = 817, ++ .mcu_2_app_addr = 747, ++ .uartsh_2_mcu_addr = 1032, ++ .mcu_2_shp_addr = 960, ++ .app_2_mcu_addr = 683, ++ .shp_2_mcu_addr = 891, ++ .spdif_2_mcu_addr = 1100, ++ .mcu_2_spdif_addr = 1134, ++}; ++ ++static struct sdma_driver_data sdma_imx6sx = { ++ .chnenbl0 = SDMA_CHNENBL0_IMX35, ++ .num_events = 48, ++ .script_addrs = &sdma_script_imx6sx, ++}; ++ + static struct platform_device_id sdma_devtypes[] = { + { + .name = "imx25-sdma", +@@ -438,12 +477,16 @@ + .name = "imx6q-sdma", + .driver_data = (unsigned long)&sdma_imx6q, + }, { ++ .name = "imx6sx-sdma", ++ .driver_data = (unsigned long)&sdma_imx6sx, ++ }, { + /* sentinel */ + } + }; + MODULE_DEVICE_TABLE(platform, sdma_devtypes); + + static const struct of_device_id sdma_dt_ids[] = { ++ { .compatible = "fsl,imx6sx-sdma", .data = &sdma_imx6sx, }, + { .compatible = "fsl,imx6q-sdma", .data = &sdma_imx6q, }, + { .compatible = "fsl,imx53-sdma", .data = &sdma_imx53, }, + { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, }, +@@ -540,12 +583,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 +607,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 +641,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 +661,15 @@ + + 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); ++ if (sdmac->peripheral_type == IMX_DMATYPE_UART) { ++ /* restore mode.count after counter readed */ ++ sdmac->chn_real_count = bd->mode.count; ++ bd->mode.count = sdmac->chn_count; ++ } + } + } + +@@ -650,6 +704,14 @@ + static void sdma_tasklet(unsigned long data) + { + struct sdma_channel *sdmac = (struct sdma_channel *) data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sdmac->lock, flags); ++ if (sdmac->status != DMA_IN_PROGRESS && !(sdmac->flags & IMX_DMA_SG_LOOP)) { ++ spin_unlock_irqrestore(&sdmac->lock, flags); ++ return; ++ } ++ spin_unlock_irqrestore(&sdmac->lock, flags); + + if (sdmac->flags & IMX_DMA_SG_LOOP) + sdma_handle_channel_loop(sdmac); +@@ -660,7 +722,7 @@ + static irqreturn_t sdma_int_handler(int irq, void *dev_id) + { + struct sdma_engine *sdma = dev_id; +- unsigned long stat; ++ unsigned long stat, flags; + + stat = readl_relaxed(sdma->regs + SDMA_H_INTR); + /* not interested in channel 0 interrupts */ +@@ -671,7 +733,14 @@ + int channel = fls(stat) - 1; + struct sdma_channel *sdmac = &sdma->channel[channel]; + +- tasklet_schedule(&sdmac->tasklet); ++ if ((sdmac->flags & IMX_DMA_SG_LOOP) && ++ (sdmac->peripheral_type != IMX_DMATYPE_HDMI)) ++ sdma_update_channel_loop(sdmac); ++ ++ spin_lock_irqsave(&sdmac->lock, flags); ++ if (sdmac->status == DMA_IN_PROGRESS || (sdmac->flags & IMX_DMA_SG_LOOP)) ++ tasklet_schedule(&sdmac->tasklet); ++ spin_unlock_irqrestore(&sdmac->lock, flags); + + __clear_bit(channel, &stat); + } +@@ -695,6 +764,8 @@ + + sdmac->pc_from_device = 0; + sdmac->pc_to_device = 0; ++ sdmac->device_to_device = 0; ++ sdmac->pc_to_pc = 0; + + switch (peripheral_type) { + case IMX_DMATYPE_MEMORY: +@@ -721,8 +792,12 @@ + emi_2_per = sdma->script_addrs->mcu_2_ata_addr; + break; + case IMX_DMATYPE_CSPI: ++ per_2_emi = sdma->script_addrs->app_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_ecspi_addr; ++ break; + case IMX_DMATYPE_EXT: + case IMX_DMATYPE_SSI: ++ case IMX_DMATYPE_SAI: + per_2_emi = sdma->script_addrs->app_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_app_addr; + break; +@@ -744,6 +819,11 @@ + emi_2_per = sdma->script_addrs->asrc_2_mcu_addr; + per_2_per = sdma->script_addrs->per_2_per_addr; + break; ++ case IMX_DMATYPE_ASRC_SP: ++ 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: + per_2_emi = sdma->script_addrs->mshc_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_mshc_addr; +@@ -758,12 +838,17 @@ + case IMX_DMATYPE_IPU_MEMORY: + emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; + break; ++ case IMX_DMATYPE_HDMI: ++ emi_2_per = 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->pc_to_pc = emi_2_emi; + } + + static int sdma_load_context(struct sdma_channel *sdmac) +@@ -776,11 +861,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_MEM) ++ load_address = sdmac->pc_to_pc; ++ else + load_address = sdmac->pc_to_device; +- } + + if (load_address < 0) + return load_address; +@@ -800,11 +888,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->per_addr; ++ context->gReg[6] = sdmac->shp_addr; ++ } 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; +@@ -822,9 +915,75 @@ + { + struct sdma_engine *sdma = sdmac->sdma; + int channel = sdmac->channel; ++ unsigned long flags; + +- writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP); ++ spin_lock_irqsave(&sdmac->lock, flags); + sdmac->status = DMA_ERROR; ++ spin_unlock_irqrestore(&sdmac->lock, flags); ++ ++ writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP); ++} ++ ++static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) ++{ ++ int lwml = sdmac->watermark_level & 0xff; ++ int hwml = (sdmac->watermark_level >> 16) & 0xff; ++ ++ 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[0] |= 0; ++ sdmac->event_mask[1] |= ++ BIT(sdmac->event_id0 % 32); ++ } ++ if (sdmac->event_id1 > 31) { ++ sdmac->event_mask[1] |= 0; ++ __set_bit(29, &sdmac->watermark_level); ++ sdmac->event_mask[0] |= ++ BIT(sdmac->event_id1 % 32); ++ } else { ++ sdmac->event_mask[1] |= 0; ++ sdmac->event_mask[0] |= ++ BIT(sdmac->event_id1 % 32); ++ } ++ ++ /* ++ * If LWML(src_maxburst) > HWML(dst_maxburst), we need ++ * swap LWML and HWML of INFO(A.3.2.5.1), also need swap ++ * r0(event_mask[1]) and r1(event_mask[0]). ++ */ ++ if (lwml > hwml) { ++ sdmac->watermark_level &= ~0xff00ff; ++ sdmac->watermark_level |= hwml; ++ sdmac->watermark_level |= lwml << 16; ++ swap(sdmac->event_mask[0], sdmac->event_mask[1]); ++ } ++ /* 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); + } + + static int sdma_config_channel(struct sdma_channel *sdmac) +@@ -844,6 +1003,12 @@ + 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: + sdma_config_ownership(sdmac, false, true, true); +@@ -862,19 +1027,22 @@ + (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); +- } else { ++ if (sdmac->peripheral_type == IMX_DMATYPE_ASRC_SP || ++ sdmac->peripheral_type == IMX_DMATYPE_ASRC) ++ sdma_set_watermarklevel_for_p2p(sdmac); ++ } else + __set_bit(sdmac->event_id0, sdmac->event_mask); +- } ++ + /* Watermark Level */ + sdmac->watermark_level |= sdmac->watermark_level; + /* Address */ +- sdmac->shp_addr = sdmac->per_address; ++ if (sdmac->direction == DMA_DEV_TO_DEV || ++ (sdmac->peripheral_type == IMX_DMATYPE_HDMI)) { ++ sdmac->shp_addr = sdmac->per_address2; ++ sdmac->per_addr = sdmac->per_address; ++ } else { ++ sdmac->shp_addr = sdmac->per_address; ++ } + } else { + sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ + } +@@ -906,10 +1074,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); +@@ -968,6 +1141,7 @@ + + sdmac->peripheral_type = data->peripheral_type; + sdmac->event_id0 = data->dma_request; ++ sdmac->event_id1 = data->dma_request2; + + clk_enable(sdmac->sdma->clk_ipg); + clk_enable(sdmac->sdma->clk_ahb); +@@ -1005,58 +1179,177 @@ + + 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); + } + +-static struct dma_async_tx_descriptor *sdma_prep_slave_sg( +- struct dma_chan *chan, struct scatterlist *sgl, +- unsigned int sg_len, enum dma_transfer_direction direction, +- unsigned long flags, void *context) ++static int sdma_transfer_init(struct sdma_channel *sdmac, ++ enum dma_transfer_direction direction) ++{ ++ int ret = 0; ++ ++ sdmac->status = DMA_IN_PROGRESS; ++ sdmac->buf_tail = 0; ++ sdmac->flags = 0; ++ sdmac->direction = direction; ++ ++ ret = sdma_load_context(sdmac); ++ if (ret) ++ return ret; ++ ++ sdmac->chn_count = 0; ++ ++ return ret; ++} ++ ++static int check_bd_buswidth(struct sdma_buffer_descriptor *bd, ++ struct sdma_channel *sdmac, int count, ++ dma_addr_t dma_dst, dma_addr_t dma_src) ++{ ++ int ret = 0; ++ ++ switch (sdmac->word_size) { ++ case DMA_SLAVE_BUSWIDTH_4_BYTES: ++ bd->mode.command = 0; ++ if ((count | dma_dst | dma_src) & 3) ++ ret = -EINVAL; ++ break; ++ case DMA_SLAVE_BUSWIDTH_2_BYTES: ++ bd->mode.command = 2; ++ if ((count | dma_dst | dma_src) & 1) ++ ret = -EINVAL; ++ break; ++ case DMA_SLAVE_BUSWIDTH_1_BYTE: ++ bd->mode.command = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static struct dma_async_tx_descriptor *sdma_prep_memcpy( ++ struct dma_chan *chan, dma_addr_t dma_dst, ++ dma_addr_t dma_src, size_t len, unsigned long flags) + { + struct sdma_channel *sdmac = to_sdma_chan(chan); + struct sdma_engine *sdma = sdmac->sdma; +- int ret, i, count; + int channel = sdmac->channel; +- struct scatterlist *sg; ++ size_t count; ++ int i = 0, param; ++ struct sdma_buffer_descriptor *bd; + +- if (sdmac->status == DMA_IN_PROGRESS) ++ if (!chan || !len || sdmac->status == DMA_IN_PROGRESS) + return NULL; +- sdmac->status = DMA_IN_PROGRESS; + +- sdmac->flags = 0; +- +- sdmac->buf_tail = 0; ++ if (len >= NUM_BD * SDMA_BD_MAX_CNT) { ++ dev_err(sdma->dev, "channel%d: maximum bytes exceeded:%zu > %d\n", ++ channel, len, NUM_BD * SDMA_BD_MAX_CNT); ++ goto err_out; ++ } + +- dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n", +- sg_len, channel); ++ dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n", ++ &dma_src, &dma_dst, len, channel); + +- sdmac->direction = direction; +- ret = sdma_load_context(sdmac); +- if (ret) ++ if (sdma_transfer_init(sdmac, DMA_MEM_TO_MEM)) + goto err_out; + +- if (sg_len > NUM_BD) { ++ do { ++ count = min_t(size_t, len, SDMA_BD_MAX_CNT); ++ bd = &sdmac->bd[i]; ++ bd->buffer_addr = dma_src; ++ bd->ext_buffer_addr = dma_dst; ++ bd->mode.count = count; ++ ++ if (check_bd_buswidth(bd, sdmac, count, dma_dst, dma_src)) ++ goto err_out; ++ ++ dma_src += count; ++ dma_dst += count; ++ len -= count; ++ i++; ++ ++ param = BD_DONE | BD_EXTD | BD_CONT; ++ /* last bd */ ++ if (!len) { ++ param |= BD_INTR; ++ param |= BD_LAST; ++ param &= ~BD_CONT; ++ } ++ ++ dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%u %s%s\n", ++ i, count, bd->buffer_addr, ++ param & BD_WRAP ? "wrap" : "", ++ param & BD_INTR ? " intr" : ""); ++ ++ bd->mode.status = param; ++ sdmac->chn_count += count; ++ } while (len); ++ ++ sdmac->num_bd = i; ++ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; ++ ++ return &sdmac->desc; ++err_out: ++ sdmac->status = DMA_ERROR; ++ return NULL; ++} ++ ++/* ++ * Please ensure dst_nents no smaller than src_nents , also every sg_len of ++ * dst_sg node no smaller than src_sg. To simply things, please use the same ++ * size of dst_sg as src_sg. ++ */ ++static struct dma_async_tx_descriptor *sdma_prep_sg( ++ struct dma_chan *chan, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents, ++ enum dma_transfer_direction direction) ++{ ++ struct sdma_channel *sdmac = to_sdma_chan(chan); ++ struct sdma_engine *sdma = sdmac->sdma; ++ int ret, i, count; ++ int channel = sdmac->channel; ++ struct scatterlist *sg_src = src_sg, *sg_dst = dst_sg; ++ ++ if (sdmac->status == DMA_IN_PROGRESS) ++ return NULL; ++ ++ dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n", ++ src_nents, channel); ++ ++ if (src_nents > NUM_BD) { + dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", +- channel, sg_len, NUM_BD); ++ channel, src_nents, NUM_BD); + ret = -EINVAL; + goto err_out; + } + +- sdmac->chn_count = 0; +- for_each_sg(sgl, sg, sg_len, i) { ++ if (sdma_transfer_init(sdmac, direction)) ++ goto err_out; ++ ++ for_each_sg(src_sg, sg_src, src_nents, i) { + struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; + int param; + +- bd->buffer_addr = sg->dma_address; ++ bd->buffer_addr = sg_src->dma_address; ++ ++ if (direction == DMA_MEM_TO_MEM) { ++ BUG_ON(!sg_dst); ++ bd->ext_buffer_addr = sg_dst->dma_address; ++ } + +- count = sg_dma_len(sg); ++ count = sg_dma_len(sg_src); + +- if (count > 0xffff) { ++ if (count > SDMA_BD_MAX_CNT) { + dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n", +- channel, count, 0xffff); ++ channel, count, SDMA_BD_MAX_CNT); + ret = -EINVAL; + goto err_out; + } +@@ -1064,46 +1357,35 @@ + bd->mode.count = count; + sdmac->chn_count += count; + +- if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) { +- ret = -EINVAL; ++ if (direction == DMA_MEM_TO_MEM) ++ ret = check_bd_buswidth(bd, sdmac, count, ++ sg_dst->dma_address, ++ sg_src->dma_address); ++ else ++ ret = check_bd_buswidth(bd, sdmac, count, 0, ++ sg_src->dma_address); ++ if (ret) + goto err_out; +- } +- +- switch (sdmac->word_size) { +- case DMA_SLAVE_BUSWIDTH_4_BYTES: +- bd->mode.command = 0; +- if (count & 3 || sg->dma_address & 3) +- return NULL; +- break; +- case DMA_SLAVE_BUSWIDTH_2_BYTES: +- bd->mode.command = 2; +- if (count & 1 || sg->dma_address & 1) +- return NULL; +- break; +- case DMA_SLAVE_BUSWIDTH_1_BYTE: +- bd->mode.command = 1; +- break; +- default: +- return NULL; +- } + + param = BD_DONE | BD_EXTD | BD_CONT; + +- if (i + 1 == sg_len) { ++ if (i + 1 == src_nents) { + param |= BD_INTR; + param |= BD_LAST; + param &= ~BD_CONT; + } + +- dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n", +- i, count, (u64)sg->dma_address, ++ dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%pad %s%s\n", ++ i, count, &sg_src->dma_address, + param & BD_WRAP ? "wrap" : "", + param & BD_INTR ? " intr" : ""); + + bd->mode.status = param; ++ if (direction == DMA_MEM_TO_MEM) ++ sg_dst = sg_next(sg_dst); + } + +- sdmac->num_bd = sg_len; ++ sdmac->num_bd = src_nents; + sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; + + return &sdmac->desc; +@@ -1112,6 +1394,24 @@ + return NULL; + } + ++static struct dma_async_tx_descriptor *sdma_prep_memcpy_sg( ++ struct dma_chan *chan, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents, ++ unsigned long flags) ++{ ++ return sdma_prep_sg(chan, dst_sg, dst_nents, src_sg, src_nents, ++ DMA_MEM_TO_MEM); ++} ++ ++static struct dma_async_tx_descriptor *sdma_prep_slave_sg( ++ struct dma_chan *chan, struct scatterlist *sgl, ++ unsigned int sg_len, enum dma_transfer_direction direction, ++ unsigned long flags, void *context) ++{ ++ return sdma_prep_sg(chan, NULL, 0, sgl, sg_len, direction); ++} ++ + static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, +@@ -1119,9 +1419,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,6 +1431,7 @@ + sdmac->status = DMA_IN_PROGRESS; + + sdmac->buf_tail = 0; ++ sdmac->period_len = period_len; + + sdmac->flags |= IMX_DMA_SG_LOOP; + sdmac->direction = direction; +@@ -1138,18 +1439,26 @@ + if (ret) + goto err_out; + ++ if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) ++ return &sdmac->desc; ++ else ++ num_periods = buf_len / period_len; ++ + 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); + goto err_out; + } + +- if (period_len > 0xffff) { +- dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n", +- channel, period_len, 0xffff); ++ if (period_len > SDMA_BD_MAX_CNT) { ++ dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n", ++ channel, period_len, SDMA_BD_MAX_CNT); + goto err_out; + } + ++ if (sdmac->peripheral_type == IMX_DMATYPE_UART) ++ sdmac->chn_count = period_len; ++ + while (buf < buf_len) { + struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; + int param; +@@ -1169,8 +1478,8 @@ + if (i + 1 == num_periods) + param |= BD_WRAP; + +- dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n", +- i, period_len, (u64)dma_addr, ++ dev_dbg(sdma->dev, "entry %d: count: %d dma: %pad %s%s\n", ++ i, period_len, &dma_addr, + param & BD_WRAP ? "wrap" : "", + param & BD_INTR ? " intr" : ""); + +@@ -1207,12 +1516,27 @@ + 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_DEV_TO_DEV) { ++ sdmac->per_address = dmaengine_cfg->src_addr; ++ sdmac->per_address2 = dmaengine_cfg->dst_addr; ++ sdmac->watermark_level = ++ dmaengine_cfg->src_maxburst & 0xff; ++ sdmac->watermark_level |= ++ (dmaengine_cfg->dst_maxburst & 0xff) << 16; ++ sdmac->word_size = dmaengine_cfg->dst_addr_width; ++ } 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; ++ } else if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) { ++ sdmac->per_address = dmaengine_cfg->src_addr; ++ sdmac->per_address2 = dmaengine_cfg->dst_addr; ++ sdmac->watermark_level = 0; ++ } else if (dmaengine_cfg->direction == DMA_MEM_TO_MEM) { ++ sdmac->word_size = dmaengine_cfg->dst_addr_width; + } ++ + sdmac->direction = dmaengine_cfg->direction; + return sdma_config_channel(sdmac); + default: +@@ -1227,9 +1551,20 @@ + struct dma_tx_state *txstate) + { + struct sdma_channel *sdmac = to_sdma_chan(chan); ++ u32 residue; ++ ++ /* ++ * For uart rx data may not receive fully, use old chn_real_count to ++ * know the real rx count. ++ */ ++ if ((sdmac->flags & IMX_DMA_SG_LOOP) && ++ (sdmac->peripheral_type != IMX_DMATYPE_UART)) ++ 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; + } +@@ -1245,6 +1580,7 @@ + + #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 + #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 ++#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 41 + + static void sdma_add_scripts(struct sdma_engine *sdma, + const struct sdma_script_start_addrs *addr) +@@ -1290,6 +1626,9 @@ + case 2: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; + break; ++ case 3: ++ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3; ++ break; + default: + dev_err(sdma->dev, "unknown firmware version\n"); + goto err_firmware; +@@ -1317,7 +1656,73 @@ + release_firmware(fw); + } + +-static int __init sdma_get_firmware(struct sdma_engine *sdma, ++#define EVENT_REMAP_CELLS 3 ++ ++static int __init sdma_event_remap(struct sdma_engine *sdma) ++{ ++ struct device_node *np = sdma->dev->of_node; ++ struct device_node *gpr_np = of_parse_phandle(np, "gpr", 0); ++ struct property *event_remap; ++ struct regmap *gpr; ++ char propname[] = "fsl,sdma-event-remap"; ++ u32 reg, val, shift, num_map, i; ++ int ret = 0; ++ ++ if (IS_ERR(np) || IS_ERR(gpr_np)) ++ goto out; ++ ++ event_remap = of_find_property(np, propname, NULL); ++ num_map = event_remap ? (event_remap->length / sizeof(u32)) : 0; ++ if (!num_map) { ++ dev_warn(sdma->dev, "no event needs to be remapped\n"); ++ goto out; ++ } else if (num_map % EVENT_REMAP_CELLS) { ++ dev_err(sdma->dev, "the property %s must modulo %d\n", ++ propname, EVENT_REMAP_CELLS); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ gpr = syscon_node_to_regmap(gpr_np); ++ if (IS_ERR(gpr)) { ++ dev_err(sdma->dev, "failed to get gpr regmap\n"); ++ ret = PTR_ERR(gpr); ++ goto out; ++ } ++ ++ for (i = 0; i < num_map; i += EVENT_REMAP_CELLS) { ++ ret = of_property_read_u32_index(np, propname, i, ®); ++ if (ret) { ++ dev_err(sdma->dev, "failed to read property %s index %d\n", ++ propname, i); ++ goto out; ++ } ++ ++ ret = of_property_read_u32_index(np, propname, i + 1, &shift); ++ if (ret) { ++ dev_err(sdma->dev, "failed to read property %s index %d\n", ++ propname, i + 1); ++ goto out; ++ } ++ ++ ret = of_property_read_u32_index(np, propname, i + 2, &val); ++ if (ret) { ++ dev_err(sdma->dev, "failed to read property %s index %d\n", ++ propname, i + 2); ++ goto out; ++ } ++ ++ regmap_update_bits(gpr, reg, BIT(shift), val << shift); ++ } ++ ++out: ++ if (!IS_ERR(gpr_np)) ++ of_node_put(gpr_np); ++ ++ return ret; ++} ++ ++static int sdma_get_firmware(struct sdma_engine *sdma, + const char *fw_name) + { + int ret; +@@ -1331,7 +1736,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 +1745,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 + +@@ -1402,12 +1810,14 @@ + + static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param) + { ++ struct sdma_channel *sdmac = to_sdma_chan(chan); + struct imx_dma_data *data = fn_param; + + if (!imx_dma_is_general_purpose(chan)) + return false; + +- chan->private = data; ++ sdmac->data = *data; ++ chan->private = &sdmac->data; + + return true; + } +@@ -1426,6 +1836,15 @@ + data.peripheral_type = dma_spec->args[1]; + data.priority = dma_spec->args[2]; + ++ /* ++ * init dma_request2 to zero, which is not used by the dts. ++ * For P2P, dma_request2 is init from dma_request_channel(), ++ * chan->private will point to the imx_dma_data, and in ++ * device_alloc_chan_resources(), imx_dma_data.dma_request2 will ++ * be set to sdmac->event_id1. ++ */ ++ data.dma_request2 = 0; ++ + return dma_request_channel(mask, sdma_filter_fn, &data); + } + +@@ -1517,6 +1936,7 @@ + + dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask); + dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask); ++ dma_cap_set(DMA_MEMCPY, sdma->dma_device.cap_mask); + + INIT_LIST_HEAD(&sdma->dma_device.channels); + /* Initialize channel parameters */ +@@ -1542,10 +1962,19 @@ + &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; + ++ ret = sdma_event_remap(sdma); ++ if (ret) ++ goto err_init; ++ + if (sdma->drvdata->script_addrs) + sdma_add_scripts(sdma, sdma->drvdata->script_addrs); + if (pdata && pdata->script_addrs) +@@ -1571,6 +2000,7 @@ + dev_warn(&pdev->dev, "failed to get firmware from device tree\n"); + } + } ++ sdma->fw_name = fw_name; + + sdma->dma_device.dev = &pdev->dev; + +@@ -1579,6 +2009,8 @@ + sdma->dma_device.device_tx_status = sdma_tx_status; + sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg; + sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; ++ sdma->dma_device.device_prep_dma_memcpy = sdma_prep_memcpy; ++ sdma->dma_device.device_prep_dma_sg = sdma_prep_memcpy_sg; + sdma->dma_device.device_control = sdma_control; + sdma->dma_device.device_issue_pending = sdma_issue_pending; + sdma->dma_device.dev->dma_parms = &sdma->dma_parms; +@@ -1598,6 +2030,7 @@ + } + } + ++ platform_set_drvdata(pdev, sdma); + dev_info(sdma->dev, "initialized\n"); + + return 0; +@@ -1624,10 +2057,94 @@ + return -EBUSY; + } + ++#ifdef CONFIG_PM_SLEEP ++static int sdma_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct sdma_engine *sdma = platform_get_drvdata(pdev); ++ int i; ++ ++ /* Do nothing if not i.MX6SX */ ++ if (sdma->drvdata != &sdma_imx6sx) ++ return 0; ++ ++ clk_enable(sdma->clk_ipg); ++ clk_enable(sdma->clk_ahb); ++ /* save regs */ ++ for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) { ++ /* ++ * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are ++ * reserved and can't be touched. Skip these regs. ++ */ ++ if (i > SDMA_XTRIG_CONF2 / 4) ++ sdma->save_regs[i] = readl_relaxed(sdma->regs + ++ MXC_SDMA_RESERVED_REG ++ + 4 * i); ++ else ++ sdma->save_regs[i] = readl_relaxed(sdma->regs + 4 * i); ++ } ++ ++ clk_disable(sdma->clk_ipg); ++ clk_disable(sdma->clk_ahb); ++ ++ return 0; ++} ++ ++static int sdma_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct sdma_engine *sdma = platform_get_drvdata(pdev); ++ int i, ret; ++ ++ /* Do nothing if not i.MX6SX */ ++ if (sdma->drvdata != &sdma_imx6sx) ++ return 0; ++ ++ clk_enable(sdma->clk_ipg); ++ clk_enable(sdma->clk_ahb); ++ /* Do nothing if mega/fast mix not turned off */ ++ if (readl_relaxed(sdma->regs + SDMA_H_C0PTR)) { ++ clk_disable(sdma->clk_ipg); ++ clk_disable(sdma->clk_ahb); ++ return 0; ++ } ++ /* restore regs and load firmware */ ++ for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) { ++ /* ++ * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are ++ * reserved and can't be touched. Skip these regs. ++ */ ++ if (i > SDMA_XTRIG_CONF2 / 4) ++ writel_relaxed(sdma->save_regs[i], sdma->regs + ++ MXC_SDMA_RESERVED_REG + 4 * i); ++ else ++ writel_relaxed(sdma->save_regs[i] , sdma->regs + 4 * i); ++ } ++ ++ /* prepare priority for channel0 to start */ ++ sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_DEFAULT_PRIORITY); ++ clk_disable(sdma->clk_ipg); ++ clk_disable(sdma->clk_ahb); ++ ++ ret = sdma_get_firmware(sdma, sdma->fw_name); ++ if (ret) { ++ dev_warn(&pdev->dev, "failed to get firware\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops sdma_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(sdma_suspend, sdma_resume) ++}; ++ + static struct platform_driver sdma_driver = { + .driver = { + .name = "imx-sdma", + .of_match_table = sdma_dt_ids, ++ .pm = &sdma_pm_ops, + }, + .id_table = sdma_devtypes, + .remove = sdma_remove, +diff -Nur linux-3.14.72.orig/drivers/dma/Kconfig linux-3.14.72/drivers/dma/Kconfig +--- linux-3.14.72.orig/drivers/dma/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/dma/Kconfig 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/dma/Makefile linux-3.14.72/drivers/dma/Makefile +--- linux-3.14.72.orig/drivers/dma/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/dma/Makefile 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/dma/mxs-dma.c linux-3.14.72/drivers/dma/mxs-dma.c +--- linux-3.14.72.orig/drivers/dma/mxs-dma.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/dma/mxs-dma.c 2016-06-19 22:11:55.121152080 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Refer to drivers/dma/imx-sdma.c + * +@@ -28,7 +28,7 @@ + #include + #include + #include +- ++#include + #include + + #include "dmaengine.h" +@@ -710,7 +710,7 @@ + mxs_dma_enable_chan(mxs_chan); + } + +-static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma) ++static int mxs_dma_init(struct mxs_dma_engine *mxs_dma) + { + int ret; + +@@ -852,6 +852,7 @@ + + mxs_dma->pdev = pdev; + mxs_dma->dma_device.dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, mxs_dma); + + /* mxs_dma gets 65535 bytes maximum sg size */ + mxs_dma->dma_device.dev->dma_parms = &mxs_dma->dma_parms; +@@ -883,9 +884,56 @@ + return 0; + } + ++static int mxs_dma_runtime_suspend(struct device *dev) ++{ ++ struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev); ++ ++ clk_disable(mxs_dma->clk); ++ return 0; ++} ++ ++static int mxs_dma_runtime_resume(struct device *dev) ++{ ++ struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_enable(mxs_dma->clk); ++ if (ret < 0) { ++ dev_err(dev, "clk_enable failed: %d\n", ret); ++ return ret; ++ } ++ return 0; ++} ++ ++static int mxs_dma_pm_suspend(struct device *dev) ++{ ++ /* ++ * We do not save any registers here, since the gpmi will release its ++ * DMA channel. ++ */ ++ return 0; ++} ++ ++static int mxs_dma_pm_resume(struct device *dev) ++{ ++ struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = mxs_dma_init(mxs_dma); ++ if (ret) ++ return ret; ++ return 0; ++} ++ ++static const struct dev_pm_ops mxs_dma_pm_ops = { ++ SET_RUNTIME_PM_OPS(mxs_dma_runtime_suspend, mxs_dma_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(mxs_dma_pm_suspend, mxs_dma_pm_resume) ++}; ++ + static struct platform_driver mxs_dma_driver = { + .driver = { + .name = "mxs-dma", ++ .pm = &mxs_dma_pm_ops, + .of_match_table = mxs_dma_dt_ids, + }, + .id_table = mxs_dma_ids, +diff -Nur linux-3.14.72.orig/drivers/dma/pxp/Makefile linux-3.14.72/drivers/dma/pxp/Makefile +--- linux-3.14.72.orig/drivers/dma/pxp/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/dma/pxp/Makefile 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/dma/pxp/pxp_device.c linux-3.14.72/drivers/dma/pxp/pxp_device.c +--- linux-3.14.72.orig/drivers/dma/pxp/pxp_device.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/dma/pxp/pxp_device.c 2016-06-19 22:11:55.121152080 +0200 +@@ -0,0 +1,762 @@ ++/* ++ * 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) ++ 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.72.orig/drivers/dma/pxp/pxp_dma_v2.c linux-3.14.72/drivers/dma/pxp/pxp_dma_v2.c +--- linux-3.14.72.orig/drivers/dma/pxp/pxp_dma_v2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/dma/pxp/pxp_dma_v2.c 2016-06-19 22:11:55.121152080 +0200 +@@ -0,0 +1,1844 @@ ++/* ++ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++/* ++ * Based on STMP378X PxP driver ++ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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; ++ struct clk *clk_disp_axi; /* may exist on some SoC for gating */ ++ 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 ++ ++/* ++ * 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_VUY444) | ++ (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_soft_reset(struct pxps *pxp) ++{ ++ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_CLR); ++ __raw_writel(BM_PXP_CTRL_CLKGATE, pxp->base + HW_PXP_CTRL_CLR); ++ ++ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_SET); ++ while (!(__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_CLKGATE)) ++ dev_dbg(pxp->dev, "%s: wait for clock gate off", __func__); ++ ++ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_CLR); ++ __raw_writel(BM_PXP_CTRL_CLKGATE, pxp->base + HW_PXP_CTRL_CLR); ++} ++ ++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_VUY444: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV1P444; ++ 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); ++ ++ /* 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; ++ struct pxp_proc_data *proc_data = &pxp_conf->proc_data; ++ ++ __raw_writel(out_params->paddr, pxp->base + HW_PXP_OUT_BUF); ++ ++ if (proc_data->rotate == 90 || proc_data->rotate == 270) ++ __raw_writel(BF_PXP_OUT_LRC_X(out_params->height - 1) | ++ BF_PXP_OUT_LRC_Y(out_params->width - 1), ++ pxp->base + HW_PXP_OUT_LRC); ++ else ++ __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); ++ __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; ++ struct pxp_layer_param *out_params = &pxp_conf->out_param; ++ u32 s0param_ulc, s0param_lrc; ++ ++ /* 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 { ++ switch (proc_data->rotate) { ++ case 0: ++ s0param_ulc = BF_PXP_OUT_PS_ULC_X(proc_data->drect.left); ++ s0param_ulc |= BF_PXP_OUT_PS_ULC_Y(proc_data->drect.top); ++ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.width - 1); ++ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.height - 1); ++ break; ++ case 90: ++ s0param_ulc = BF_PXP_OUT_PS_ULC_Y(out_params->width - (proc_data->drect.left + proc_data->drect.width)); ++ s0param_ulc |= BF_PXP_OUT_PS_ULC_X(proc_data->drect.top); ++ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.height - 1); ++ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.width - 1); ++ break; ++ case 180: ++ s0param_ulc = BF_PXP_OUT_PS_ULC_X(out_params->width - (proc_data->drect.left + proc_data->drect.width)); ++ s0param_ulc |= BF_PXP_OUT_PS_ULC_Y(out_params->height - (proc_data->drect.top + proc_data->drect.height)); ++ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.width - 1); ++ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.height - 1); ++ break; ++ case 270: ++ s0param_ulc = BF_PXP_OUT_PS_ULC_X(out_params->height - (proc_data->drect.top + proc_data->drect.height)); ++ s0param_ulc |= BF_PXP_OUT_PS_ULC_Y(proc_data->drect.left); ++ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.height - 1); ++ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.width - 1); ++ break; ++ default: ++ return; ++ } ++ __raw_writel(s0param_ulc, pxp->base + HW_PXP_OUT_PS_ULC); ++ __raw_writel(s0param_lrc, pxp->base + HW_PXP_OUT_PS_LRC); ++ } ++ ++ /* Since user apps always pass the rotated drect ++ * to this driver, we need to first swap the width ++ * and height which is used to calculate the scale ++ * factors later. ++ */ ++ if (proc_data->rotate == 90 || proc_data->rotate == 270) { ++ int temp; ++ temp = proc_data->drect.width; ++ proc_data->drect.width = proc_data->drect.height; ++ proc_data->drect.height = temp; ++ } ++} ++ ++/* 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; ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *s0_params = &pxp_conf->s0_param; ++ ++ proc_data->scaling = 1; ++ decx = proc_data->srect.width / proc_data->drect.width; ++ decy = proc_data->srect.height / proc_data->drect.height; ++ if (decx > 1) { ++ 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 { ++ if (!is_yuv(s0_params->pixel_fmt) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_GREY) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_GY04) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_VUY444)) { ++ if ((proc_data->srect.width > 1) && ++ (proc_data->drect.width > 1)) ++ xscale = (proc_data->srect.width - 1) * 0x1000 / ++ (proc_data->drect.width - 1); ++ else ++ xscale = proc_data->srect.width * 0x1000 / ++ proc_data->drect.width; ++ } else { ++ if ((proc_data->srect.width > 2) && ++ (proc_data->drect.width > 1)) ++ xscale = (proc_data->srect.width - 2) * 0x1000 / ++ (proc_data->drect.width - 1); ++ else ++ xscale = proc_data->srect.width * 0x1000 / ++ proc_data->drect.width; ++ } ++ } ++ if (decy > 1) { ++ 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 { ++ if ((proc_data->srect.height > 1) && ++ (proc_data->drect.height > 1)) ++ yscale = (proc_data->srect.height - 1) * 0x1000 / ++ (proc_data->drect.height - 1); ++ 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); ++ ++ 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 || ++ s0_params->pixel_fmt == PXP_PIX_FMT_VUY444) ++ __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; ++ } ++ ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ pm_runtime_get_sync(pxp->dev); ++ ++ if (pxp->clk_disp_axi) ++ clk_prepare_enable(pxp->clk_disp_axi); ++ 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); ++ if (pxp->clk_disp_axi) ++ clk_disable_unprepare(pxp->clk_disp_axi); ++ pxp->clk_stat = CLK_STAT_OFF; ++ } else ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ ++ pm_runtime_put_sync_suspend(pxp->dev); ++ ++ mutex_unlock(&pxp->clk_mutex); ++ ++ release_bus_freq(BUS_FREQ_HIGH); ++} ++ ++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; ++ ++ memset(&pxp->pxp_conf_state.s0_param, 0, sizeof(struct pxp_layer_param)); ++ memset(&pxp->pxp_conf_state.out_param, 0, sizeof(struct pxp_layer_param)); ++ memset(pxp->pxp_conf_state.ol_param, 0, sizeof(struct pxp_layer_param) * 8); ++ memset(&pxp->pxp_conf_state.proc_data, 0, sizeof(struct pxp_proc_data)); ++ /* 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); ++ ++ /* set the SFTRST bit to be 1 to reset ++ * the PXP block to its default state. ++ */ ++ pxp_soft_reset(pxp); ++ ++ 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_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; ++ ++ set_freezable(); ++ ++ while (!kthread_should_stop()) { ++ int ret; ++ ret = wait_event_freezable(pxp->thread_waitq, ++ has_pending_task(pxp, pending) || ++ kthread_should_stop()); ++ if (ret < 0) ++ 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_disp_axi = devm_clk_get(&pdev->dev, "disp-axi"); ++ if (IS_ERR(pxp->clk_disp_axi)) ++ pxp->clk_disp_axi = NULL; ++ pxp->clk = devm_clk_get(&pdev->dev, "pxp-axi"); ++ ++ 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); ++ pxp_clk_enable(pxp); ++ dump_pxp_reg(pxp); ++ pxp_clk_disable(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; ++ ++ init_waitqueue_head(&pxp->thread_waitq); ++ /* 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; ++ } ++ 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(); ++ ++ pm_runtime_enable(pxp->dev); ++ ++exit: ++ if (err) ++ dev_err(&pdev->dev, "Exiting (unsuccessfully) pxp_probe()\n"); ++ return err; ++} ++ ++static int pxp_remove(struct platform_device *pdev) ++{ ++ struct pxps *pxp = platform_get_drvdata(pdev); ++ ++ unregister_pxp_device(); ++ 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); ++ if (pxp->clk_disp_axi) ++ clk_disable_unprepare(pxp->clk_disp_axi); ++ device_remove_file(&pdev->dev, &dev_attr_clk_off_timeout); ++ device_remove_file(&pdev->dev, &dev_attr_block_size); ++ dma_async_device_unregister(&(pxp->pxp_dma.dma)); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int pxp_suspend(struct device *dev) ++{ ++ struct pxps *pxp = dev_get_drvdata(dev); ++ ++ pxp_clk_enable(pxp); ++ while (__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_ENABLE) ++ ; ++ ++ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL); ++ pxp_clk_disable(pxp); ++ ++ return 0; ++} ++ ++static int pxp_resume(struct device *dev) ++{ ++ struct pxps *pxp = dev_get_drvdata(dev); ++ ++ pxp_clk_enable(pxp); ++ /* Pull PxP out of reset */ ++ __raw_writel(0, pxp->base + HW_PXP_CTRL); ++ pxp_clk_disable(pxp); ++ ++ return 0; ++} ++#else ++#define pxp_suspend NULL ++#define pxp_resume NULL ++#endif ++ ++#ifdef CONFIG_PM_RUNTIME ++static int pxp_runtime_suspend(struct device *dev) ++{ ++ dev_dbg(dev, "pxp busfreq high release.\n"); ++ return 0; ++} ++ ++static int pxp_runtime_resume(struct device *dev) ++{ ++ dev_dbg(dev, "pxp busfreq high request.\n"); ++ return 0; ++} ++#else ++#define pxp_runtime_suspend NULL ++#define pxp_runtime_resume NULL ++#endif ++ ++static const struct dev_pm_ops pxp_pm_ops = { ++ SET_RUNTIME_PM_OPS(pxp_runtime_suspend, pxp_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(pxp_suspend, pxp_resume) ++}; ++ ++static struct platform_driver pxp_driver = { ++ .driver = { ++ .name = "imx-pxp", ++ .of_match_table = of_match_ptr(imx_pxpdma_dt_ids), ++ .pm = &pxp_pm_ops, ++ }, ++ .probe = pxp_probe, ++ .remove = pxp_remove, ++}; ++ ++module_platform_driver(pxp_driver); ++ ++ ++MODULE_DESCRIPTION("i.MX PxP driver"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/dma/pxp/regs-pxp_v2.h linux-3.14.72/drivers/dma/pxp/regs-pxp_v2.h +--- linux-3.14.72.orig/drivers/dma/pxp/regs-pxp_v2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/dma/pxp/regs-pxp_v2.h 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/gpio/gpio-generic.c linux-3.14.72/drivers/gpio/gpio-generic.c +--- linux-3.14.72.orig/drivers/gpio/gpio-generic.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/gpio/gpio-generic.c 2016-06-19 22:11:55.121152080 +0200 +@@ -139,7 +139,7 @@ + { + struct bgpio_chip *bgc = to_bgpio_chip(gc); + +- return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio); ++ return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); + } + + static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +diff -Nur linux-3.14.72.orig/drivers/gpio/gpio-pca953x.c linux-3.14.72/drivers/gpio/gpio-pca953x.c +--- linux-3.14.72.orig/drivers/gpio/gpio-pca953x.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/gpio/gpio-pca953x.c 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/gpu/drm/drm_platform.c linux-3.14.72/drivers/gpu/drm/drm_platform.c +--- linux-3.14.72.orig/drivers/gpu/drm/drm_platform.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/gpu/drm/drm_platform.c 2016-06-19 22:11:55.121152080 +0200 +@@ -53,6 +53,14 @@ + + dev->platformdev = platdev; + ++ /* ++ * If drvdata is not used by platform driver, let's set drm_device ++ * pointer into it. We take this as the default usage of drvdata, ++ * and platform driver is free to overwrite it later as needed. ++ */ ++ if (platform_get_drvdata(platdev) == NULL) ++ platform_set_drvdata(platdev, dev); ++ + ret = drm_dev_register(dev, 0); + if (ret) + goto err_free; +diff -Nur linux-3.14.72.orig/drivers/gpu/drm/Kconfig linux-3.14.72/drivers/gpu/drm/Kconfig +--- linux-3.14.72.orig/drivers/gpu/drm/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/gpu/drm/Kconfig 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/gpu/drm/Makefile linux-3.14.72/drivers/gpu/drm/Makefile +--- linux-3.14.72.orig/drivers/gpu/drm/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/gpu/drm/Makefile 2016-06-19 22:11:55.121152080 +0200 +@@ -35,6 +35,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.72.orig/drivers/gpu/drm/vivante/Makefile linux-3.14.72/drivers/gpu/drm/vivante/Makefile +--- linux-3.14.72.orig/drivers/gpu/drm/vivante/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/drm/vivante/Makefile 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/gpu/drm/vivante/vivante_drv.c linux-3.14.72/drivers/gpu/drm/vivante/vivante_drv.c +--- linux-3.14.72.orig/drivers/gpu/drm/vivante/vivante_drv.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/drm/vivante/vivante_drv.c 2016-06-19 22:11:55.121152080 +0200 +@@ -0,0 +1,110 @@ ++/**************************************************************************** ++* ++* 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) { ++ /* The drvdata is set in drm_get_platform_dev() */ ++ drm_put_dev(platform_get_drvdata(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.72.orig/drivers/gpu/drm/vivante/vivante_drv.h linux-3.14.72/drivers/gpu/drm/vivante/vivante_drv.h +--- linux-3.14.72.orig/drivers/gpu/drm/vivante/vivante_drv.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/drm/vivante/vivante_drv.h 2016-06-19 22:11:55.121152080 +0200 +@@ -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.72.orig/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h linux-3.14.72/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h +--- linux-3.14.72.orig/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h 2016-06-19 22:11:55.121152080 +0200 +@@ -0,0 +1,34 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++extern gceSTATUS ++_DefaultAlloctorInit( ++ IN gckOS Os, ++ OUT gckALLOCATOR * Allocator ++ ); ++ ++gcsALLOCATOR_DESC allocatorArray[] = ++{ ++ /* Default allocator. */ ++ gcmkDEFINE_ALLOCATOR_DESC("default", _DefaultAlloctorInit), ++}; ++ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h linux-3.14.72/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h +--- linux-3.14.72.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h 2016-06-19 22:11:55.121152080 +0200 +@@ -0,0 +1,45 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++extern gceSTATUS ++_DefaultAlloctorInit( ++ IN gckOS Os, ++ OUT gckALLOCATOR * Allocator ++ ); ++ ++#if LINUX_CMA_FSL ++gceSTATUS ++_CMAFSLAlloctorInit( ++ IN gckOS Os, ++ OUT gckALLOCATOR * Allocator ++ ); ++#endif ++ ++gcsALLOCATOR_DESC allocatorArray[] = ++{ ++#if LINUX_CMA_FSL ++ gcmkDEFINE_ALLOCATOR_DESC("cmafsl", _CMAFSLAlloctorInit), ++#endif ++ /* Default allocator. */ ++ gcmkDEFINE_ALLOCATOR_DESC("default", _DefaultAlloctorInit), ++}; ++ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c linux-3.14.72/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c +--- linux-3.14.72.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c 2016-06-19 22:11:55.125151817 +0200 +@@ -0,0 +1,386 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++#include "gc_hal_kernel_allocator.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define _GC_OBJ_ZONE gcvZONE_OS ++ ++typedef struct _gcsCMA_PRIV * gcsCMA_PRIV_PTR; ++typedef struct _gcsCMA_PRIV { ++ gctUINT32 cmasize; ++} ++gcsCMA_PRIV; ++ ++struct mdl_cma_priv { ++ gctPOINTER kvaddr; ++ dma_addr_t physical; ++}; ++ ++int gc_cma_usage_show(struct seq_file* m, void* data) ++{ ++ gcsINFO_NODE *node = m->private; ++ gckALLOCATOR Allocator = node->device; ++ gcsCMA_PRIV_PTR priv = Allocator->privateData; ++ ++ seq_printf(m, "cma: %u bytes\n", priv->cmasize); ++ ++ return 0; ++} ++ ++static gcsINFO InfoList[] = ++{ ++ {"cmausage", gc_cma_usage_show}, ++}; ++ ++static void ++_DefaultAllocatorDebugfsInit( ++ IN gckALLOCATOR Allocator, ++ IN gckDEBUGFS_DIR Root ++ ) ++{ ++ gcmkVERIFY_OK( ++ gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "cma")); ++ ++ gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles( ++ &Allocator->debugfsDir, ++ InfoList, ++ gcmCOUNTOF(InfoList), ++ Allocator ++ )); ++} ++ ++static void ++_DefaultAllocatorDebugfsCleanup( ++ IN gckALLOCATOR Allocator ++ ) ++{ ++ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles( ++ &Allocator->debugfsDir, ++ InfoList, ++ gcmCOUNTOF(InfoList) ++ )); ++ ++ gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir); ++} ++ ++static gceSTATUS ++_CMAFSLAlloc( ++ IN gckALLOCATOR Allocator, ++ INOUT PLINUX_MDL Mdl, ++ IN gctSIZE_T NumPages, ++ IN gctUINT32 Flags ++ ) ++{ ++ gceSTATUS status; ++ gcsCMA_PRIV_PTR priv = (gcsCMA_PRIV_PTR)Allocator->privateData; ++ ++ struct mdl_cma_priv *mdl_priv=gcvNULL; ++ gckOS os = Allocator->os; ++ ++ gcmkHEADER_ARG("Mdl=%p NumPages=%d", Mdl, NumPages); ++ ++ gcmkONERROR(gckOS_Allocate(os, sizeof(struct mdl_cma_priv), (gctPOINTER *)&mdl_priv)); ++ mdl_priv->kvaddr = gcvNULL; ++ ++ mdl_priv->kvaddr = dma_alloc_writecombine(gcvNULL, ++ NumPages * PAGE_SIZE, ++ &mdl_priv->physical, ++ GFP_KERNEL | gcdNOWARN); ++ ++ if (mdl_priv->kvaddr == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ Mdl->priv = mdl_priv; ++ priv->cmasize += NumPages * PAGE_SIZE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if(mdl_priv) ++ gckOS_Free(os, mdl_priv); ++ gcmkFOOTER(); ++ return status; ++} ++ ++static void ++_CMAFSLFree( ++ IN gckALLOCATOR Allocator, ++ IN OUT PLINUX_MDL Mdl ++ ) ++{ ++ gckOS os = Allocator->os; ++ struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv; ++ gcsCMA_PRIV_PTR priv = (gcsCMA_PRIV_PTR)Allocator->privateData; ++ dma_free_writecombine(gcvNULL, ++ Mdl->numPages * PAGE_SIZE, ++ mdl_priv->kvaddr, ++ mdl_priv->physical); ++ gckOS_Free(os, mdl_priv); ++ priv->cmasize -= Mdl->numPages * PAGE_SIZE; ++} ++ ++gctINT ++_CMAFSLMapUser( ++ gckALLOCATOR Allocator, ++ PLINUX_MDL Mdl, ++ PLINUX_MDL_MAP MdlMap, ++ gctBOOL Cacheable ++ ) ++{ ++ ++ PLINUX_MDL mdl = Mdl; ++ PLINUX_MDL_MAP mdlMap = MdlMap; ++ struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv; ++ ++ gcmkHEADER_ARG("Allocator=%p Mdl=%p MdlMap=%p gctBOOL=%d", Allocator, Mdl, MdlMap, Cacheable); ++ ++ mdlMap->vmaAddr = (gctSTRING)vm_mmap(gcvNULL, ++ 0L, ++ mdl->numPages * PAGE_SIZE, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED, ++ 0); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): vmaAddr->0x%X for phys_addr->0x%X", ++ __FUNCTION__, __LINE__, ++ (gctUINT32)(gctUINTPTR_T)mdlMap->vmaAddr, ++ (gctUINT32)(gctUINTPTR_T)mdl ++ ); ++ ++ if (IS_ERR(mdlMap->vmaAddr)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): do_mmap_pgoff error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ down_write(¤t->mm->mmap_sem); ++ ++ mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); ++ ++ if (mdlMap->vma == gcvNULL) ++ { ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): find_vma error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_RESOURCES); ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++ /* Now map all the vmalloc pages to this user address. */ ++ if (mdl->contiguous) ++ { ++ /* map kernel memory to user space.. */ ++ if (dma_mmap_writecombine(gcvNULL, ++ mdlMap->vma, ++ mdl_priv->kvaddr, ++ mdl_priv->physical, ++ mdl->numPages * PAGE_SIZE) < 0) ++ { ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d): dma_mmap_attrs error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ } ++ else ++ { ++ gckOS_Print("incorrect mdl:conti%d\n",mdl->contiguous); ++ } ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++void ++_CMAUnmapUser( ++ IN gckALLOCATOR Allocator, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Size ++ ) ++{ ++ if (unlikely(current->mm == gcvNULL)) ++ { ++ /* Do nothing if process is exiting. */ ++ return; ++ } ++ ++ if (vm_munmap((unsigned long)Logical, Size) < 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d): vm_munmap failed", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++} ++ ++gceSTATUS ++_CMAMapKernel( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ OUT gctPOINTER *Logical ++ ) ++{ ++ struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv; ++ *Logical =mdl_priv->kvaddr; ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_CMAUnmapKernel( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical ++ ) ++{ ++ return gcvSTATUS_OK; ++} ++ ++extern gceSTATUS ++_DefaultLogicalToPhysical( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical, ++ IN gctUINT32 ProcessID, ++ OUT gctUINT32_PTR Physical ++ ); ++ ++extern gceSTATUS ++_DefaultCache( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical, ++ IN gctUINT32 Bytes, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++gceSTATUS ++_CMAPhysical( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctUINT32 Offset, ++ OUT gctUINT32_PTR Physical ++ ) ++{ ++ struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv; ++ gcmkASSERT(!Offset); ++ *Physical = mdl_priv->physical; ++ ++ return gcvSTATUS_OK; ++} ++ ++ ++extern void ++_DefaultAllocatorDestructor( ++ IN void* PrivateData ++ ); ++ ++/* Default allocator operations. */ ++gcsALLOCATOR_OPERATIONS CMAFSLAllocatorOperations = { ++ .Alloc = _CMAFSLAlloc, ++ .Free = _CMAFSLFree, ++ .MapUser = _CMAFSLMapUser, ++ .UnmapUser = _CMAUnmapUser, ++ .MapKernel = _CMAMapKernel, ++ .UnmapKernel = _CMAUnmapKernel, ++ .LogicalToPhysical = _DefaultLogicalToPhysical, ++ .Cache = _DefaultCache, ++ .Physical = _CMAPhysical, ++}; ++ ++/* Default allocator entry. */ ++gceSTATUS ++_CMAFSLAlloctorInit( ++ IN gckOS Os, ++ OUT gckALLOCATOR * Allocator ++ ) ++{ ++ gceSTATUS status; ++ gckALLOCATOR allocator; ++ gcsCMA_PRIV_PTR priv = gcvNULL; ++ ++ gcmkONERROR( ++ gckALLOCATOR_Construct(Os, &CMAFSLAllocatorOperations, &allocator)); ++ ++ priv = kzalloc(gcmSIZEOF(gcsCMA_PRIV), GFP_KERNEL | gcdNOWARN); ++ ++ if (!priv) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Register private data. */ ++ allocator->privateData = priv; ++ allocator->privateDataDestructor = _DefaultAllocatorDestructor; ++ ++ allocator->debugfsInit = _DefaultAllocatorDebugfsInit; ++ allocator->debugfsCleanup = _DefaultAllocatorDebugfsCleanup; ++ ++ allocator->capability = gcvALLOC_FLAG_CONTIGUOUS; ++ ++ *Allocator = allocator; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.c linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_context.c +--- linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_context.c 2016-06-19 22:11:55.125151817 +0200 +@@ -0,0 +1,2252 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal.h" ++#include "gc_hal_kernel.h" ++#include "gc_hal_kernel_context.h" ++#include "gc_hal_kernel_buffer.h" ++ ++/******************************************************************************\ ++******************************** Debugging Macro ******************************* ++\******************************************************************************/ ++ ++/* Zone used for header/footer. */ ++#define _GC_OBJ_ZONE gcvZONE_HARDWARE ++ ++ ++/******************************************************************************\ ++************************** Context State Buffer Helpers ************************ ++\******************************************************************************/ ++ ++#define _STATE(reg) \ ++ _State(\ ++ Context, index, \ ++ reg ## _Address >> 2, \ ++ reg ## _ResetValue, \ ++ reg ## _Count, \ ++ gcvFALSE, gcvFALSE \ ++ ) ++ ++#define _STATE_COUNT(reg, count) \ ++ _State(\ ++ Context, index, \ ++ reg ## _Address >> 2, \ ++ reg ## _ResetValue, \ ++ count, \ ++ gcvFALSE, gcvFALSE \ ++ ) ++ ++#define _STATE_COUNT_OFFSET(reg, offset, count) \ ++ _State(\ ++ Context, index, \ ++ (reg ## _Address >> 2) + offset, \ ++ reg ## _ResetValue, \ ++ count, \ ++ gcvFALSE, gcvFALSE \ ++ ) ++ ++#define _STATE_MIRROR_COUNT(reg, mirror, count) \ ++ _StateMirror(\ ++ Context, \ ++ reg ## _Address >> 2, \ ++ count, \ ++ mirror ## _Address >> 2 \ ++ ) ++ ++#define _STATE_HINT(reg) \ ++ _State(\ ++ Context, index, \ ++ reg ## _Address >> 2, \ ++ reg ## _ResetValue, \ ++ reg ## _Count, \ ++ gcvFALSE, gcvTRUE \ ++ ) ++ ++#define _STATE_HINT_BLOCK(reg, block, count) \ ++ _State(\ ++ Context, index, \ ++ (reg ## _Address >> 2) + (block << reg ## _BLK), \ ++ reg ## _ResetValue, \ ++ count, \ ++ gcvFALSE, gcvTRUE \ ++ ) ++ ++#define _STATE_COUNT_OFFSET_HINT(reg, offset, count) \ ++ _State(\ ++ Context, index, \ ++ (reg ## _Address >> 2) + offset, \ ++ reg ## _ResetValue, \ ++ count, \ ++ gcvFALSE, gcvTRUE \ ++ ) ++ ++#define _STATE_X(reg) \ ++ _State(\ ++ Context, index, \ ++ reg ## _Address >> 2, \ ++ reg ## _ResetValue, \ ++ reg ## _Count, \ ++ gcvTRUE, gcvFALSE \ ++ ) ++ ++#define _STATE_INIT_VALUE(reg, value) \ ++ _State(\ ++ Context, index, \ ++ reg ## _Address >> 2, \ ++ value, \ ++ reg ## _Count, \ ++ gcvFALSE, gcvFALSE \ ++ ) ++ ++#define _CLOSE_RANGE() \ ++ _TerminateStateBlock(Context, index) ++ ++#define _ENABLE(reg, field) \ ++ do \ ++ { \ ++ if (gcmVERIFYFIELDVALUE(data, reg, MASK_ ## field, ENABLED)) \ ++ { \ ++ enable |= gcmFIELDMASK(reg, field); \ ++ } \ ++ } \ ++ while (gcvFALSE) ++ ++#define _BLOCK_COUNT(reg) \ ++ ((reg ## _Count) >> (reg ## _BLK)) ++ ++ ++/******************************************************************************\ ++*********************** Support Functions and Definitions ********************** ++\******************************************************************************/ ++ ++#define gcdSTATE_MASK \ ++ (((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 | 0xC0FFEE & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))) ++ ++#if gcdENABLE_3D ++static gctUINT32 ++_TerminateStateBlock( ++ IN gckCONTEXT Context, ++ IN gctUINT32 Index ++ ) ++{ ++ gctUINT32_PTR buffer; ++ gctUINT32 align; ++ ++ /* Determine if we need alignment. */ ++ align = (Index & 1) ? 1 : 0; ++ ++ /* Address correct index. */ ++ buffer = (Context->buffer == gcvNULL) ++ ? gcvNULL ++ : Context->buffer->logical; ++ ++ /* Flush the current state block; make sure no pairing with the states ++ to follow happens. */ ++ if (align && (buffer != gcvNULL)) ++ { ++ buffer[Index] = 0xDEADDEAD; ++ } ++ ++ /* Reset last address. */ ++ Context->lastAddress = ~0U; ++ ++ /* Return alignment requirement. */ ++ return align; ++} ++#endif ++ ++ ++#if (gcdENABLE_3D || gcdENABLE_2D) ++static gctUINT32 ++_FlushPipe( ++ IN gckCONTEXT Context, ++ IN gctUINT32 Index, ++ IN gcePIPE_SELECT Pipe ++ ) ++{ ++ gctBOOL fcFlushStall; ++ gctUINT32 flushSlots; ++ gctBOOL iCacheInvalidate; ++ ++ fcFlushStall ++ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_FC_FLUSH_STALL); ++ ++ iCacheInvalidate ++ = ((((gctUINT32) (Context->hardware->identity.chipMinorFeatures3)) >> (0 ? 3:3) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))); ++ ++ flushSlots = 6; ++ ++ if (fcFlushStall) ++ { ++ /* Flush tile status cache. */ ++ flushSlots += 6; ++ } ++ ++ if (iCacheInvalidate) ++ { ++ flushSlots += 12; ++ } ++ ++ if (Context->buffer != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Address correct index. */ ++ buffer = Context->buffer->logical + Index; ++ ++ /* Flush the current pipe. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = (Pipe == gcvPIPE_2D) ++ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) ++ : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); ++ ++ /* Semaphore from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* Stall from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ if (fcFlushStall) ++ { ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ /* Semaphore from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* Stall from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ } ++ ++ if (iCacheInvalidate) ++ { ++ /* Invalidate I$ after pipe is stalled */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0218) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0218) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); ++ ++ /* Semaphore from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* Stall from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ } ++ } ++ ++ /* Number of slots taken by flushing pipe. */ ++ return flushSlots; ++} ++#endif ++ ++#if gcdENABLE_3D ++static gctUINT32 ++_SemaphoreStall( ++ IN gckCONTEXT Context, ++ IN gctUINT32 Index ++ ) ++{ ++ if (Context->buffer != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Address correct index. */ ++ buffer = Context->buffer->logical + Index; ++ ++ /* Semaphore from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* Stall from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ } ++ ++ /* Semaphore/stall takes 4 slots. */ ++ return 4; ++} ++#endif ++ ++#if (gcdENABLE_3D || gcdENABLE_2D) ++static gctUINT32 ++_SwitchPipe( ++ IN gckCONTEXT Context, ++ IN gctUINT32 Index, ++ IN gcePIPE_SELECT Pipe ++ ) ++{ ++ gctUINT32 slots = 6; ++ ++ if (Context->buffer != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Address correct index. */ ++ buffer = Context->buffer->logical + Index; ++ ++ /* LoadState(AQPipeSelect, 1), pipe. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ ++ = (Pipe == gcvPIPE_2D) ++ ? 0x1 ++ : 0x0; ++ ++ /* Semaphore from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* Stall from FE to PE. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ } ++ ++ Context->pipeSelectBytes = slots * gcmSIZEOF(gctUINT32); ++ ++ return slots; ++} ++#endif ++ ++#if gcdENABLE_3D ++static gctUINT32 ++_State( ++ IN gckCONTEXT Context, ++ IN gctUINT32 Index, ++ IN gctUINT32 Address, ++ IN gctUINT32 Value, ++ IN gctUINT32 Size, ++ IN gctBOOL FixedPoint, ++ IN gctBOOL Hinted ++ ) ++{ ++ gctUINT32_PTR buffer; ++ gctUINT32 align; ++ gctUINT32 i; ++ ++ /* Determine if we need alignment. */ ++ align = (Index & 1) ? 1 : 0; ++ ++ /* Address correct index. */ ++ buffer = (Context->buffer == gcvNULL) ++ ? gcvNULL ++ : Context->buffer->logical; ++ ++ if ((buffer == gcvNULL) && (Address + Size > Context->stateCount)) ++ { ++ /* Determine maximum state. */ ++ Context->stateCount = Address + Size; ++ } ++ ++ /* Do we need a new entry? */ ++ if ((Address != Context->lastAddress) || (FixedPoint != Context->lastFixed)) ++ { ++ if (buffer != gcvNULL) ++ { ++ if (align) ++ { ++ /* Add filler. */ ++ buffer[Index++] = 0xDEADDEAD; ++ } ++ ++ /* LoadState(Address, Count). */ ++ gcmkASSERT((Index & 1) == 0); ++ ++ if (FixedPoint) ++ { ++ buffer[Index] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ } ++ else ++ { ++ buffer[Index] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ } ++ ++ /* Walk all the states. */ ++ for (i = 0; i < (gctUINT32)Size; i += 1) ++ { ++ /* Set state to uninitialized value. */ ++ buffer[Index + 1 + i] = Value; ++ ++ /* Set index in state mapping table. */ ++ Context->map[Address + i].index = (gctUINT)Index + 1 + i; ++ } ++ } ++ ++ /* Save information for this LoadState. */ ++ Context->lastIndex = (gctUINT)Index; ++ Context->lastAddress = Address + (gctUINT32)Size; ++ Context->lastSize = Size; ++ Context->lastFixed = FixedPoint; ++ ++ /* Return size for load state. */ ++ return align + 1 + Size; ++ } ++ ++ /* Append this state to the previous one. */ ++ if (buffer != gcvNULL) ++ { ++ /* Update last load state. */ ++ buffer[Context->lastIndex] = ++ ((((gctUINT32) (buffer[Context->lastIndex])) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Context->lastSize + Size) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ /* Walk all the states. */ ++ for (i = 0; i < (gctUINT32)Size; i += 1) ++ { ++ /* Set state to uninitialized value. */ ++ buffer[Index + i] = Value; ++ ++ /* Set index in state mapping table. */ ++ Context->map[Address + i].index = (gctUINT)Index + i; ++ } ++ } ++ ++ /* Update last address and size. */ ++ Context->lastAddress += (gctUINT32)Size; ++ Context->lastSize += Size; ++ ++ /* Return number of slots required. */ ++ return Size; ++} ++ ++static gctUINT32 ++_StateMirror( ++ IN gckCONTEXT Context, ++ IN gctUINT32 Address, ++ IN gctUINT32 Size, ++ IN gctUINT32 AddressMirror ++ ) ++{ ++ gctUINT32 i; ++ ++ /* Process when buffer is set. */ ++ if (Context->buffer != gcvNULL) ++ { ++ /* Walk all states. */ ++ for (i = 0; i < Size; i++) ++ { ++ /* Copy the mapping address. */ ++ Context->map[Address + i].index = ++ Context->map[AddressMirror + i].index; ++ } ++ } ++ ++ /* Return the number of required maps. */ ++ return Size; ++} ++#endif ++ ++#if (gcdENABLE_3D || gcdENABLE_2D) ++static gceSTATUS ++_InitializeContextBuffer( ++ IN gckCONTEXT Context ++ ) ++{ ++ gctUINT32_PTR buffer; ++ gctUINT32 index; ++ ++#if gcdENABLE_3D ++ gctBOOL halti0, halti1, halti2, halti3; ++ gctUINT i; ++ gctUINT vertexUniforms, fragmentUniforms, vsConstBase, psConstBase, constMax; ++ gctBOOL unifiedUniform; ++ gctUINT fe2vsCount; ++#endif ++ ++ /* Reset the buffer index. */ ++ index = 0; ++ ++ /* Reset the last state address. */ ++ Context->lastAddress = ~0U; ++ ++ /* Get the buffer pointer. */ ++ buffer = (Context->buffer == gcvNULL) ++ ? gcvNULL ++ : Context->buffer->logical; ++ ++ ++ /**************************************************************************/ ++ /* Build 2D states. *******************************************************/ ++ ++ ++#if gcdENABLE_3D ++ /**************************************************************************/ ++ /* Build 3D states. *******************************************************/ ++ ++ halti0 = (((((gctUINT32) (Context->hardware->identity.chipMinorFeatures1)) >> (0 ? 23:23)) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))) ); ++ halti1 = (((((gctUINT32) (Context->hardware->identity.chipMinorFeatures2)) >> (0 ? 11:11)) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1)))))) ); ++ halti2 = (((((gctUINT32) (Context->hardware->identity.chipMinorFeatures4)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ); ++ halti3 = (((((gctUINT32) (Context->hardware->identity.chipMinorFeatures5)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) ); ++ ++ /* Query how many uniforms can support for non-unified uniform mode. */ ++ {if (Context->hardware->identity.numConstants > 256){ unifiedUniform = gcvTRUE; vsConstBase = 0xC000; psConstBase = 0xC000; constMax = Context->hardware->identity.numConstants; vertexUniforms = 256; fragmentUniforms = constMax - vertexUniforms;}else if (Context->hardware->identity.numConstants == 256){ if (Context->hardware->identity.chipModel == gcv2000 && Context->hardware->identity.chipRevision == 0x5118) { unifiedUniform = gcvFALSE; vsConstBase = 0x1400; psConstBase = 0x1C00; vertexUniforms = 256; fragmentUniforms = 64; constMax = 320; } else { unifiedUniform = gcvFALSE; vsConstBase = 0x1400; psConstBase = 0x1C00; vertexUniforms = 256; fragmentUniforms = 256; constMax = 512; }}else{ unifiedUniform = gcvFALSE; vsConstBase = 0x1400; psConstBase = 0x1C00; vertexUniforms = 168; fragmentUniforms = 64; constMax = 232;}}; ++ ++#if !gcdENABLE_UNIFIED_CONSTANT ++ if (Context->hardware->identity.numConstants > 256) ++ { ++ unifiedUniform = gcvTRUE; ++ } ++ else ++ { ++ unifiedUniform = gcvFALSE; ++ } ++#endif ++ ++ /* Store the 3D entry index. */ ++ Context->entryOffset3D = (gctUINT)index * gcmSIZEOF(gctUINT32); ++ ++ /* Switch to 3D pipe. */ ++ index += _SwitchPipe(Context, index, gcvPIPE_3D); ++ ++ /* Current context pointer. */ ++#if DEBUG ++ index += _State(Context, index, 0x03850 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++#endif ++ ++ index += _FlushPipe(Context, index, gcvPIPE_3D); ++ ++ /* Global states. */ ++ index += _State(Context, index, 0x03814 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x03818 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0381C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x03820 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x03828 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0382C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x03834 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x03838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x03854 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0384C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ /* Front End states. */ ++ fe2vsCount = 12; ++ if (halti0) ++ { ++ fe2vsCount = 16; ++ } ++ index += _State(Context, index, 0x00600 >> 2, 0x00000000, fe2vsCount, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ index += _State(Context, index, 0x00644 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x00648 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0064C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x00650 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00680 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x006A0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00674 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00670 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00678 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0067C >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x006C0 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00700 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00740 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00780 >> 2, 0x3F800000, 16, gcvFALSE, gcvFALSE); ++ ++ if (halti2) ++ { ++ index += _State(Context, index, 0x14600 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14640 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14680 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); ++ } ++ ++ /* This register is programed by all chips, which program all DECODE_SELECT as VS ++ ** except SAMPLER_DECODE_SELECT. ++ */ ++ index += _State(Context, index, 0x00860 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ if (((((gctUINT32) (Context->hardware->identity.chipMinorFeatures3)) >> (0 ? 3:3) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))))) ++ { ++ /* I-Cache states. */ ++ index += _State(Context, index, 0x00868 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0086C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0304C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01028 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ if (halti3) ++ { ++ index += _State(Context, index, 0x00890 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x0104C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _CLOSE_RANGE(); ++ } ++ } ++ ++ /* Vertex Shader states. */ ++ index += _State(Context, index, 0x00804 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00808 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0080C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00810 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00820 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00830 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ index += _CLOSE_RANGE(); ++ ++ /* Primitive Assembly states. */ ++ index += _State(Context, index, 0x00A00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00A04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00A08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A0C >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00A10 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00A14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A1C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A28 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A2C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A30 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A40 >> 2, 0x00000000, Context->hardware->identity.varyingsCount, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A38 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A3C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A80 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A84 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00A8C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00A88 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ /* Setup states. */ ++ index += _State(Context, index, 0x00C00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00C04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00C08 >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00C0C >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00C10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00C14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00C18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00C1C >> 2, 0x42000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00C20 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ index += _State(Context, index, 0x00C24 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); ++ ++ /* Raster states. */ ++ index += _State(Context, index, 0x00E00 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00E10 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00E04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00E40 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00E08 >> 2, 0x00000031, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00E24 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00E20 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ if (halti2) ++ { ++ index += _State(Context, index, 0x00E0C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ } ++ ++ /* Pixel Shader states. */ ++ index += _State(Context, index, 0x01004 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01008 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0100C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01010 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01030 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ index += _CLOSE_RANGE(); ++ ++ /* Texture states. */ ++ index += _State(Context, index, 0x02000 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x02040 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x02080 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x020C0 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x02100 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x02140 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x02180 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x021C0 >> 2, 0x00321000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x02200 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x02240 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, (0x02400 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02440 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02480 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x024C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02500 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02540 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02580 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x025C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02600 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02640 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02680 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x026C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02700 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x02740 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); ++ index += _CLOSE_RANGE(); ++ ++ if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures1)) >> (0 ? 22:22)) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))) )) ++ { ++ /* ++ * Linear stride LODn will overwrite LOD0 on GC880,GC2000. ++ * And only LOD0 is valid for this register. ++ */ ++ gctUINT count = halti1 ? 14 : 1; ++ ++ for (i = 0; i < 12; i += 1) ++ { ++ index += _State(Context, index, (0x02C00 >> 2) + i * 16, 0x00000000, count, gcvFALSE, gcvFALSE); ++ } ++ } ++ ++ if (halti1) ++ { ++ gctUINT texBlockCount; ++ gctUINT gcregTXLogSizeResetValue; ++ ++ /* Enable the integer filter pipe for all texture samplers ++ so that the floating point filter clock will shut off until ++ we start using the floating point filter. ++ */ ++ gcregTXLogSizeResetValue = ((((gctUINT32) (0x00000000)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 29:29) - (0 ? 29:29) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 29:29) - (0 ? 29:29) + 1))))))) << (0 ? 29:29))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 29:29) - (0 ? 29:29) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 29:29) - (0 ? 29:29) + 1))))))) << (0 ? 29:29))); ++ ++ /* New texture block. */ ++ index += _State(Context, index, 0x10000 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10080 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10100 >> 2, gcregTXLogSizeResetValue, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10180 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10200 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10280 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10300 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10380 >> 2, 0x00321000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10400 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10480 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ ++ if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures2)) >> (0 ? 15:15)) & ((gctUINT32) ((((1 ? 15:15) - (0 ? 15:15) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:15) - (0 ? 15:15) + 1)))))) )) ++ { ++ index += _State(Context, index, 0x12000 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x12400 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE); ++ } ++ ++ texBlockCount = ((512) >> (4)); ++ ++ for (i = 0; i < texBlockCount; i += 1) ++ { ++ index += _State(Context, index, (0x10800 >> 2) + (i << 4), 0x00000000, 14, gcvFALSE, gcvTRUE); ++ } ++ } ++ ++ if (halti2) ++ { ++ index += _State(Context, index, 0x10700 >> 2, 0x00000F00, 32, gcvFALSE, gcvFALSE); ++ } ++ ++ if (halti3) ++ { ++ index += _State(Context, index, 0x10780 >> 2, 0x00030000, 32, gcvFALSE, gcvFALSE); ++ } ++ ++ /* ASTC */ ++ if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures4)) >> (0 ? 13:13)) & ((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:13) - (0 ? 13:13) + 1)))))) )) ++ { ++ index += _State(Context, index, 0x10500 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10580 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10600 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x10680 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); ++ } ++ ++ /* YUV. */ ++ index += _State(Context, index, 0x01678 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0167C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01680 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x01684 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01688 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x0168C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01690 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x01694 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01698 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x0169C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ /* Thread walker states. */ ++ index += _State(Context, index, 0x00900 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00904 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00908 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0090C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00910 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00914 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00918 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0091C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00924 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ if (((((gctUINT32) (Context->hardware->identity.chipMinorFeatures3)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))) ++ { ++ index += _State(Context, index, 0x00940 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00944 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00948 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0094C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00950 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00954 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ } ++ ++ index += _CLOSE_RANGE(); ++ ++ if (!halti3) ++ { ++ if (Context->hardware->identity.instructionCount > 1024) ++ { ++ /* New Shader instruction PC registers. */ ++ index += _State(Context, index, 0x0085C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0101C >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ for (i = 0; ++ i < Context->hardware->identity.instructionCount << 2; ++ i += 256 << 2 ++ ) ++ { ++ index += _State(Context, index, (0x20000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ } ++ } ++ else if (Context->hardware->identity.instructionCount > 256) ++ { ++ /* New Shader instruction PC registers. */ ++ index += _State(Context, index, 0x0085C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0101C >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ /* VX instruction memory. */ ++ for (i = 0; ++ i < Context->hardware->identity.instructionCount << 2; ++ i += 256 << 2 ++ ) ++ { ++ index += _State(Context, index, (0x0C000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ } ++ ++ _StateMirror(Context, 0x08000 >> 2, Context->hardware->identity.instructionCount << 2 , 0x0C000 >> 2); ++ } ++ else /* if (Context->hardware->identity.instructionCount <= 256) */ ++ { ++ /* old shader instruction PC registers */ ++ index += _State(Context, index, 0x00800 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ index += _State(Context, index, 0x01000 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01018 >> 2, 0x01000000, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ index += _State(Context, index, 0x04000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ index += _State(Context, index, 0x06000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ } ++ } ++ /* I cache use the new instruction PC registers */ ++ else ++ { ++ /* New Shader instruction PC registers. */ ++ index += _State(Context, index, 0x0085C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0101C >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ } ++ ++ if (unifiedUniform) ++ { ++ gctINT numConstants = Context->hardware->identity.numConstants; ++ ++ index += _State(Context, index, 0x01024 >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x00864 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ for (i = 0; ++ numConstants > 0; ++ i += 256 << 2, ++ numConstants -= 256 ++ ) ++ { ++ if (numConstants >= 256) ++ { ++ index += _State(Context, index, (0x30000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE); ++ } ++ else ++ { ++ index += _State(Context, index, (0x30000 >> 2) + i, 0x00000000, numConstants << 2, gcvFALSE, gcvFALSE); ++ } ++ index += _CLOSE_RANGE(); ++ } ++ } ++#if gcdENABLE_UNIFIED_CONSTANT ++ else ++#endif ++ { ++ index += _State(Context, index, 0x05000 >> 2, 0x00000000, vertexUniforms * 4, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x07000 >> 2, 0x00000000, fragmentUniforms * 4, gcvFALSE, gcvFALSE); ++ } ++ ++ /* Store the index of the "XD" entry. */ ++ Context->entryOffsetXDFrom3D = (gctUINT)index * gcmSIZEOF(gctUINT32); ++ ++ ++ /* Pixel Engine states. */ ++ index += _State(Context, index, 0x01400 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01404 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01408 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0140C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01414 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01418 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0141C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01420 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01424 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01428 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0142C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01434 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01454 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01458 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x0145C >> 2, 0x00000010, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x014A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x014A8 >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x014AC >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x014B0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x014B4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x014A4 >> 2, 0x000E400C, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01580 >> 2, 0x00000000, 3, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x014B8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ /* Composition states. */ ++ index += _State(Context, index, 0x03008 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ if (Context->hardware->identity.pixelPipes == 1) ++ { ++ index += _State(Context, index, 0x01460 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE); ++ ++ index += _State(Context, index, 0x01430 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x01410 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ } ++ else ++ { ++ index += _State(Context, index, (0x01460 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); ++ } ++ ++ if (Context->hardware->identity.pixelPipes > 1 || halti0) ++ { ++ index += _State(Context, index, (0x01480 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); ++ } ++ ++ for (i = 0; i < 3; i++) ++ { ++ index += _State(Context, index, (0x01500 >> 2) + (i << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); ++ } ++ ++ if (halti2) ++ { ++ for (i = 0; i < 7; i++) ++ { ++ index += _State(Context, index, (0x14800 >> 2) + (i << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); ++ } ++ index += _State(Context, index, 0x14900 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE); ++ } ++ ++ ++ if (halti3) ++ { ++ index += _State(Context, index, 0x014BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ } ++ ++ /* Resolve states. */ ++ index += _State(Context, index, 0x01604 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01608 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x0160C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01610 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x01614 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01620 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01630 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01640 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x0163C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x016A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x016B4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ ++ if ((Context->hardware->identity.pixelPipes > 1) || halti1) ++ { ++ index += _State(Context, index, (0x016C0 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); ++ ++ index += _State(Context, index, (0x016E0 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); ++ ++ index += _State(Context, index, 0x01700 >> 2, 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvFALSE); ++ } ++ ++#if gcd3DBLIT ++ index += _State(Context, index, (0x14000 >> 2) + (0 << 1), 0x00000000, 2, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x14008 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x1400C >> 2, 0x0001C800, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14010 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x14014 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, (0x14018 >> 2) + (0 << 1), 0x00000000, 2, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x14020 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x14024 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14028 >> 2, 0x0001C800, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x1402C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14030 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14034 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14038 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x1403C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14040 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14044 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14048 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x1404C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14050 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14058 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x1405C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14054 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14100 >> 2, 0x00000000, 64, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14200 >> 2, 0x00000000, 64, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14064 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14068 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ index += _State(Context, index, 0x1406C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14070 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14074 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14078 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x1407C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14080 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14084 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14088 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x1408C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14090 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ ++ index += _State(Context, index, 0x14094 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x14098 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++#endif ++ ++ /* Tile status. */ ++ index += _State(Context, index, 0x01654 >> 2, 0x00200000, 1, gcvFALSE, gcvFALSE); ++ ++ index += _CLOSE_RANGE(); ++ index += _State(Context, index, 0x01658 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x0165C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x01660 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01664 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x01668 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x0166C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01670 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01674 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x016A4 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x016AC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x016A8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01720 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x01740 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, 0x01760 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE); ++ ++ ++ if (halti2) ++ { ++ index += _State(Context, index, 0x01780 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, 0x016BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, (0x017A0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, (0x017C0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x017E0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvTRUE); ++ index += _State(Context, index, (0x01A00 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, (0x01A20 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE); ++ index += _State(Context, index, (0x01A40 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE); ++ } ++ ++ index += _CLOSE_RANGE(); ++ ++ if(((((gctUINT32) (Context->hardware->identity.chipMinorFeatures4)) >> (0 ? 25:25) & ((gctUINT32) ((((1 ? 25:25) - (0 ? 25:25) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:25) - (0 ? 25:25) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 25:25) - (0 ? 25:25) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:25) - (0 ? 25:25) + 1)))))))) ++ { ++ index += _State(Context, index, 0x03860 >> 2, 0x6, 1, gcvFALSE, gcvFALSE); ++ index += _CLOSE_RANGE(); ++ } ++ ++ if (halti3) ++ { ++ index += _State(Context, index, 0x01A80 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE); ++ index += _CLOSE_RANGE(); ++ } ++ ++ /* Semaphore/stall. */ ++ index += _SemaphoreStall(Context, index); ++#endif ++ ++ /**************************************************************************/ ++ /* Link to another address. ***********************************************/ ++ ++ Context->linkIndex3D = (gctUINT)index; ++ ++ if (buffer != gcvNULL) ++ { ++ buffer[index + 0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[index + 1] ++ = 0; ++ } ++ ++ index += 2; ++ ++ /* Store the end of the context buffer. */ ++ Context->bufferSize = index * gcmSIZEOF(gctUINT32); ++ ++ ++ /**************************************************************************/ ++ /* Pipe switch for the case where neither 2D nor 3D are used. *************/ ++ ++ /* Store the 3D entry index. */ ++ Context->entryOffsetXDFrom2D = (gctUINT)index * gcmSIZEOF(gctUINT32); ++ ++ /* Flush 2D pipe. */ ++ index += _FlushPipe(Context, index, gcvPIPE_2D); ++ ++ /* Switch to 3D pipe. */ ++ index += _SwitchPipe(Context, index, gcvPIPE_3D); ++ ++ /* Store the location of the link. */ ++ Context->linkIndexXD = (gctUINT)index; ++ ++ if (buffer != gcvNULL) ++ { ++ buffer[index + 0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[index + 1] ++ = 0; ++ } ++ ++ index += 2; ++ ++ ++ /**************************************************************************/ ++ /* Save size for buffer. **************************************************/ ++ ++ Context->totalSize = index * gcmSIZEOF(gctUINT32); ++ ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++#endif ++ ++static gceSTATUS ++_DestroyContext( ++ IN gckCONTEXT Context ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ ++ if (Context != gcvNULL) ++ { ++ gcsCONTEXT_PTR bufferHead; ++ ++ /* Free context buffers. */ ++ for (bufferHead = Context->buffer; Context->buffer != gcvNULL;) ++ { ++ /* Get a shortcut to the current buffer. */ ++ gcsCONTEXT_PTR buffer = Context->buffer; ++ ++ /* Get the next buffer. */ ++ gcsCONTEXT_PTR next = buffer->next; ++ ++ /* Last item? */ ++ if (next == bufferHead) ++ { ++ next = gcvNULL; ++ } ++ ++ /* Destroy the signal. */ ++ if (buffer->signal != gcvNULL) ++ { ++ gcmkONERROR(gckOS_DestroySignal( ++ Context->os, buffer->signal ++ )); ++ ++ buffer->signal = gcvNULL; ++ } ++ ++ /* Free state delta map. */ ++ if (buffer->logical != gcvNULL) ++ { ++ if (Context->hardware->kernel->virtualCommandBuffer) ++ { ++ gcmkONERROR(gckEVENT_DestroyVirtualCommandBuffer( ++ Context->hardware->kernel->eventObj, ++ Context->totalSize, ++ buffer->physical, ++ buffer->logical, ++ gcvKERNEL_PIXEL ++ )); ++ } ++ else ++ { ++ gcmkONERROR(gckEVENT_FreeContiguousMemory( ++ Context->hardware->kernel->eventObj, ++ Context->totalSize, ++ buffer->physical, ++ buffer->logical, ++ gcvKERNEL_PIXEL ++ )); ++ } ++ ++ buffer->logical = gcvNULL; ++ } ++ ++ /* Free context buffer. */ ++ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, buffer)); ++ ++ /* Remove from the list. */ ++ Context->buffer = next; ++ } ++ ++ /* Free record array copy. */ ++#if REMOVE_DUPLICATED_COPY_FROM_USER ++ if (Context->recordArrayMap != gcvNULL) ++ { ++ gcsRECORD_ARRAY_MAP_PTR map = Context->recordArrayMap; ++ ++ do ++ { ++ /* Free record array. */ ++ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, map->kData)); ++ map = map->next; ++ } ++ while (map != Context->recordArrayMap); ++ ++ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context->recordArrayMap)); ++ } ++#else ++ if (Context->recordArray != gcvNULL) ++ { ++ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context->recordArray)); ++ } ++#endif ++ ++ /* Free the state mapping. */ ++ if (Context->map != gcvNULL) ++ { ++ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context->map)); ++ } ++ ++ /* Mark the gckCONTEXT object as unknown. */ ++ Context->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckCONTEXT object. */ ++ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context)); ++ } ++ ++OnError: ++ return status; ++} ++ ++ ++/******************************************************************************\ ++**************************** Context Management API **************************** ++\******************************************************************************/ ++ ++/******************************************************************************\ ++** ++** gckCONTEXT_Construct ++** ++** Construct a new gckCONTEXT object. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to gckOS object. ++** ++** gctUINT32 ProcessID ++** Current process ID. ++** ++** gckHARDWARE Hardware ++** Pointer to gckHARDWARE object. ++** ++** OUTPUT: ++** ++** gckCONTEXT * Context ++** Pointer to a variable thet will receive the gckCONTEXT object ++** pointer. ++*/ ++#if (gcdENABLE_3D || gcdENABLE_2D) ++gceSTATUS ++gckCONTEXT_Construct( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 ProcessID, ++ OUT gckCONTEXT * Context ++ ) ++{ ++ gceSTATUS status; ++ gckCONTEXT context = gcvNULL; ++ gctUINT32 allocationSize; ++ gctUINT i; ++ gctPOINTER pointer = gcvNULL; ++ gctUINT32 address; ++ ++ gcmkHEADER_ARG("Os=0x%08X Hardware=0x%08X", Os, Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Context != gcvNULL); ++ ++ ++ /**************************************************************************/ ++ /* Allocate and initialize basic fields of gckCONTEXT. ********************/ ++ ++ /* The context object size. */ ++ allocationSize = gcmSIZEOF(struct _gckCONTEXT); ++ ++ /* Allocate the object. */ ++ gcmkONERROR(gckOS_Allocate( ++ Os, allocationSize, &pointer ++ )); ++ ++ context = pointer; ++ ++ /* Reset the entire object. */ ++ gcmkONERROR(gckOS_ZeroMemory(context, allocationSize)); ++ ++ /* Initialize the gckCONTEXT object. */ ++ context->object.type = gcvOBJ_CONTEXT; ++ context->os = Os; ++ context->hardware = Hardware; ++ ++ ++#if !gcdENABLE_3D ++ context->entryPipe = gcvPIPE_2D; ++ context->exitPipe = gcvPIPE_2D; ++#elif gcdCMD_NO_2D_CONTEXT ++ context->entryPipe = gcvPIPE_3D; ++ context->exitPipe = gcvPIPE_3D; ++#else ++ context->entryPipe ++ = (((((gctUINT32) (context->hardware->identity.chipFeatures)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) ) ++ ? gcvPIPE_2D ++ : gcvPIPE_3D; ++ context->exitPipe = gcvPIPE_3D; ++#endif ++ ++ /* Get the command buffer requirements. */ ++ gcmkONERROR(gckHARDWARE_QueryCommandBuffer( ++ Hardware, ++ &context->alignment, ++ &context->reservedHead, ++ &context->reservedTail ++ )); ++ ++ /* Mark the context as dirty to force loading of the entire state table ++ the first time. */ ++ context->dirty = gcvTRUE; ++ ++ ++ /**************************************************************************/ ++ /* Get the size of the context buffer. ************************************/ ++ ++ gcmkONERROR(_InitializeContextBuffer(context)); ++ ++ ++ /**************************************************************************/ ++ /* Compute the size of the record array. **********************************/ ++ ++ context->recordArraySize ++ = gcmSIZEOF(gcsSTATE_DELTA_RECORD) * (gctUINT)context->stateCount; ++ ++ ++ if (context->stateCount > 0) ++ { ++ /**************************************************************************/ ++ /* Allocate and reset the state mapping table. ****************************/ ++ ++ /* Allocate the state mapping table. */ ++ gcmkONERROR(gckOS_Allocate( ++ Os, ++ gcmSIZEOF(gcsSTATE_MAP) * context->stateCount, ++ &pointer ++ )); ++ ++ context->map = pointer; ++ ++ /* Zero the state mapping table. */ ++ gcmkONERROR(gckOS_ZeroMemory( ++ context->map, gcmSIZEOF(gcsSTATE_MAP) * context->stateCount ++ )); ++ } ++ ++ /**************************************************************************/ ++ /* Allocate the context and state delta buffers. **************************/ ++ ++ for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i += 1) ++ { ++ /* Allocate a context buffer. */ ++ gcsCONTEXT_PTR buffer; ++ ++ gctSIZE_T totalSize = context->totalSize; ++ ++ /* Allocate the context buffer structure. */ ++ gcmkONERROR(gckOS_Allocate( ++ Os, ++ gcmSIZEOF(gcsCONTEXT), ++ &pointer ++ )); ++ ++ buffer = pointer; ++ ++ /* Reset the context buffer structure. */ ++ gcmkVERIFY_OK(gckOS_ZeroMemory( ++ buffer, gcmSIZEOF(gcsCONTEXT) ++ )); ++ ++ /* Append to the list. */ ++ if (context->buffer == gcvNULL) ++ { ++ buffer->next = buffer; ++ context->buffer = buffer; ++ } ++ else ++ { ++ buffer->next = context->buffer->next; ++ context->buffer->next = buffer; ++ } ++ ++ /* Set the number of delta in the order of creation. */ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++ buffer->num = i; ++#endif ++ ++ /* Create the busy signal. */ ++ gcmkONERROR(gckOS_CreateSignal( ++ Os, gcvFALSE, &buffer->signal ++ )); ++ ++ /* Set the signal, buffer is currently not busy. */ ++ gcmkONERROR(gckOS_Signal( ++ Os, buffer->signal, gcvTRUE ++ )); ++ ++ /* Create a new physical context buffer. */ ++ if (context->hardware->kernel->virtualCommandBuffer) ++ { ++ gcmkONERROR(gckKERNEL_AllocateVirtualCommandBuffer( ++ context->hardware->kernel, ++ gcvFALSE, ++ &totalSize, ++ &buffer->physical, ++ &pointer ++ )); ++ ++ gcmkONERROR(gckKERNEL_GetGPUAddress( ++ context->hardware->kernel, ++ pointer, ++ gcvFALSE, ++ &address ++ )); ++ } ++ else ++ { ++ gcmkONERROR(gckOS_AllocateContiguous( ++ Os, ++ gcvFALSE, ++ &totalSize, ++ &buffer->physical, ++ &pointer ++ )); ++ ++ gcmkONERROR(gckHARDWARE_ConvertLogical( ++ context->hardware, ++ pointer, ++ gcvFALSE, ++ &address ++ )); ++ } ++ ++ buffer->logical = pointer; ++ buffer->address = address; ++ ++ /* Set gckEVENT object pointer. */ ++ buffer->eventObj = Hardware->kernel->eventObj; ++ ++ /* Set the pointers to the LINK commands. */ ++ if (context->linkIndex2D != 0) ++ { ++ buffer->link2D = &buffer->logical[context->linkIndex2D]; ++ } ++ ++ if (context->linkIndex3D != 0) ++ { ++ buffer->link3D = &buffer->logical[context->linkIndex3D]; ++ } ++ ++ if (context->linkIndexXD != 0) ++ { ++ gctPOINTER xdLink; ++ gctUINT32 xdEntryAddress; ++ gctUINT32 xdEntrySize; ++ gctUINT32 linkBytes; ++ ++ /* Determine LINK parameters. */ ++ xdLink ++ = &buffer->logical[context->linkIndexXD]; ++ ++ xdEntryAddress ++ = buffer->address ++ + context->entryOffsetXDFrom3D; ++ ++ xdEntrySize ++ = context->bufferSize ++ - context->entryOffsetXDFrom3D; ++ ++ /* Query LINK size. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ Hardware, gcvNULL, 0, 0, &linkBytes ++ )); ++ ++ /* Generate a LINK. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ Hardware, ++ xdLink, ++ xdEntryAddress, ++ xdEntrySize, ++ &linkBytes ++ )); ++ } ++ } ++ ++ ++ /**************************************************************************/ ++ /* Initialize the context buffers. ****************************************/ ++ ++ /* Initialize the current context buffer. */ ++ gcmkONERROR(_InitializeContextBuffer(context)); ++ ++ /* Make all created contexts equal. */ ++ { ++ gcsCONTEXT_PTR currContext, tempContext; ++ ++ /* Set the current context buffer. */ ++ currContext = context->buffer; ++ ++ /* Get the next context buffer. */ ++ tempContext = currContext->next; ++ ++ /* Loop through all buffers. */ ++ while (tempContext != currContext) ++ { ++ if (tempContext == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_FOUND); ++ } ++ ++ /* Copy the current context. */ ++ gckOS_MemCopy( ++ tempContext->logical, ++ currContext->logical, ++ context->totalSize ++ ); ++ ++ /* Get the next context buffer. */ ++ tempContext = tempContext->next; ++ } ++ } ++ ++ /* Return pointer to the gckCONTEXT object. */ ++ *Context = context; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Context=0x%08X", *Context); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back on error. */ ++ gcmkVERIFY_OK(_DestroyContext(context)); ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++/******************************************************************************\ ++** ++** gckCONTEXT_Destroy ++** ++** Destroy a gckCONTEXT object. ++** ++** INPUT: ++** ++** gckCONTEXT Context ++** Pointer to an gckCONTEXT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCONTEXT_Destroy( ++ IN gckCONTEXT Context ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Context=0x%08X", Context); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT); ++ ++ /* Destroy the context and all related objects. */ ++ status = _DestroyContext(Context); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return status; ++} ++ ++/******************************************************************************\ ++** ++** gckCONTEXT_Update ++** ++** Merge all pending state delta buffers into the current context buffer. ++** ++** INPUT: ++** ++** gckCONTEXT Context ++** Pointer to an gckCONTEXT object. ++** ++** gctUINT32 ProcessID ++** Current process ID. ++** ++** gcsSTATE_DELTA_PTR StateDelta ++** Pointer to the state delta. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCONTEXT_Update( ++ IN gckCONTEXT Context, ++ IN gctUINT32 ProcessID, ++ IN gcsSTATE_DELTA_PTR StateDelta ++ ) ++{ ++#if gcdENABLE_3D ++ gceSTATUS status = gcvSTATUS_OK; ++ gcsSTATE_DELTA _stateDelta; ++ gckKERNEL kernel; ++ gcsCONTEXT_PTR buffer; ++ gcsSTATE_MAP_PTR map; ++ gctBOOL needCopy = gcvFALSE; ++ gcsSTATE_DELTA_PTR nDelta; ++ gcsSTATE_DELTA_PTR uDelta = gcvNULL; ++ gcsSTATE_DELTA_PTR kDelta = gcvNULL; ++ gcsSTATE_DELTA_RECORD_PTR record; ++ gcsSTATE_DELTA_RECORD_PTR recordArray = gcvNULL; ++#if REMOVE_DUPLICATED_COPY_FROM_USER ++ gcsRECORD_ARRAY_MAP_PTR recordArrayMap = gcvNULL; ++#endif ++ gctUINT elementCount; ++ gctUINT address; ++ gctUINT32 mask; ++ gctUINT32 data; ++ gctUINT index; ++ gctUINT i, j; ++ ++ gcmkHEADER_ARG( ++ "Context=0x%08X ProcessID=%d StateDelta=0x%08X", ++ Context, ProcessID, StateDelta ++ ); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT); ++ ++ /* Get a shortcut to the kernel object. */ ++ kernel = Context->hardware->kernel; ++ ++ /* Check wehther we need to copy the structures or not. */ ++ gcmkONERROR(gckOS_QueryNeedCopy(Context->os, ProcessID, &needCopy)); ++ ++ /* Allocate the copy buffer for the user record array. */ ++#if REMOVE_DUPLICATED_COPY_FROM_USER ++ if (needCopy && (Context->recordArrayMap == gcvNULL)) ++ { ++ /* Allocate enough maps. */ ++ gcmkONERROR(gckOS_Allocate( ++ Context->os, ++ gcmSIZEOF(gcsRECORD_ARRAY_MAP_PTR) * gcdCONTEXT_BUFFER_COUNT, ++ (gctPOINTER *) &Context->recordArrayMap ++ )); ++ ++ for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i++) ++ { ++ /* Next mapping id. */ ++ gctUINT n = (i + 1) % gcdCONTEXT_BUFFER_COUNT; ++ ++ recordArrayMap = &Context->recordArrayMap[i]; ++ ++ /* Allocate the buffer. */ ++ gcmkONERROR(gckOS_Allocate( ++ Context->os, ++ Context->recordArraySize, ++ (gctPOINTER *) &recordArrayMap->kData ++ )); ++ ++ /* Initialize fields. */ ++ recordArrayMap->key = 0; ++ recordArrayMap->next = &Context->recordArrayMap[n]; ++ } ++ } ++#else ++ if (needCopy && (Context->recordArray == gcvNULL)) ++ { ++ /* Allocate the buffer. */ ++ gcmkONERROR(gckOS_Allocate( ++ Context->os, ++ Context->recordArraySize, ++ (gctPOINTER *) &Context->recordArray ++ )); ++ } ++#endif ++ ++ /* Get the current context buffer. */ ++ buffer = Context->buffer; ++ ++ /* Wait until the context buffer becomes available; this will ++ also reset the signal and mark the buffer as busy. */ ++ gcmkONERROR(gckOS_WaitSignal( ++ Context->os, buffer->signal, gcvINFINITE ++ )); ++ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) && 1 && gcdENABLE_3D ++ /* Update current context token. */ ++ buffer->logical[Context->map[0x0E14].index] ++ = (gctUINT32)gcmPTR2INT32(Context); ++#endif ++ ++ /* Are there any pending deltas? */ ++ if (buffer->deltaCount != 0) ++ { ++ /* Get the state map. */ ++ map = Context->map; ++ ++ /* Get the first delta item. */ ++ uDelta = buffer->delta; ++ ++ /* Reset the vertex stream count. */ ++ elementCount = 0; ++ ++ /* Merge all pending deltas. */ ++ for (i = 0; i < buffer->deltaCount; i += 1) ++ { ++ /* Get access to the state delta. */ ++ gcmkONERROR(gckKERNEL_OpenUserData( ++ kernel, needCopy, ++ &_stateDelta, ++ uDelta, gcmSIZEOF(gcsSTATE_DELTA), ++ (gctPOINTER *) &kDelta ++ )); ++ ++#if REMOVE_DUPLICATED_COPY_FROM_USER ++ if (needCopy) ++ { ++ recordArray = gcvNULL; ++ recordArrayMap = Context->recordArrayMap; ++ ++ do ++ { ++ /* Check if recordArray is alreay opened. */ ++ if (recordArrayMap->key == kDelta->recordArray) ++ { ++ /* Found. */ ++ recordArray = recordArrayMap->kData; ++ break; ++ } ++ ++ recordArrayMap = recordArrayMap->next; ++ } ++ while (recordArrayMap != Context->recordArrayMap); ++ ++ if (recordArray == gcvNULL) ++ { ++ while (recordArrayMap->key != 0) ++ { ++ /* Found an empty slot. */ ++ recordArrayMap = recordArrayMap->next; ++ } ++ ++ /* Get access to the state records. */ ++ gcmkONERROR(gckOS_CopyFromUserData( ++ kernel->os, ++ recordArrayMap->kData, ++ gcmUINT64_TO_PTR(kDelta->recordArray), ++ Context->recordArraySize ++ )); ++ ++ /* Save user pointer as key. */ ++ recordArrayMap->key = kDelta->recordArray; ++ recordArray = recordArrayMap->kData; ++ } ++ } ++ else ++ { ++ /* Get access to the state records. */ ++ gcmkONERROR(gckOS_MapUserPointer( ++ kernel->os, ++ gcmUINT64_TO_PTR(kDelta->recordArray), ++ Context->recordArraySize, ++ (gctPOINTER *) &recordArray ++ )); ++ } ++#else ++ /* Get access to the state records. */ ++ gcmkONERROR(gckKERNEL_OpenUserData( ++ kernel, needCopy, ++ Context->recordArray, ++ gcmUINT64_TO_PTR(kDelta->recordArray), Context->recordArraySize, ++ (gctPOINTER *) &recordArray ++ )); ++#endif ++ ++ /* Merge all pending states. */ ++ for (j = 0; j < kDelta->recordCount; j += 1) ++ { ++ if (j >= Context->stateCount) ++ { ++ break; ++ } ++ ++ /* Get the current state record. */ ++ record = &recordArray[j]; ++ ++ /* Get the state address. */ ++ address = record->address; ++ ++ /* Make sure the state is a part of the mapping table. */ ++ if (address >= Context->stateCount) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): State 0x%04X is not mapped.\n", ++ __FUNCTION__, __LINE__, ++ address ++ ); ++ ++ continue; ++ } ++ ++ /* Get the state index. */ ++ index = map[address].index; ++ ++ /* Skip the state if not mapped. */ ++ if (index == 0) ++ { ++ continue; ++ } ++ ++ /* Get the data mask. */ ++ mask = record->mask; ++ ++ /* Masked states that are being completly reset or regular states. */ ++ if ((mask == 0) || (mask == ~0U)) ++ { ++ /* Get the new data value. */ ++ data = record->data; ++ ++ /* Process special states. */ ++ if (address == 0x0595) ++ { ++ /* Force auto-disable to be disabled. */ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:13) - (0 ? 13:13) + 1))))))) << (0 ? 13:13))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:13) - (0 ? 13:13) + 1))))))) << (0 ? 13:13))); ++ } ++ ++ /* Set new data. */ ++ buffer->logical[index] = data; ++ } ++ ++ /* Masked states that are being set partially. */ ++ else ++ { ++ buffer->logical[index] ++ = (~mask & buffer->logical[index]) ++ | (mask & record->data); ++ } ++ } ++ ++ /* Get the element count. */ ++ if (kDelta->elementCount != 0) ++ { ++ elementCount = kDelta->elementCount; ++ } ++ ++ /* Dereference delta. */ ++ kDelta->refCount -= 1; ++ gcmkASSERT(kDelta->refCount >= 0); ++ ++ /* Get the next state delta. */ ++ nDelta = gcmUINT64_TO_PTR(kDelta->next); ++ ++#if REMOVE_DUPLICATED_COPY_FROM_USER ++ if (needCopy) ++ { ++ if (kDelta->refCount == 0) ++ { ++ /* No other reference, reset the mapping. */ ++ recordArrayMap->key = 0; ++ } ++ } ++ else ++ { ++ /* Close access to the state records. */ ++ gcmkONERROR(gckOS_UnmapUserPointer( ++ kernel->os, ++ gcmUINT64_TO_PTR(kDelta->recordArray), ++ Context->recordArraySize, ++ (gctPOINTER *) recordArray ++ )); ++ ++ recordArray = gcvNULL; ++ } ++#else ++ /* Get access to the state records. */ ++ gcmkONERROR(gckKERNEL_CloseUserData( ++ kernel, needCopy, ++ gcvFALSE, ++ gcmUINT64_TO_PTR(kDelta->recordArray), Context->recordArraySize, ++ (gctPOINTER *) &recordArray ++ )); ++#endif ++ ++ /* Close access to the current state delta. */ ++ gcmkONERROR(gckKERNEL_CloseUserData( ++ kernel, needCopy, ++ gcvTRUE, ++ uDelta, gcmSIZEOF(gcsSTATE_DELTA), ++ (gctPOINTER *) &kDelta ++ )); ++ ++ /* Update the user delta pointer. */ ++ uDelta = nDelta; ++ } ++ ++ /* Hardware disables all input streams when the stream 0 is programmed, ++ it then reenables those streams that were explicitely programmed by ++ the software. Because of this we cannot program the entire array of ++ values, otherwise we'll get all streams reenabled, but rather program ++ only those that are actully needed by the software. */ ++ if (elementCount != 0) ++ { ++ gctUINT base; ++ gctUINT nopCount; ++ gctUINT32_PTR nop; ++ gctUINT fe2vsCount = 12; ++ ++ if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures1)) >> (0 ? 23:23)) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))) )) ++ { ++ fe2vsCount = 16; ++ } ++ ++ /* Determine the base index of the vertex stream array. */ ++ base = map[0x0180].index; ++ ++ /* Set the proper state count. */ ++ buffer->logical[base - 1] ++ = ((((gctUINT32) (buffer->logical[base - 1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (elementCount ) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ /* Determine the number of NOP commands. */ ++ nopCount ++ = (fe2vsCount / 2) ++ - (elementCount / 2); ++ ++ /* Determine the location of the first NOP. */ ++ nop = &buffer->logical[base + (elementCount | 1)]; ++ ++ if ((nop + (nopCount * 2)) >= buffer->logical + Context->totalSize) ++ nopCount = (buffer->logical + Context->totalSize - nop) / 2; ++ ++ /* Fill the unused space with NOPs. */ ++ for (i = 0; i < nopCount; i += 1) ++ { ++ /* Generate a NOP command. */ ++ *nop = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ /* Advance. */ ++ nop += 2; ++ } ++ } ++ ++ /* Reset pending deltas. */ ++ buffer->deltaCount = 0; ++ buffer->delta = gcvNULL; ++ } ++ ++ /* Set state delta user pointer. */ ++ uDelta = StateDelta; ++ ++ /* Get access to the state delta. */ ++ gcmkONERROR(gckKERNEL_OpenUserData( ++ kernel, needCopy, ++ &_stateDelta, ++ uDelta, gcmSIZEOF(gcsSTATE_DELTA), ++ (gctPOINTER *) &kDelta ++ )); ++ ++ /* State delta cannot be attached to anything yet. */ ++ if (kDelta->refCount != 0) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): kDelta->refCount = %d (has to be 0).\n", ++ __FUNCTION__, __LINE__, ++ kDelta->refCount ++ ); ++ } ++ ++ /* Attach to all contexts. */ ++ buffer = Context->buffer; ++ ++ do ++ { ++ /* Attach to the context if nothing is attached yet. If a delta ++ is allready attached, all we need to do is to increment ++ the number of deltas in the context. */ ++ if (buffer->delta == gcvNULL) ++ { ++ buffer->delta = uDelta; ++ } ++ ++ /* Update reference count. */ ++ kDelta->refCount += 1; ++ ++ /* Update counters. */ ++ buffer->deltaCount += 1; ++ ++ /* Get the next context buffer. */ ++ buffer = buffer->next; ++ ++ if (buffer == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_FOUND); ++ } ++ } ++ while (Context->buffer != buffer); ++ ++ /* Close access to the current state delta. */ ++ gcmkONERROR(gckKERNEL_CloseUserData( ++ kernel, needCopy, ++ gcvTRUE, ++ uDelta, gcmSIZEOF(gcsSTATE_DELTA), ++ (gctPOINTER *) &kDelta ++ )); ++ ++ /* Schedule an event to mark the context buffer as available. */ ++ gcmkONERROR(gckEVENT_Signal( ++ buffer->eventObj, buffer->signal, gcvKERNEL_PIXEL ++ )); ++ ++ /* Advance to the next context buffer. */ ++ Context->buffer = buffer->next; ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Get access to the state records. */ ++ if (kDelta != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckKERNEL_CloseUserData( ++ kernel, needCopy, ++ gcvFALSE, ++ gcmUINT64_TO_PTR(kDelta->recordArray), Context->recordArraySize, ++ (gctPOINTER *) &recordArray ++ )); ++ } ++ ++ /* Close access to the current state delta. */ ++ gcmkVERIFY_OK(gckKERNEL_CloseUserData( ++ kernel, needCopy, ++ gcvTRUE, ++ uDelta, gcmSIZEOF(gcsSTATE_DELTA), ++ (gctPOINTER *) &kDelta ++ )); ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++#else ++ return gcvSTATUS_OK; ++#endif ++} ++ ++gceSTATUS ++gckCONTEXT_MapBuffer( ++ IN gckCONTEXT Context, ++ OUT gctUINT32 *Physicals, ++ OUT gctUINT64 *Logicals, ++ OUT gctUINT32 *Bytes ++ ) ++{ ++ gceSTATUS status; ++ int i = 0; ++ gctSIZE_T pageCount; ++ gckVIRTUAL_COMMAND_BUFFER_PTR commandBuffer; ++ gckKERNEL kernel = Context->hardware->kernel; ++ gctPOINTER logical; ++ gctPHYS_ADDR physical; ++ ++ gcsCONTEXT_PTR buffer; ++ ++ gcmkHEADER(); ++ ++ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT); ++ ++ buffer = Context->buffer; ++ ++ for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i++) ++ { ++ if (kernel->virtualCommandBuffer) ++ { ++ commandBuffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)buffer->physical; ++ physical = commandBuffer->physical; ++ ++ gcmkONERROR(gckOS_CreateUserVirtualMapping( ++ kernel->os, ++ physical, ++ Context->totalSize, ++ &logical, ++ &pageCount)); ++ } ++ else ++ { ++ physical = buffer->physical; ++ ++ gcmkONERROR(gckOS_MapMemory( ++ kernel->os, ++ physical, ++ Context->totalSize, ++ &logical)); ++ } ++ ++ Physicals[i] = gcmPTR_TO_NAME(physical); ++ ++ Logicals[i] = gcmPTR_TO_UINT64(logical); ++ ++ buffer = buffer->next; ++ } ++ ++ *Bytes = (gctUINT)Context->totalSize; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.h linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_context.h +--- linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_context.h 2016-06-19 22:11:55.125151817 +0200 +@@ -0,0 +1,178 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_context_h_ ++#define __gc_hal_kernel_context_h_ ++ ++#include "gc_hal_kernel_buffer.h" ++ ++/* Exprimental optimization. */ ++#define REMOVE_DUPLICATED_COPY_FROM_USER 1 ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Maps state locations within the context buffer. */ ++typedef struct _gcsSTATE_MAP * gcsSTATE_MAP_PTR; ++typedef struct _gcsSTATE_MAP ++{ ++ /* Index of the state in the context buffer. */ ++ gctUINT index; ++ ++ /* State mask. */ ++ gctUINT32 mask; ++} ++gcsSTATE_MAP; ++ ++/* Context buffer. */ ++typedef struct _gcsCONTEXT * gcsCONTEXT_PTR; ++typedef struct _gcsCONTEXT ++{ ++ /* For debugging: the number of context buffer in the order of creation. */ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++ gctUINT num; ++#endif ++ ++ /* Pointer to gckEVENT object. */ ++ gckEVENT eventObj; ++ ++ /* Context busy signal. */ ++ gctSIGNAL signal; ++ ++ /* Physical address of the context buffer. */ ++ gctPHYS_ADDR physical; ++ ++ /* Logical address of the context buffer. */ ++ gctUINT32_PTR logical; ++ ++ /* Hardware address of the context buffer. */ ++ gctUINT32 address; ++ ++ /* Pointer to the LINK commands. */ ++ gctPOINTER link2D; ++ gctPOINTER link3D; ++ ++ /* The number of pending state deltas. */ ++ gctUINT deltaCount; ++ ++ /* Pointer to the first delta to be applied. */ ++ gcsSTATE_DELTA_PTR delta; ++ ++ /* Next context buffer. */ ++ gcsCONTEXT_PTR next; ++} ++gcsCONTEXT; ++ ++typedef struct _gcsRECORD_ARRAY_MAP * gcsRECORD_ARRAY_MAP_PTR; ++struct _gcsRECORD_ARRAY_MAP ++{ ++ /* User pointer key. */ ++ gctUINT64 key; ++ ++ /* Kernel memory buffer. */ ++ gcsSTATE_DELTA_RECORD_PTR kData; ++ ++ /* Next map. */ ++ gcsRECORD_ARRAY_MAP_PTR next; ++ ++}; ++ ++/* gckCONTEXT structure that hold the current context. */ ++struct _gckCONTEXT ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gckOS object. */ ++ gckOS os; ++ ++ /* Pointer to gckHARDWARE object. */ ++ gckHARDWARE hardware; ++ ++ /* Command buffer alignment. */ ++ gctUINT32 alignment; ++ gctUINT32 reservedHead; ++ gctUINT32 reservedTail; ++ ++ /* Context buffer metrics. */ ++ gctSIZE_T stateCount; ++ gctUINT32 totalSize; ++ gctUINT32 bufferSize; ++ gctUINT32 linkIndex2D; ++ gctUINT32 linkIndex3D; ++ gctUINT32 linkIndexXD; ++ gctUINT32 entryOffset3D; ++ gctUINT32 entryOffsetXDFrom2D; ++ gctUINT32 entryOffsetXDFrom3D; ++ ++ /* Dirty flags. */ ++ gctBOOL dirty; ++ gctBOOL dirty2D; ++ gctBOOL dirty3D; ++ gcsCONTEXT_PTR dirtyBuffer; ++ ++ /* State mapping. */ ++ gcsSTATE_MAP_PTR map; ++ ++ /* List of context buffers. */ ++ gcsCONTEXT_PTR buffer; ++ ++ /* A copy of the user record array. */ ++ gctUINT recordArraySize; ++#if REMOVE_DUPLICATED_COPY_FROM_USER ++ gcsRECORD_ARRAY_MAP_PTR recordArrayMap; ++#else ++ gcsSTATE_DELTA_RECORD_PTR recordArray; ++#endif ++ ++ /* Requested pipe select for context. */ ++ gcePIPE_SELECT entryPipe; ++ gcePIPE_SELECT exitPipe; ++ ++ /* Variables used for building state buffer. */ ++ gctUINT32 lastAddress; ++ gctSIZE_T lastSize; ++ gctUINT32 lastIndex; ++ gctBOOL lastFixed; ++ ++ gctUINT32 pipeSelectBytes; ++ ++#if VIVANTE_PROFILER_CONTEXT ++ gcsPROFILER_COUNTERS latestProfiler; ++ gcsPROFILER_COUNTERS histroyProfiler; ++ gctUINT32 prevVSInstCount; ++ gctUINT32 prevVSBranchInstCount; ++ gctUINT32 prevVSTexInstCount; ++ gctUINT32 prevVSVertexCount; ++ gctUINT32 prevPSInstCount; ++ gctUINT32 prevPSBranchInstCount; ++ gctUINT32 prevPSTexInstCount; ++ gctUINT32 prevPSPixelCount; ++#endif ++}; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_kernel_context_h_ */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c +--- linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c 2016-06-19 22:11:55.129151555 +0200 +@@ -0,0 +1,7719 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal.h" ++#include "gc_hal_kernel.h" ++#if VIVANTE_PROFILER_CONTEXT ++#include "gc_hal_kernel_context.h" ++#endif ++ ++#define gcdDISABLE_FE_L2 1 ++ ++#define _GC_OBJ_ZONE gcvZONE_HARDWARE ++ ++#define gcmSEMAPHORESTALL(buffer) \ ++ do \ ++ { \ ++ /* Arm the PE-FE Semaphore. */ \ ++ *buffer++ \ ++ = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, 1) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, 0x0E02); \ ++ \ ++ *buffer++ \ ++ = gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END) \ ++ | gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE);\ ++ \ ++ /* STALL FE until PE is done flushing. */ \ ++ *buffer++ \ ++ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \ ++ \ ++ *buffer++ \ ++ = gcmSETFIELDVALUE(0, STALL_STALL, SOURCE, FRONT_END) \ ++ | gcmSETFIELDVALUE(0, STALL_STALL, DESTINATION, PIXEL_ENGINE); \ ++ } while(0) ++ ++typedef struct _gcsiDEBUG_REGISTERS * gcsiDEBUG_REGISTERS_PTR; ++typedef struct _gcsiDEBUG_REGISTERS ++{ ++ gctSTRING module; ++ gctUINT index; ++ gctUINT shift; ++ gctUINT data; ++ gctUINT count; ++ gctUINT32 signature; ++} ++gcsiDEBUG_REGISTERS; ++ ++/******************************************************************************\ ++********************************* Support Code ********************************* ++\******************************************************************************/ ++static gctBOOL ++_IsHardwareMatch( ++ IN gckHARDWARE Hardware, ++ IN gctINT32 ChipModel, ++ IN gctUINT32 ChipRevision ++ ) ++{ ++ return ((Hardware->identity.chipModel == ChipModel) && ++ (Hardware->identity.chipRevision == ChipRevision)); ++} ++ ++static gceSTATUS ++_ResetGPU( ++ IN gckHARDWARE Hardware, ++ IN gckOS Os, ++ IN gceCORE Core ++ ); ++ ++static gceSTATUS ++_IdentifyHardware( ++ IN gckOS Os, ++ IN gceCORE Core, ++ OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity ++ ) ++{ ++ gceSTATUS status; ++ ++ gctUINT32 chipIdentity; ++ ++ gctUINT32 streamCount = 0; ++ gctUINT32 registerMax = 0; ++ gctUINT32 threadCount = 0; ++ gctUINT32 shaderCoreCount = 0; ++ gctUINT32 vertexCacheSize = 0; ++ gctUINT32 vertexOutputBufferSize = 0; ++ gctUINT32 pixelPipes = 0; ++ gctUINT32 instructionCount = 0; ++ gctUINT32 numConstants = 0; ++ gctUINT32 bufferSize = 0; ++ gctUINT32 varyingsCount = 0; ++ ++ gcmkHEADER_ARG("Os=0x%x", Os); ++ ++ /*************************************************************************** ++ ** Get chip ID and revision. ++ */ ++ ++ /* Read chip identity register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00018, ++ &chipIdentity)); ++ ++ /* Special case for older graphic cores. */ ++ if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))))) ++ { ++ Identity->chipModel = gcv500; ++ Identity->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) ); ++ } ++ ++ else ++ { ++ /* Read chip identity register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00020, ++ (gctUINT32_PTR) &Identity->chipModel)); ++ ++ if (((Identity->chipModel & 0xFF00) == 0x0400) ++ && (Identity->chipModel != 0x0420) ++ && (Identity->chipModel != 0x0428)) ++ { ++ Identity->chipModel = (gceCHIPMODEL) (Identity->chipModel & 0x0400); ++ } ++ ++ /* Read CHIP_REV register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00024, ++ &Identity->chipRevision)); ++ ++ if ((Identity->chipModel == gcv300) ++ && (Identity->chipRevision == 0x2201) ++ ) ++ { ++ gctUINT32 chipDate; ++ gctUINT32 chipTime; ++ ++ /* Read date and time registers. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00028, ++ &chipDate)); ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x0002C, ++ &chipTime)); ++ ++ if ((chipDate == 0x20080814) && (chipTime == 0x12051100)) ++ { ++ /* This IP has an ECO; put the correct revision in it. */ ++ Identity->chipRevision = 0x1051; ++ } ++ } ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x000A8, ++ &Identity->productID)); ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipModel=%X", ++ Identity->chipModel); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipRevision=%X", ++ Identity->chipRevision); ++ ++ ++ /*************************************************************************** ++ ** Get chip features. ++ */ ++ ++ /* Read chip feature register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x0001C, ++ &Identity->chipFeatures)); ++ ++#if gcdENABLE_3D ++ /* Disable fast clear on GC700. */ ++ if (Identity->chipModel == gcv700) ++ { ++ Identity->chipFeatures ++ = ((((gctUINT32) (Identity->chipFeatures)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ } ++#endif ++ ++ if (((Identity->chipModel == gcv500) && (Identity->chipRevision < 2)) ++ || ((Identity->chipModel == gcv300) && (Identity->chipRevision < 0x2000)) ++ ) ++ { ++ /* GC500 rev 1.x and GC300 rev < 2.0 doesn't have these registers. */ ++ Identity->chipMinorFeatures = 0; ++ Identity->chipMinorFeatures1 = 0; ++ Identity->chipMinorFeatures2 = 0; ++ Identity->chipMinorFeatures3 = 0; ++ Identity->chipMinorFeatures4 = 0; ++ Identity->chipMinorFeatures5 = 0; ++ } ++ else ++ { ++ /* Read chip minor feature register #0. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00034, ++ &Identity->chipMinorFeatures)); ++ ++ if (((((gctUINT32) (Identity->chipMinorFeatures)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) ++ ) ++ { ++ /* Read chip minor featuress register #1. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00074, ++ &Identity->chipMinorFeatures1)); ++ ++ /* Read chip minor featuress register #2. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00084, ++ &Identity->chipMinorFeatures2)); ++ ++ /*Identity->chipMinorFeatures2 &= ~(0x1 << 3);*/ ++ ++ /* Read chip minor featuress register #1. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00088, ++ &Identity->chipMinorFeatures3)); ++ ++ ++ /* Read chip minor featuress register #4. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00094, ++ &Identity->chipMinorFeatures4)); ++ ++ /* Read chip minor featuress register #5. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x000A0, ++ &Identity->chipMinorFeatures5)); ++ } ++ else ++ { ++ /* Chip doesn't has minor features register #1 or 2 or 3 or 4. */ ++ Identity->chipMinorFeatures1 = 0; ++ Identity->chipMinorFeatures2 = 0; ++ Identity->chipMinorFeatures3 = 0; ++ Identity->chipMinorFeatures4 = 0; ++ Identity->chipMinorFeatures5 = 0; ++ } ++ } ++ ++ /* Get the Supertile layout in the hardware. */ ++ if (((((gctUINT32) (Identity->chipMinorFeatures3)) >> (0 ? 26:26) & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) ++ || ((((gctUINT32) (Identity->chipMinorFeatures3)) >> (0 ? 8:8) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1)))))))) ++ { ++ Identity->superTileMode = 2; ++ } ++ else if (((((gctUINT32) (Identity->chipMinorFeatures)) >> (0 ? 27:27) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1)))))))) ++ { ++ Identity->superTileMode = 1; ++ } ++ else ++ { ++ Identity->superTileMode = 0; ++ } ++ ++ /* Exception for GC1000, revision 5035 & GC800, revision 4612 */ ++ if (((Identity->chipModel == gcv1000) && ((Identity->chipRevision == 0x5035) ++ || (Identity->chipRevision == 0x5036) ++ || (Identity->chipRevision == 0x5037) ++ || (Identity->chipRevision == 0x5039) ++ || (Identity->chipRevision >= 0x5040))) ++ || ((Identity->chipModel == gcv800) && (Identity->chipRevision == 0x4612)) ++ || ((Identity->chipModel == gcv600) && (Identity->chipRevision >= 0x4650)) ++ || ((Identity->chipModel == gcv860) && (Identity->chipRevision == 0x4647)) ++ || ((Identity->chipModel == gcv400) && (Identity->chipRevision >= 0x4633))) ++ { ++ Identity->superTileMode = 1; ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipFeatures=0x%08X", ++ Identity->chipFeatures); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipMinorFeatures=0x%08X", ++ Identity->chipMinorFeatures); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipMinorFeatures1=0x%08X", ++ Identity->chipMinorFeatures1); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipMinorFeatures2=0x%08X", ++ Identity->chipMinorFeatures2); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipMinorFeatures3=0x%08X", ++ Identity->chipMinorFeatures3); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipMinorFeatures4=0x%08X", ++ Identity->chipMinorFeatures4); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipMinorFeatures5=0x%08X", ++ Identity->chipMinorFeatures5); ++ ++ /*************************************************************************** ++ ** Get chip specs. ++ */ ++ ++ if (((((gctUINT32) (Identity->chipMinorFeatures)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))) ++ { ++ gctUINT32 specs, specs2, specs3, specs4; ++ ++ /* Read gcChipSpecs register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00048, ++ &specs)); ++ ++ /* Extract the fields. */ ++ registerMax = (((((gctUINT32) (specs)) >> (0 ? 7:4)) & ((gctUINT32) ((((1 ? 7:4) - (0 ? 7:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:4) - (0 ? 7:4) + 1)))))) ); ++ threadCount = (((((gctUINT32) (specs)) >> (0 ? 11:8)) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1)))))) ); ++ shaderCoreCount = (((((gctUINT32) (specs)) >> (0 ? 24:20)) & ((gctUINT32) ((((1 ? 24:20) - (0 ? 24:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:20) - (0 ? 24:20) + 1)))))) ); ++ vertexCacheSize = (((((gctUINT32) (specs)) >> (0 ? 16:12)) & ((gctUINT32) ((((1 ? 16:12) - (0 ? 16:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:12) - (0 ? 16:12) + 1)))))) ); ++ vertexOutputBufferSize = (((((gctUINT32) (specs)) >> (0 ? 31:28)) & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1)))))) ); ++ pixelPipes = (((((gctUINT32) (specs)) >> (0 ? 27:25)) & ((gctUINT32) ((((1 ? 27:25) - (0 ? 27:25) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:25) - (0 ? 27:25) + 1)))))) ); ++ ++ /* Read gcChipSpecs2 register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x00080, ++ &specs2)); ++ ++ instructionCount = (((((gctUINT32) (specs2)) >> (0 ? 15:8)) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1)))))) ); ++ numConstants = (((((gctUINT32) (specs2)) >> (0 ? 31:16)) & ((gctUINT32) ((((1 ? 31:16) - (0 ? 31:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:16) - (0 ? 31:16) + 1)))))) ); ++ bufferSize = (((((gctUINT32) (specs2)) >> (0 ? 7:0)) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1)))))) ); ++ ++ /* Read gcChipSpecs3 register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x0008C, ++ &specs3)); ++ ++ varyingsCount = (((((gctUINT32) (specs3)) >> (0 ? 8:4)) & ((gctUINT32) ((((1 ? 8:4) - (0 ? 8:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:4) - (0 ? 8:4) + 1)))))) ); ++ ++ /* Read gcChipSpecs4 register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, Core, ++ 0x0009C, ++ &specs4)); ++ ++ ++ streamCount = (((((gctUINT32) (specs4)) >> (0 ? 16:12)) & ((gctUINT32) ((((1 ? 16:12) - (0 ? 16:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:12) - (0 ? 16:12) + 1)))))) ); ++ if (streamCount == 0) ++ { ++ /* Extract stream count from older register. */ ++ streamCount = (((((gctUINT32) (specs)) >> (0 ? 3:0)) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1)))))) ); ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipSpecs1=0x%08X", ++ specs); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipSpecs2=0x%08X", ++ specs2); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipSpecs3=0x%08X", ++ specs3); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Identity: chipSpecs4=0x%08X", ++ specs4); ++ } ++ ++ /* Get the number of pixel pipes. */ ++ Identity->pixelPipes = gcmMAX(pixelPipes, 1); ++ ++ /* Get the stream count. */ ++ Identity->streamCount = (streamCount != 0) ++ ? streamCount ++ : (Identity->chipModel >= gcv1000) ? 4 : 1; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: streamCount=%u%s", ++ Identity->streamCount, ++ (streamCount == 0) ? " (default)" : ""); ++ ++ /* Get the vertex output buffer size. */ ++ Identity->vertexOutputBufferSize = (vertexOutputBufferSize != 0) ++ ? 1 << vertexOutputBufferSize ++ : (Identity->chipModel == gcv400) ++ ? (Identity->chipRevision < 0x4000) ? 512 ++ : (Identity->chipRevision < 0x4200) ? 256 ++ : 128 ++ : (Identity->chipModel == gcv530) ++ ? (Identity->chipRevision < 0x4200) ? 512 ++ : 128 ++ : 512; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: vertexOutputBufferSize=%u%s", ++ Identity->vertexOutputBufferSize, ++ (vertexOutputBufferSize == 0) ? " (default)" : ""); ++ ++ /* Get the maximum number of threads. */ ++ Identity->threadCount = (threadCount != 0) ++ ? 1 << threadCount ++ : (Identity->chipModel == gcv400) ? 64 ++ : (Identity->chipModel == gcv500) ? 128 ++ : (Identity->chipModel == gcv530) ? 128 ++ : 256; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: threadCount=%u%s", ++ Identity->threadCount, ++ (threadCount == 0) ? " (default)" : ""); ++ ++ /* Get the number of shader cores. */ ++ Identity->shaderCoreCount = (shaderCoreCount != 0) ++ ? shaderCoreCount ++ : (Identity->chipModel >= gcv1000) ? 2 ++ : 1; ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: shaderCoreCount=%u%s", ++ Identity->shaderCoreCount, ++ (shaderCoreCount == 0) ? " (default)" : ""); ++ ++ /* Get the vertex cache size. */ ++ Identity->vertexCacheSize = (vertexCacheSize != 0) ++ ? vertexCacheSize ++ : 8; ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: vertexCacheSize=%u%s", ++ Identity->vertexCacheSize, ++ (vertexCacheSize == 0) ? " (default)" : ""); ++ ++ /* Get the maximum number of temporary registers. */ ++ Identity->registerMax = (registerMax != 0) ++ /* Maximum of registerMax/4 registers are accessible to 1 shader */ ++ ? 1 << registerMax ++ : (Identity->chipModel == gcv400) ? 32 ++ : 64; ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: registerMax=%u%s", ++ Identity->registerMax, ++ (registerMax == 0) ? " (default)" : ""); ++ ++ /* Get the instruction count. */ ++ Identity->instructionCount = (instructionCount == 0) ? 256 ++ : (instructionCount == 1) ? 1024 ++ : (instructionCount == 2) ? 2048 ++ : (instructionCount == 0xFF) ? 512 ++ : 256; ++ ++ if (Identity->instructionCount == 256) ++ { ++ if ((Identity->chipModel == gcv2000 && Identity->chipRevision == 0x5108) ++ || Identity->chipModel == gcv880) ++ { ++ Identity->instructionCount = 512; ++ } ++ else if (((((gctUINT32) (Identity->chipMinorFeatures3)) >> (0 ? 3:3) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))))) ++ { ++ Identity->instructionCount = 512; ++ } ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: instructionCount=%u%s", ++ Identity->instructionCount, ++ (instructionCount == 0) ? " (default)" : ""); ++ ++ /* Get the number of constants. */ ++ Identity->numConstants = (numConstants == 0) ? 168 : numConstants; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: numConstants=%u%s", ++ Identity->numConstants, ++ (numConstants == 0) ? " (default)" : ""); ++ ++ /* Get the buffer size. */ ++ Identity->bufferSize = bufferSize; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Specs: bufferSize=%u%s", ++ Identity->bufferSize, ++ (bufferSize == 0) ? " (default)" : ""); ++ ++ ++ if (varyingsCount != 0) ++ { ++ Identity->varyingsCount = varyingsCount; ++ } ++ else if (((((gctUINT32) (Identity->chipMinorFeatures1)) >> (0 ? 23:23) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))))) ++ { ++ Identity->varyingsCount = 12; ++ } ++ else ++ { ++ Identity->varyingsCount = 8; ++ } ++ ++ /* For some cores, it consumes two varying for position, so the max varying vectors should minus one. */ ++ if ((Identity->chipModel == gcv5000 && Identity->chipRevision == 0x5434) || ++ (Identity->chipModel == gcv4000 && Identity->chipRevision == 0x5222) || ++ (Identity->chipModel == gcv4000 && Identity->chipRevision == 0x5208) || ++ (Identity->chipModel == gcv4000 && Identity->chipRevision == 0x5245) || ++ (Identity->chipModel == gcv3000 && Identity->chipRevision == 0x5435) || ++ (Identity->chipModel == gcv2200 && Identity->chipRevision == 0x5244) || ++ (Identity->chipModel == gcv1500 && Identity->chipRevision == 0x5246) || ++ ((Identity->chipModel == gcv2100 || Identity->chipModel == gcv2000) && Identity->chipRevision == 0x5108) || ++ (Identity->chipModel == gcv880 && (Identity->chipRevision == 0x5107 || Identity->chipRevision == 0x5106))) ++ { ++ Identity->varyingsCount -= 1; ++ } ++ ++ Identity->chip2DControl = 0; ++ if (Identity->chipModel == gcv320) ++ { ++ gctUINT32 data; ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Os, ++ Core, ++ 0x0002C, ++ &data)); ++ ++ if ((data != 33956864) && ++ ((Identity->chipRevision == 0x5007) || ++ (Identity->chipRevision == 0x5220))) ++ { ++ Identity->chip2DControl |= 0xFF & ++ (Identity->chipRevision == 0x5220 ? 8 : ++ (Identity->chipRevision == 0x5007 ? 12 : 0)); ++ } ++ ++ if (Identity->chipRevision == 0x5007) ++ { ++ /* Disable splitting rectangle. */ ++ Identity->chip2DControl |= 0x100; ++ ++ /* Enable 2D Flush. */ ++ Identity->chip2DControl |= 0x200; ++ } ++ } ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#define gcdDEBUG_MODULE_CLOCK_GATING 0 ++#define gcdDISABLE_MODULE_CLOCK_GATING 0 ++#define gcdDISABLE_FE_CLOCK_GATING 0 ++#define gcdDISABLE_PE_CLOCK_GATING 0 ++#define gcdDISABLE_SH_CLOCK_GATING 0 ++#define gcdDISABLE_PA_CLOCK_GATING 0 ++#define gcdDISABLE_SE_CLOCK_GATING 0 ++#define gcdDISABLE_RA_CLOCK_GATING 0 ++#define gcdDISABLE_RA_EZ_CLOCK_GATING 0 ++#define gcdDISABLE_RA_HZ_CLOCK_GATING 0 ++#define gcdDISABLE_TX_CLOCK_GATING 0 ++ ++#if gcdDEBUG_MODULE_CLOCK_GATING ++gceSTATUS ++_ConfigureModuleLevelClockGating( ++ gckHARDWARE Hardware ++ ) ++{ ++ gctUINT32 data; ++ ++ gcmkVERIFY_OK( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ &data)); ++ ++#if gcdDISABLE_FE_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++#endif ++ ++#if gcdDISABLE_PE_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); ++#endif ++ ++#if gcdDISABLE_SH_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))); ++#endif ++ ++#if gcdDISABLE_PA_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); ++#endif ++ ++#if gcdDISABLE_SE_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); ++#endif ++ ++#if gcdDISABLE_RA_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++#endif ++ ++#if gcdDISABLE_TX_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))); ++#endif ++ ++#if gcdDISABLE_RA_EZ_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))); ++#endif ++ ++#if gcdDISABLE_RA_HZ_CLOCK_GATING ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))); ++#endif ++ ++ gcmkVERIFY_OK( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ data)); ++ ++#if gcdDISABLE_MODULE_CLOCK_GATING ++ gcmkVERIFY_OK( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress + ++ 0x00100, ++ &data)); ++ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ ++ gcmkVERIFY_OK( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00100, ++ data)); ++#endif ++ ++ return gcvSTATUS_OK; ++} ++#endif ++ ++#if gcdPOWEROFF_TIMEOUT ++void ++_PowerTimerFunction( ++ gctPOINTER Data ++ ) ++{ ++ gckHARDWARE hardware = (gckHARDWARE)Data; ++ gcmkVERIFY_OK( ++ gckHARDWARE_SetPowerManagementState(hardware, gcvPOWER_OFF_TIMEOUT)); ++} ++#endif ++ ++static gceSTATUS ++_VerifyDMA( ++ IN gckOS Os, ++ IN gceCORE Core, ++ gctUINT32_PTR Address1, ++ gctUINT32_PTR Address2, ++ gctUINT32_PTR State1, ++ gctUINT32_PTR State2 ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 i; ++ ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x660, State1)); ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x664, Address1)); ++ ++ for (i = 0; i < 500; i += 1) ++ { ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x660, State2)); ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x664, Address2)); ++ ++ if (*Address1 != *Address2) ++ { ++ break; ++ } ++ ++ if (*State1 != *State2) ++ { ++ break; ++ } ++ } ++ ++OnError: ++ return status; ++} ++ ++static gceSTATUS ++_DumpDebugRegisters( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gcsiDEBUG_REGISTERS_PTR Descriptor ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gctUINT32 select; ++ gctUINT32 data = 0; ++ gctUINT i; ++ ++ gcmkHEADER_ARG("Os=0x%X Descriptor=0x%X", Os, Descriptor); ++ ++ gcmkPRINT_N(4, " %s debug registers:\n", Descriptor->module); ++ ++ for (i = 0; i < Descriptor->count; i += 1) ++ { ++ select = i << Descriptor->shift; ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, select)); ++#if gcdFPGA_BUILD ++ gcmkONERROR(gckOS_Delay(Os, 1000)); ++#endif ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &data)); ++ ++ gcmkPRINT_N(12, " [0x%02X] 0x%08X\n", i, data); ++ } ++ ++ select = 0xF << Descriptor->shift; ++ ++ for (i = 0; i < 500; i += 1) ++ { ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, select)); ++#if gcdFPGA_BUILD ++ gcmkONERROR(gckOS_Delay(Os, 1000)); ++#endif ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &data)); ++ ++ if (data == Descriptor->signature) ++ { ++ break; ++ } ++ } ++ ++ if (i == 500) ++ { ++ gcmkPRINT_N(4, " failed to obtain the signature (read 0x%08X).\n", data); ++ } ++ else ++ { ++ gcmkPRINT_N(8, " signature = 0x%08X (%d read attempt(s))\n", data, i + 1); ++ } ++ ++OnError: ++ /* Return the error. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++_IsGPUPresent( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 control; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ &control)); ++ ++ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))); ++ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ control)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the error. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++_FlushCache( ++ gckHARDWARE Hardware, ++ gckCOMMAND Command ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 bytes, requested; ++ gctPOINTER buffer; ++ ++ /* Get the size of the flush command. */ ++ gcmkONERROR(gckHARDWARE_Flush(Hardware, ++ gcvFLUSH_ALL, ++ gcvNULL, ++ &requested)); ++ ++ /* Reserve space in the command queue. */ ++ gcmkONERROR(gckCOMMAND_Reserve(Command, ++ requested, ++ &buffer, ++ &bytes)); ++ ++ /* Append a flush. */ ++ gcmkONERROR(gckHARDWARE_Flush( ++ Hardware, gcvFLUSH_ALL, buffer, &bytes ++ )); ++ ++ /* Execute the command queue. */ ++ gcmkONERROR(gckCOMMAND_Execute(Command, requested)); ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++gctBOOL ++_IsGPUIdle( ++ IN gctUINT32 Idle ++ ) ++{ ++ return (((((gctUINT32) (Idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) ++ && (((((gctUINT32) (Idle)) >> (0 ? 1:1)) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1)))))) ) ++ && (((((gctUINT32) (Idle)) >> (0 ? 3:3)) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) ) ++ && (((((gctUINT32) (Idle)) >> (0 ? 4:4)) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1)))))) ) ++ && (((((gctUINT32) (Idle)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) ) ++ && (((((gctUINT32) (Idle)) >> (0 ? 6:6)) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1)))))) ) ++ && (((((gctUINT32) (Idle)) >> (0 ? 7:7)) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1)))))) ) ++ && (((((gctUINT32) (Idle)) >> (0 ? 2:2)) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1)))))) ) ++ ; ++} ++ ++/******************************************************************************\ ++****************************** gckHARDWARE API code ***************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Construct ++** ++** Construct a new gckHARDWARE object. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an initialized gckOS object. ++** ++** gceCORE Core ++** Specified core. ++** ++** OUTPUT: ++** ++** gckHARDWARE * Hardware ++** Pointer to a variable that will hold the pointer to the gckHARDWARE ++** object. ++*/ ++gceSTATUS ++gckHARDWARE_Construct( ++ IN gckOS Os, ++ IN gceCORE Core, ++ OUT gckHARDWARE * Hardware ++ ) ++{ ++ gceSTATUS status; ++ gckHARDWARE hardware = gcvNULL; ++ gctUINT16 data = 0xff00; ++ gctPOINTER pointer = gcvNULL; ++ ++ gcmkHEADER_ARG("Os=0x%x", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Hardware != gcvNULL); ++ ++ /* Enable the GPU. */ ++ gcmkONERROR(gckOS_SetGPUPower(Os, Core, gcvTRUE, gcvTRUE)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x00000, ++ 0x00000900)); ++ ++ /* Allocate the gckHARDWARE object. */ ++ gcmkONERROR(gckOS_Allocate(Os, ++ gcmSIZEOF(struct _gckHARDWARE), ++ &pointer)); ++ ++ hardware = (gckHARDWARE) pointer; ++ ++ /* Initialize the gckHARDWARE object. */ ++ hardware->object.type = gcvOBJ_HARDWARE; ++ hardware->os = Os; ++ hardware->core = Core; ++ ++ /* Identify the hardware. */ ++ gcmkONERROR(_IdentifyHardware(Os, Core, &hardware->identity)); ++ ++ /* Determine the hardware type */ ++ switch (hardware->identity.chipModel) ++ { ++ case gcv350: ++ case gcv355: ++ hardware->type = gcvHARDWARE_VG; ++ break; ++ ++ case gcv200: ++ case gcv300: ++ case gcv320: ++ case gcv328: ++ case gcv420: ++ case gcv428: ++ hardware->type = gcvHARDWARE_2D; ++ break; ++ ++ default: ++ hardware->type = gcvHARDWARE_3D; ++ ++ if(hardware->identity.chipModel == gcv880 && hardware->identity.chipRevision == 0x5107) ++ { ++ /*set outstanding limit*/ ++ gctUINT32 axi_ot; ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00414, &axi_ot)); ++ axi_ot = (axi_ot & (~0xFF)) | 0x00010; ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00414, axi_ot)); ++ } ++ ++ ++ if ((((((gctUINT32) (hardware->identity.chipFeatures)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) )) ++ { ++ hardware->type = (gceHARDWARE_TYPE) (hardware->type | gcvHARDWARE_2D); ++ } ++ } ++ ++ hardware->powerBaseAddress ++ = ((hardware->identity.chipModel == gcv300) ++ && (hardware->identity.chipRevision < 0x2000)) ++ ? 0x0100 ++ : 0x0000; ++ ++ /* _ResetGPU need powerBaseAddress. */ ++ status = _ResetGPU(hardware, Os, Core); ++ ++ if (status != gcvSTATUS_OK) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "_ResetGPU failed: status=%d\n", status); ++ } ++ ++ hardware->powerMutex = gcvNULL; ++ ++ hardware->mmuVersion ++ = (((((gctUINT32) (hardware->identity.chipMinorFeatures1)) >> (0 ? 28:28)) & ((gctUINT32) ((((1 ? 28:28) - (0 ? 28:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 28:28) - (0 ? 28:28) + 1)))))) ); ++ ++ /* Determine whether bug fixes #1 are present. */ ++ hardware->extraEventStates = ((((gctUINT32) (hardware->identity.chipMinorFeatures1)) >> (0 ? 3:3) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))); ++ ++ /* Check if big endian */ ++ hardware->bigEndian = (*(gctUINT8 *)&data == 0xff); ++ ++ /* Initialize the fast clear. */ ++ gcmkONERROR(gckHARDWARE_SetFastClear(hardware, -1, -1)); ++ ++#if !gcdENABLE_128B_MERGE ++ ++ if (((((gctUINT32) (hardware->identity.chipMinorFeatures2)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))) ++ { ++ /* 128B merge is turned on by default. Disable it. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00558, 0)); ++ } ++ ++#endif ++ ++ /* Set power state to ON. */ ++ hardware->chipPowerState = gcvPOWER_ON; ++ hardware->clockState = gcvTRUE; ++ hardware->powerState = gcvTRUE; ++ hardware->lastWaitLink = ~0U; ++ hardware->lastEnd = ~0U; ++ hardware->globalSemaphore = gcvNULL; ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ hardware->powerOnFscaleVal = 64; ++#endif ++ ++ gcmkONERROR(gckOS_CreateMutex(Os, &hardware->powerMutex)); ++ gcmkONERROR(gckOS_CreateSemaphore(Os, &hardware->globalSemaphore)); ++ hardware->startIsr = gcvNULL; ++ hardware->stopIsr = gcvNULL; ++ ++#if gcdPOWEROFF_TIMEOUT ++ hardware->powerOffTimeout = gcdPOWEROFF_TIMEOUT; ++ ++ gcmkVERIFY_OK(gckOS_CreateTimer(Os, ++ _PowerTimerFunction, ++ (gctPOINTER)hardware, ++ &hardware->powerOffTimer)); ++#endif ++ ++ gcmkONERROR(gckOS_AtomConstruct(Os, &hardware->pageTableDirty)); ++ gcmkONERROR(gckOS_AtomConstruct(Os, &hardware->pendingEvent)); ++ ++#if gcdLINK_QUEUE_SIZE ++ hardware->linkQueue.front = 0; ++ hardware->linkQueue.rear = 0; ++ hardware->linkQueue.count = 0; ++#endif ++ ++ /* Enable power management by default. */ ++ hardware->powerManagement = gcvTRUE; ++ ++ /* Disable profiler by default */ ++ hardware->gpuProfiler = gcvFALSE; ++ ++ if (hardware->mmuVersion) ++ { ++ hardware->endAfterFlushMmuCache = gcvTRUE; ++ } ++ else ++ { ++ hardware->endAfterFlushMmuCache = gcvFALSE; ++ } ++ ++ gcmkONERROR(gckOS_QueryOption(Os, "mmu", (gctUINT32_PTR)&hardware->enableMMU)); ++ ++ hardware->minFscaleValue = 1; ++ ++ /* Return pointer to the gckHARDWARE object. */ ++ *Hardware = hardware; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Hardware=0x%x", *Hardware); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (hardware != gcvNULL) ++ { ++ /* Turn off the power. */ ++ gcmkVERIFY_OK(gckOS_SetGPUPower(Os, Core, gcvFALSE, gcvFALSE)); ++ ++ if (hardware->globalSemaphore != gcvNULL) ++ { ++ /* Destroy the global semaphore. */ ++ gcmkVERIFY_OK(gckOS_DestroySemaphore(Os, ++ hardware->globalSemaphore)); ++ } ++ ++ if (hardware->powerMutex != gcvNULL) ++ { ++ /* Destroy the power mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, hardware->powerMutex)); ++ } ++ ++#if gcdPOWEROFF_TIMEOUT ++ if (hardware->powerOffTimer != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_StopTimer(Os, hardware->powerOffTimer)); ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Os, hardware->powerOffTimer)); ++ } ++#endif ++ ++ if (hardware->pageTableDirty != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pageTableDirty)); ++ } ++ ++ if (hardware->pendingEvent != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pendingEvent)); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, hardware)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Destroy ++** ++** Destroy an gckHARDWARE object. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object that needs to be destroyed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_Destroy( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Destroy the power semaphore. */ ++ gcmkVERIFY_OK(gckOS_DestroySemaphore(Hardware->os, ++ Hardware->globalSemaphore)); ++ ++ /* Destroy the power mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Hardware->os, Hardware->powerMutex)); ++ ++#if gcdPOWEROFF_TIMEOUT ++ gcmkVERIFY_OK(gckOS_StopTimer(Hardware->os, Hardware->powerOffTimer)); ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Hardware->os, Hardware->powerOffTimer)); ++#endif ++ ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pageTableDirty)); ++ ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pendingEvent)); ++ ++ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory( ++ Hardware->os, ++ Hardware->functionBytes, ++ Hardware->functionPhysical, ++ Hardware->functionLogical ++ )); ++ ++ /* Mark the object as unknown. */ ++ Hardware->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the object. */ ++ gcmkONERROR(gcmkOS_SAFE_FREE(Hardware->os, Hardware)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_GetType ++** ++** Get the hardware type. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** OUTPUT: ++** ++** gceHARDWARE_TYPE * Type ++** Pointer to a variable that receives the type of hardware object. ++*/ ++gceSTATUS ++gckHARDWARE_GetType( ++ IN gckHARDWARE Hardware, ++ OUT gceHARDWARE_TYPE * Type ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ gcmkVERIFY_ARGUMENT(Type != gcvNULL); ++ ++ *Type = Hardware->type; ++ ++ gcmkFOOTER_ARG("*Type=%d", *Type); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_InitializeHardware ++** ++** Initialize the hardware. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_InitializeHardware( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 baseAddress; ++ gctUINT32 chipRev; ++ gctUINT32 control; ++ gctUINT32 data; ++ gctUINT32 regPMC = 0; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Read the chip revision register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00024, ++ &chipRev)); ++ ++ if (chipRev != Hardware->identity.chipRevision) ++ { ++ /* Chip is not there! */ ++ gcmkONERROR(gcvSTATUS_CONTEXT_LOSSED); ++ } ++ ++ /* Disable isolate GPU bit. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (0x00000900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))))); ++ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ &control)); ++ ++ /* Enable debug register. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))))); ++ ++ /* Reset memory counters. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0003C, ++ ~0U)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0003C, ++ 0)); ++ ++ /* Get the system's physical base address. */ ++ gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, &baseAddress)); ++ ++ /* Program the base addesses. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0041C, ++ baseAddress)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00418, ++ baseAddress)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00428, ++ baseAddress)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00420, ++ baseAddress)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00424, ++ baseAddress)); ++ ++ { ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress + ++ 0x00100, ++ &data)); ++ ++ /* Enable clock gating. */ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ if ((Hardware->identity.chipRevision == 0x4301) ++ || (Hardware->identity.chipRevision == 0x4302) ++ ) ++ { ++ /* Disable stall module level clock gating for 4.3.0.1 and 4.3.0.2 ++ ** revisions. */ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))); ++ } ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00100, ++ data)); ++ ++#if gcdENABLE_3D ++ /* Disable PE clock gating on revs < 5.0 when HZ is present without a ++ ** bug fix. */ ++ if ((Hardware->identity.chipRevision < 0x5000) ++ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HZ) ++ && ((((gctUINT32) (Hardware->identity.chipMinorFeatures1)) >> (0 ? 9:9) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) ++ ) ++ { ++ if (regPMC == 0) ++ { ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ ®PMC)); ++ } ++ ++ /* Disable PE clock gating. */ ++ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); ++ } ++ ++#endif ++ } ++ ++ if (Hardware->identity.chipModel == gcv4000 && ++ ((Hardware->identity.chipRevision == 0x5208) || (Hardware->identity.chipRevision == 0x5222))) ++ { ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23))))); ++ } ++ ++ if (Hardware->identity.chipModel == gcv1000 && ++ (Hardware->identity.chipRevision == 0x5039 || ++ Hardware->identity.chipRevision == 0x5040)) ++ { ++ gctUINT32 pulseEater; ++ ++ pulseEater = ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))); ++ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ ((((gctUINT32) (pulseEater)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))))); ++ } ++ ++ if ((gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI2) == gcvSTATUS_FALSE) ++ || (Hardware->identity.chipRevision < 0x5422) ++ ) ++ { ++ if (regPMC == 0) ++ { ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ ®PMC)); ++ } ++ ++ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:15) - (0 ? 15:15) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ? 15:15))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 15:15) - (0 ? 15:15) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ? 15:15))); ++ } ++ ++ if (_IsHardwareMatch(Hardware, gcv2000, 0x5108)) ++ { ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00480, ++ &data)); ++ ++ /* Set FE bus to one, TX bus to zero */ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))); ++ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00480, ++ data)); ++ } ++ ++ gcmkONERROR( ++ gckHARDWARE_SetMMU(Hardware, ++ Hardware->kernel->mmu->pageTableLogical)); ++ ++ if (Hardware->identity.chipModel >= gcv400 ++ && Hardware->identity.chipModel != gcv420) ++ { ++ if (regPMC == 0) ++ { ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ ®PMC)); ++ } ++ ++ /* Disable PA clock gating. */ ++ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); ++ } ++ ++ /* Limit 2D outstanding request. */ ++ if (_IsHardwareMatch(Hardware, gcv880, 0x5107)) ++ { ++ gctUINT32 axi_ot; ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00414, &axi_ot)); ++ axi_ot = (axi_ot & (~0xFF)) | 0x00010; ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00414, axi_ot)); ++ } ++ ++ if (Hardware->identity.chip2DControl & 0xFF) ++ { ++ gctUINT32 data; ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00414, ++ &data)); ++ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (Hardware->identity.chip2DControl & 0xFF) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))); ++ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00414, ++ data)); ++ } ++ ++ if (_IsHardwareMatch(Hardware, gcv1000, 0x5035)) ++ { ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00414, ++ &data)); ++ ++ /* Disable HZ-L2. */ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))); ++ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00414, ++ data)); ++ } ++ ++ if (_IsHardwareMatch(Hardware, gcv4000, 0x5222)) ++ { ++ if (regPMC == 0) ++ { ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ ®PMC)); ++ } ++ ++ /* Disable TX clock gating. */ ++ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))); ++ } ++ ++ if (_IsHardwareMatch(Hardware, gcv880, 0x5106)) ++ { ++ Hardware->kernel->timeOut = 140 * 1000; ++ } ++ ++ if (regPMC == 0) ++ { ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ ®PMC)); ++ } ++ ++ /* Disable RA HZ clock gating. */ ++ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))); ++ ++ /* Disable RA EZ clock gating. */ ++ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))); ++ ++ if (regPMC != 0) ++ { ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ regPMC)); ++ } ++ ++ if (_IsHardwareMatch(Hardware, gcv2000, 0x5108) ++ || _IsHardwareMatch(Hardware, gcv320, 0x5007) ++ || _IsHardwareMatch(Hardware, gcv880, 0x5106) ++ || _IsHardwareMatch(Hardware, gcv400, 0x4645) ++ ) ++ { ++ /* Update GPU AXI cache atttribute. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00008, ++ 0x00002200)); ++ } ++ ++ ++ if ((Hardware->identity.chipRevision > 0x5420) ++ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_3D)) ++ { ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ &data)); ++ ++ /* Disable internal DFS. */ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1))))))) << (0 ? 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1))))))) << (0 ? 18:18))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ data)); ++ } ++ ++#if gcdDEBUG_MODULE_CLOCK_GATING ++ _ConfigureModuleLevelClockGating(Hardware); ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the error. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_QueryMemory ++** ++** Query the amount of memory available on the hardware. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** OUTPUT: ++** ++** gctSIZE_T * InternalSize ++** Pointer to a variable that will hold the size of the internal video ++** memory in bytes. If 'InternalSize' is gcvNULL, no information of the ++** internal memory will be returned. ++** ++** gctUINT32 * InternalBaseAddress ++** Pointer to a variable that will hold the hardware's base address for ++** the internal video memory. This pointer cannot be gcvNULL if ++** 'InternalSize' is also non-gcvNULL. ++** ++** gctUINT32 * InternalAlignment ++** Pointer to a variable that will hold the hardware's base address for ++** the internal video memory. This pointer cannot be gcvNULL if ++** 'InternalSize' is also non-gcvNULL. ++** ++** gctSIZE_T * ExternalSize ++** Pointer to a variable that will hold the size of the external video ++** memory in bytes. If 'ExternalSize' is gcvNULL, no information of the ++** external memory will be returned. ++** ++** gctUINT32 * ExternalBaseAddress ++** Pointer to a variable that will hold the hardware's base address for ++** the external video memory. This pointer cannot be gcvNULL if ++** 'ExternalSize' is also non-gcvNULL. ++** ++** gctUINT32 * ExternalAlignment ++** Pointer to a variable that will hold the hardware's base address for ++** the external video memory. This pointer cannot be gcvNULL if ++** 'ExternalSize' is also non-gcvNULL. ++** ++** gctUINT32 * HorizontalTileSize ++** Number of horizontal pixels per tile. If 'HorizontalTileSize' is ++** gcvNULL, no horizontal pixel per tile will be returned. ++** ++** gctUINT32 * VerticalTileSize ++** Number of vertical pixels per tile. If 'VerticalTileSize' is ++** gcvNULL, no vertical pixel per tile will be returned. ++*/ ++gceSTATUS ++gckHARDWARE_QueryMemory( ++ IN gckHARDWARE Hardware, ++ OUT gctSIZE_T * InternalSize, ++ OUT gctUINT32 * InternalBaseAddress, ++ OUT gctUINT32 * InternalAlignment, ++ OUT gctSIZE_T * ExternalSize, ++ OUT gctUINT32 * ExternalBaseAddress, ++ OUT gctUINT32 * ExternalAlignment, ++ OUT gctUINT32 * HorizontalTileSize, ++ OUT gctUINT32 * VerticalTileSize ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (InternalSize != gcvNULL) ++ { ++ /* No internal memory. */ ++ *InternalSize = 0; ++ } ++ ++ if (ExternalSize != gcvNULL) ++ { ++ /* No external memory. */ ++ *ExternalSize = 0; ++ } ++ ++ if (HorizontalTileSize != gcvNULL) ++ { ++ /* 4x4 tiles. */ ++ *HorizontalTileSize = 4; ++ } ++ ++ if (VerticalTileSize != gcvNULL) ++ { ++ /* 4x4 tiles. */ ++ *VerticalTileSize = 4; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*InternalSize=%lu *InternalBaseAddress=0x%08x " ++ "*InternalAlignment=0x%08x *ExternalSize=%lu " ++ "*ExternalBaseAddress=0x%08x *ExtenalAlignment=0x%08x " ++ "*HorizontalTileSize=%u *VerticalTileSize=%u", ++ gcmOPT_VALUE(InternalSize), ++ gcmOPT_VALUE(InternalBaseAddress), ++ gcmOPT_VALUE(InternalAlignment), ++ gcmOPT_VALUE(ExternalSize), ++ gcmOPT_VALUE(ExternalBaseAddress), ++ gcmOPT_VALUE(ExternalAlignment), ++ gcmOPT_VALUE(HorizontalTileSize), ++ gcmOPT_VALUE(VerticalTileSize)); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_QueryChipIdentity ++** ++** Query the identity of the hardware. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** OUTPUT: ++** ++** gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity ++** Pointer to the identity structure. ++** ++*/ ++gceSTATUS ++gckHARDWARE_QueryChipIdentity( ++ IN gckHARDWARE Hardware, ++ OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity ++ ) ++{ ++ gctUINT32 features; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Identity != gcvNULL); ++ ++ /* Return chip model and revision. */ ++ Identity->chipModel = Hardware->identity.chipModel; ++ Identity->chipRevision = Hardware->identity.chipRevision; ++ ++ /* Return feature set. */ ++ features = Hardware->identity.chipFeatures; ++ ++ if ((((((gctUINT32) (features)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) ++ { ++ /* Override fast clear by command line. */ ++ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (Hardware->allowFastClear) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ } ++ ++ if ((((((gctUINT32) (features)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) )) ++ { ++ /* Override compression by command line. */ ++ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (Hardware->allowCompression) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); ++ } ++ ++ /* Mark 2D pipe as available for GC500.0 through GC500.2 and GC300, ++ ** since they did not have this bit. */ ++ if (((Hardware->identity.chipModel == gcv500) && (Hardware->identity.chipRevision <= 2)) ++ || (Hardware->identity.chipModel == gcv300) ++ ) ++ { ++ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))); ++ } ++ ++ Identity->chipFeatures = features; ++ ++ /* Return minor features. */ ++ Identity->chipMinorFeatures = Hardware->identity.chipMinorFeatures; ++ Identity->chipMinorFeatures1 = Hardware->identity.chipMinorFeatures1; ++ Identity->chipMinorFeatures2 = Hardware->identity.chipMinorFeatures2; ++ Identity->chipMinorFeatures3 = Hardware->identity.chipMinorFeatures3; ++ Identity->chipMinorFeatures4 = Hardware->identity.chipMinorFeatures4; ++ Identity->chipMinorFeatures5 = Hardware->identity.chipMinorFeatures5; ++ ++ /* Return chip specs. */ ++ Identity->streamCount = Hardware->identity.streamCount; ++ Identity->registerMax = Hardware->identity.registerMax; ++ Identity->threadCount = Hardware->identity.threadCount; ++ Identity->shaderCoreCount = Hardware->identity.shaderCoreCount; ++ Identity->vertexCacheSize = Hardware->identity.vertexCacheSize; ++ Identity->vertexOutputBufferSize = Hardware->identity.vertexOutputBufferSize; ++ Identity->pixelPipes = Hardware->identity.pixelPipes; ++ Identity->instructionCount = Hardware->identity.instructionCount; ++ Identity->numConstants = Hardware->identity.numConstants; ++ Identity->bufferSize = Hardware->identity.bufferSize; ++ Identity->varyingsCount = Hardware->identity.varyingsCount; ++ Identity->superTileMode = Hardware->identity.superTileMode; ++ Identity->chip2DControl = Hardware->identity.chip2DControl; ++ ++ Identity->productID = Hardware->identity.productID; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_SplitMemory ++** ++** Split a hardware specific memory address into a pool and offset. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** gctUINT32 Address ++** Address in hardware specific format. ++** ++** OUTPUT: ++** ++** gcePOOL * Pool ++** Pointer to a variable that will hold the pool type for the address. ++** ++** gctUINT32 * Offset ++** Pointer to a variable that will hold the offset for the address. ++*/ ++gceSTATUS ++gckHARDWARE_SplitMemory( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Address, ++ OUT gcePOOL * Pool, ++ OUT gctUINT32 * Offset ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x Addres=0x%08x", Hardware, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Pool != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Offset != gcvNULL); ++ ++ if (Hardware->mmuVersion == 0) ++ { ++ /* Dispatch on memory type. */ ++ switch ((((((gctUINT32) (Address)) >> (0 ? 31:31)) & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1)))))) )) ++ { ++ case 0x0: ++ /* System memory. */ ++ *Pool = gcvPOOL_SYSTEM; ++ break; ++ ++ case 0x1: ++ /* Virtual memory. */ ++ *Pool = gcvPOOL_VIRTUAL; ++ break; ++ ++ default: ++ /* Invalid memory type. */ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); ++ return gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++ /* Return offset of address. */ ++ *Offset = (((((gctUINT32) (Address)) >> (0 ? 30:0)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1)))))) ); ++ } ++ else ++ { ++ *Pool = gcvPOOL_SYSTEM; ++ *Offset = Address; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Pool=%d *Offset=0x%08x", *Pool, *Offset); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Execute ++** ++** Kickstart the hardware's command processor with an initialized command ++** buffer. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** gctUINT32 Address ++** Hardware address of command buffer. ++** ++** gctSIZE_T Bytes ++** Number of bytes for the prefetch unit (until after the first LINK). ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_Execute( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Address, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 control; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Bytes=%lu", ++ Hardware, Address, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Enable all events. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00014, ~0U)); ++ ++ /* Write address register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00654, Address)); ++ ++ /* Build control register. */ ++ control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes + 7) >> 3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ /* Set big endian */ ++ if (Hardware->bigEndian) ++ { ++ control |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))); ++ } ++ ++ /* Write control register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control)); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Started command buffer @ 0x%08x", ++ Address); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_WaitLink ++** ++** Append a WAIT/LINK command sequence at the specified location in the command ++** queue. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command queue to append ++** WAIT/LINK command sequence at or gcvNULL just to query the size of the ++** WAIT/LINK command sequence. ++** ++** gctUINT32 Offset ++** Offset into command buffer required for alignment. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the WAIT/LINK command ++** sequence. If 'Logical' is gcvNULL, this argument will be ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** by the WAIT/LINK command sequence. If 'Bytes' is gcvNULL, nothing will ++** be returned. ++** ++** gctUINT32 * WaitOffset ++** Pointer to a variable that will receive the offset of the WAIT command ++** from the specified logcial pointer. ++** If 'WaitOffset' is gcvNULL nothing will be returned. ++** ++** gctSIZE_T * WaitSize ++** Pointer to a variable that will receive the number of bytes used by ++** the WAIT command. If 'LinkSize' is gcvNULL nothing will be returned. ++*/ ++gceSTATUS ++gckHARDWARE_WaitLink( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Offset, ++ IN OUT gctUINT32 * Bytes, ++ OUT gctUINT32 * WaitOffset, ++ OUT gctUINT32 * WaitSize ++ ) ++{ ++ static const gctUINT waitCount = 200; ++ ++ gceSTATUS status; ++ gctUINT32 address; ++ gctUINT32_PTR logical; ++ gctUINT32 bytes; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x *Bytes=%lu", ++ Hardware, Logical, Offset, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT((Logical != gcvNULL) || (Bytes != gcvNULL)); ++ ++ /* Compute number of bytes required. */ ++ bytes = gcmALIGN(Offset + 16, 8) - Offset; ++ /* Cast the input pointer. */ ++ logical = (gctUINT32_PTR) Logical; ++ ++ if (logical != gcvNULL) ++ { ++ /* Not enough space? */ ++ if (*Bytes < bytes) ++ { ++ /* Command queue too small. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ ++ /* Convert logical into hardware specific address. */ ++ gcmkONERROR(gckHARDWARE_ConvertLogical(Hardware, logical, gcvFALSE, &address)); ++ ++ /* Store the WAIT/LINK address. */ ++ Hardware->lastWaitLink = address; ++ ++ /* Append WAIT(count). */ ++ logical[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (waitCount) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ /* Append LINK(2, address). */ ++ logical[2] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ logical[3] = address; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%08x: WAIT %u", address, waitCount ++ ); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%08x: LINK 0x%08x, #%lu", ++ address + 8, address, bytes ++ ); ++ if (WaitOffset != gcvNULL) ++ { ++ /* Return the offset pointer to WAIT command. */ ++ *WaitOffset = 0; ++ } ++ ++ if (WaitSize != gcvNULL) ++ { ++ /* Return number of bytes used by the WAIT command. */ ++ *WaitSize = 8; ++ } ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the WAIT/LINK command ++ ** sequence. */ ++ *Bytes = bytes; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu *WaitOffset=0x%x *WaitSize=%lu", ++ gcmOPT_VALUE(Bytes), gcmOPT_VALUE(WaitOffset), ++ gcmOPT_VALUE(WaitSize)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_End ++** ++** Append an END command at the specified location in the command queue. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command queue to append ++** END command at or gcvNULL just to query the size of the END command. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the END command. If ++** 'Logical' is gcvNULL, this argument will be ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the END command. If 'Bytes' is gcvNULL, nothing will be returned. ++*/ ++gceSTATUS ++gckHARDWARE_End( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gctUINT32_PTR logical = (gctUINT32_PTR) Logical; ++ gctUINT32 address; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", ++ Hardware, Logical, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); ++ ++ if (Logical != gcvNULL) ++ { ++ if (*Bytes < 8) ++ { ++ /* Command queue too small. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ ++ /* Append END. */ ++ logical[0] = ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical); ++ ++ /* Make sure the CPU writes out the data to memory. */ ++ gcmkONERROR( ++ gckOS_MemoryBarrier(Hardware->os, Logical)); ++ ++ gcmkONERROR(gckHARDWARE_ConvertLogical(Hardware, logical, gcvFALSE, &address)); ++ ++ Hardware->lastEnd = address; ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the END command. */ ++ *Bytes = 8; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Nop ++** ++** Append a NOP command at the specified location in the command queue. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command queue to append ++** NOP command at or gcvNULL just to query the size of the NOP command. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the NOP command. If ++** 'Logical' is gcvNULL, this argument will be ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned. ++*/ ++gceSTATUS ++gckHARDWARE_Nop( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN OUT gctSIZE_T * Bytes ++ ) ++{ ++ gctUINT32_PTR logical = (gctUINT32_PTR) Logical; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", ++ Hardware, Logical, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); ++ ++ if (Logical != gcvNULL) ++ { ++ if (*Bytes < 8) ++ { ++ /* Command queue too small. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ ++ /* Append NOP. */ ++ logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the NOP command. */ ++ *Bytes = 8; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Event ++** ++** Append an EVENT command at the specified location in the command queue. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command queue to append ++** the EVENT command at or gcvNULL just to query the size of the EVENT ++** command. ++** ++** gctUINT8 Event ++** Event ID to program. ++** ++** gceKERNEL_WHERE FromWhere ++** Location of the pipe to send the event. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the EVENT command. If ++** 'Logical' is gcvNULL, this argument will be ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the EVENT command. If 'Bytes' is gcvNULL, nothing will be ++** returned. ++*/ ++gceSTATUS ++gckHARDWARE_Event( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT8 Event, ++ IN gceKERNEL_WHERE FromWhere, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gctUINT size; ++ gctUINT32 destination = 0; ++ gctUINT32_PTR logical = (gctUINT32_PTR) Logical; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu", ++ Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); ++ gcmkVERIFY_ARGUMENT(Event < 32); ++ ++ /* Determine the size of the command. */ ++ ++ size = (Hardware->extraEventStates && (FromWhere == gcvKERNEL_PIXEL)) ++ ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */ ++ : 8; ++ ++ if (Logical != gcvNULL) ++ { ++ if (*Bytes < size) ++ { ++ /* Command queue too small. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ ++ switch (FromWhere) ++ { ++ case gcvKERNEL_COMMAND: ++ /* From command processor. */ ++ destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); ++ break; ++ ++ case gcvKERNEL_PIXEL: ++ /* From pixel engine. */ ++ destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++ break; ++ ++ default: ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Append EVENT(Event, destiantion). */ ++ logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ logical[1] = ((((gctUINT32) (destination)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (Event) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))); ++ ++ /* Make sure the event ID gets written out before GPU can access it. */ ++ gcmkONERROR( ++ gckOS_MemoryBarrier(Hardware->os, logical + 1)); ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ { ++ gctUINT32 phys; ++ gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%08x: EVENT %d", phys, Event); ++ } ++#endif ++ ++ /* Append the extra states. These are needed for the chips that do not ++ ** support back-to-back events due to the async interface. The extra ++ ** states add the necessary delay to ensure that event IDs do not ++ ** collide. */ ++ if (size > 8) ++ { ++ logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ logical[3] = 0; ++ logical[4] = 0; ++ logical[5] = 0; ++ logical[6] = 0; ++ logical[7] = 0; ++ } ++ ++#if gcdINTERRUPT_STATISTIC ++ if (Event < gcmCOUNTOF(Hardware->kernel->eventObj->queues)) ++ { ++ gckOS_AtomSetMask(Hardware->pendingEvent, 1 << Event); ++ } ++#endif ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the EVENT command. */ ++ *Bytes = size; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_PipeSelect ++** ++** Append a PIPESELECT command at the specified location in the command queue. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command queue to append ++** the PIPESELECT command at or gcvNULL just to query the size of the ++** PIPESELECT command. ++** ++** gcePIPE_SELECT Pipe ++** Pipe value to select. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the PIPESELECT command. ++** If 'Logical' is gcvNULL, this argument will be ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the PIPESELECT command. If 'Bytes' is gcvNULL, nothing will be ++** returned. ++*/ ++gceSTATUS ++gckHARDWARE_PipeSelect( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gcePIPE_SELECT Pipe, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gctUINT32_PTR logical = (gctUINT32_PTR) Logical; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Pipe=%d *Bytes=%lu", ++ Hardware, Logical, Pipe, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); ++ ++ /* Append a PipeSelect. */ ++ if (Logical != gcvNULL) ++ { ++ gctUINT32 flush, stall; ++ ++ if (*Bytes < 32) ++ { ++ /* Command queue too small. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ ++ flush = (Pipe == gcvPIPE_2D) ++ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))); ++ ++ stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* LoadState(AQFlush, 1), flush. */ ++ logical[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ logical[1] ++ = flush; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%x: FLUSH 0x%x", logical, flush); ++ ++ /* LoadState(AQSempahore, 1), stall. */ ++ logical[2] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ logical[3] ++ = stall; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%x: SEMAPHORE 0x%x", logical + 2, stall); ++ ++ /* Stall, stall. */ ++ logical[4] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ logical[5] = stall; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%x: STALL 0x%x", logical + 4, stall); ++ ++ /* LoadState(AQPipeSelect, 1), pipe. */ ++ logical[6] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ logical[7] = (Pipe == gcvPIPE_2D) ++ ? 0x1 ++ : 0x0; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%x: PIPE %d", logical + 6, Pipe); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the PIPESELECT command. */ ++ *Bytes = 32; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Link ++** ++** Append a LINK command at the specified location in the command queue. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command queue to append ++** the LINK command at or gcvNULL just to query the size of the LINK ++** command. ++** ++** gctUINT32 FetchAddress ++** Hardware address of destination of LINK. ++** ++** gctSIZE_T FetchSize ++** Number of bytes in destination of LINK. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the LINK command. If ++** 'Logical' is gcvNULL, this argument will be ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the LINK command. If 'Bytes' is gcvNULL, nothing will be returned. ++*/ ++gceSTATUS ++gckHARDWARE_Link( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT32 FetchSize, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gceSTATUS status; ++ gctSIZE_T bytes; ++ gctUINT32 link; ++ gctUINT32_PTR logical = (gctUINT32_PTR) Logical; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x FetchAddress=0x%x FetchSize=%lu " ++ "*Bytes=%lu", ++ Hardware, Logical, FetchAddress, FetchSize, ++ gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); ++ ++ if (Logical != gcvNULL) ++ { ++ if (*Bytes < 8) ++ { ++ /* Command queue too small. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ ++ gcmkONERROR( ++ gckOS_WriteMemory(Hardware->os, logical + 1, FetchAddress)); ++ ++ /* Make sure the address got written before the LINK command. */ ++ gcmkONERROR( ++ gckOS_MemoryBarrier(Hardware->os, logical + 1)); ++ ++ /* Compute number of 64-byte aligned bytes to fetch. */ ++ bytes = gcmALIGN(FetchAddress + FetchSize, 8) - FetchAddress; ++ ++ /* Append LINK(bytes / 8), FetchAddress. */ ++ link = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ gcmkONERROR( ++ gckOS_WriteMemory(Hardware->os, logical, link)); ++ ++ /* Memory barrier. */ ++ gcmkONERROR( ++ gckOS_MemoryBarrier(Hardware->os, logical)); ++ ++#if gcdLINK_QUEUE_SIZE && !gcdPROCESS_ADDRESS_SPACE ++ if ((Hardware->kernel->virtualCommandBuffer) ++ && (Hardware->kernel->stuckDump > 2) ++ ) ++ { ++ gctBOOL in; ++ ++ gcmkVERIFY_OK(gckCOMMAND_AddressInKernelCommandBuffer( ++ Hardware->kernel->command, FetchAddress, &in)); ++ ++ if (in == gcvFALSE) ++ { ++ /* Record user command buffer and context buffer link ++ ** information for stuck dump. ++ **/ ++ gckLINKQUEUE_Enqueue( ++ &Hardware->linkQueue, FetchAddress, FetchAddress + (gctUINT)bytes); ++ } ++ } ++#endif ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the LINK command. */ ++ *Bytes = 8; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_UpdateQueueTail ++** ++** Update the tail of the command queue. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Logical address of the start of the command queue. ++** ++** gctUINT32 Offset ++** Offset into the command queue of the tail (last command). ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_UpdateQueueTail( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Offset ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x", ++ Hardware, Logical, Offset); ++ ++ /* Verify the hardware. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Force a barrier. */ ++ gcmkONERROR( ++ gckOS_MemoryBarrier(Hardware->os, Logical)); ++ ++ /* Notify gckKERNEL object of change. */ ++ gcmkONERROR( ++ gckKERNEL_Notify(Hardware->kernel, ++ gcvNOTIFY_COMMAND_QUEUE, ++ gcvFALSE)); ++ ++ if (status == gcvSTATUS_CHIP_NOT_READY) ++ { ++ gcmkONERROR(gcvSTATUS_DEVICE); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_ConvertLogical ++** ++** Convert a logical system address into a hardware specific address. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Logical address to convert. ++** ++** gctBOOL InUserSpace ++** gcvTRUE if the memory in user space. ++** ++** gctUINT32* Address ++** Return hardware specific address. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_ConvertLogical( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctBOOL InUserSpace, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gctUINT32 address; ++ gceSTATUS status; ++ gctUINT32 baseAddress; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x InUserSpace=%d", ++ Hardware, Logical, InUserSpace); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ /* Convert logical address into a physical address. */ ++ if (InUserSpace) ++ { ++ gcmkONERROR(gckOS_UserLogicalToPhysical(Hardware->os, Logical, &address)); ++ } ++ else ++ { ++ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, Logical, &address)); ++ } ++ ++ /* For old MMU, get GPU address according to baseAddress. */ ++ if (Hardware->mmuVersion == 0) ++ { ++ gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, &baseAddress)); ++ ++ /* Subtract base address to get a GPU address. */ ++ gcmkASSERT(address >= baseAddress); ++ address -= baseAddress; ++ } ++ ++ /* Return hardware specific address. */ ++ *Address = (Hardware->mmuVersion == 0) ++ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) ++ : address; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Address=0x%08x", *Address); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Interrupt ++** ++** Process an interrupt. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctBOOL InterruptValid ++** If gcvTRUE, this function will read the interrupt acknowledge ++** register, stores the data, and return whether or not the interrupt ++** is ours or not. If gcvFALSE, this functions will read the interrupt ++** acknowledge register and combine it with any stored value to handle ++** the event notifications. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_Interrupt( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL InterruptValid ++ ) ++{ ++ gckEVENT eventObj; ++ gctUINT32 data = 0; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x InterruptValid=%d", Hardware, InterruptValid); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Extract gckEVENT object. */ ++ eventObj = Hardware->kernel->eventObj; ++ gcmkVERIFY_OBJECT(eventObj, gcvOBJ_EVENT); ++ ++ if (InterruptValid) ++ { ++ /* Read AQIntrAcknowledge register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00010, ++ &data)); ++ ++ if (data == 0) ++ { ++ /* Not our interrupt. */ ++ status = gcvSTATUS_NOT_OUR_INTERRUPT; ++ } ++ else ++ { ++ ++#if gcdINTERRUPT_STATISTIC ++ gckOS_AtomClearMask(Hardware->pendingEvent, data); ++#endif ++ ++ /* Inform gckEVENT of the interrupt. */ ++ status = gckEVENT_Interrupt(eventObj, ++ data); ++ } ++ } ++ else ++ { ++ /* Handle events. */ ++ status = gckEVENT_Notify(eventObj, 0); ++ } ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_QueryCommandBuffer ++** ++** Query the command buffer alignment and number of reserved bytes. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Alignment ++** Pointer to a variable receiving the alignment for each command. ++** ++** gctSIZE_T * ReservedHead ++** Pointer to a variable receiving the number of reserved bytes at the ++** head of each command buffer. ++** ++** gctSIZE_T * ReservedTail ++** Pointer to a variable receiving the number of bytes reserved at the ++** tail of each command buffer. ++*/ ++gceSTATUS ++gckHARDWARE_QueryCommandBuffer( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32 * Alignment, ++ OUT gctUINT32 * ReservedHead, ++ OUT gctUINT32 * ReservedTail ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (Alignment != gcvNULL) ++ { ++ /* Align every 8 bytes. */ ++ *Alignment = 8; ++ } ++ ++ if (ReservedHead != gcvNULL) ++ { ++ /* Reserve space for SelectPipe(). */ ++ *ReservedHead = 32; ++ } ++ ++ if (ReservedTail != gcvNULL) ++ { ++ /* Reserve space for Link(). */ ++ *ReservedTail = 8; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Alignment=%lu *ReservedHead=%lu *ReservedTail=%lu", ++ gcmOPT_VALUE(Alignment), gcmOPT_VALUE(ReservedHead), ++ gcmOPT_VALUE(ReservedTail)); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_QuerySystemMemory ++** ++** Query the command buffer alignment and number of reserved bytes. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** OUTPUT: ++** ++** gctSIZE_T * SystemSize ++** Pointer to a variable that receives the maximum size of the system ++** memory. ++** ++** gctUINT32 * SystemBaseAddress ++** Poinetr to a variable that receives the base address for system ++** memory. ++*/ ++gceSTATUS ++gckHARDWARE_QuerySystemMemory( ++ IN gckHARDWARE Hardware, ++ OUT gctSIZE_T * SystemSize, ++ OUT gctUINT32 * SystemBaseAddress ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (SystemSize != gcvNULL) ++ { ++ /* Maximum system memory can be 2GB. */ ++ *SystemSize = 1U << 31; ++ } ++ ++ if (SystemBaseAddress != gcvNULL) ++ { ++ /* Set system memory base address. */ ++ *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*SystemSize=%lu *SystemBaseAddress=%lu", ++ gcmOPT_VALUE(SystemSize), gcmOPT_VALUE(SystemBaseAddress)); ++ return gcvSTATUS_OK; ++} ++ ++#if gcdENABLE_3D ++/******************************************************************************* ++** ++** gckHARDWARE_QueryShaderCaps ++** ++** Query the shader capabilities. ++** ++** INPUT: ++** ++** Nothing. ++** ++** OUTPUT: ++** ++** gctUINT * VertexUniforms ++** Pointer to a variable receiving the number of uniforms in the vertex ++** shader. ++** ++** gctUINT * FragmentUniforms ++** Pointer to a variable receiving the number of uniforms in the ++** fragment shader. ++** ++** gctBOOL * UnifiedUnforms ++** Pointer to a variable receiving whether the uniformas are unified. ++*/ ++gceSTATUS ++gckHARDWARE_QueryShaderCaps( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT * VertexUniforms, ++ OUT gctUINT * FragmentUniforms, ++ OUT gctBOOL * UnifiedUnforms ++ ) ++{ ++ gctBOOL unifiedConst; ++ gctUINT32 vsConstMax; ++ gctUINT32 psConstMax; ++ gctUINT32 vsConstBase; ++ gctUINT32 psConstBase; ++ gctUINT32 ConstMax; ++ ++ gcmkHEADER_ARG("Hardware=0x%x VertexUniforms=0x%x " ++ "FragmentUniforms=0x%x UnifiedUnforms=0x%x", ++ Hardware, VertexUniforms, ++ FragmentUniforms, UnifiedUnforms); ++ ++ {if (Hardware->identity.numConstants > 256){ unifiedConst = gcvTRUE; vsConstBase = 0xC000; psConstBase = 0xC000; ConstMax = Hardware->identity.numConstants; vsConstMax = 256; psConstMax = ConstMax - vsConstMax;}else if (Hardware->identity.numConstants == 256){ if (Hardware->identity.chipModel == gcv2000 && Hardware->identity.chipRevision == 0x5118) { unifiedConst = gcvFALSE; vsConstBase = 0x1400; psConstBase = 0x1C00; vsConstMax = 256; psConstMax = 64; ConstMax = 320; } else { unifiedConst = gcvFALSE; vsConstBase = 0x1400; psConstBase = 0x1C00; vsConstMax = 256; psConstMax = 256; ConstMax = 512; }}else{ unifiedConst = gcvFALSE; vsConstBase = 0x1400; psConstBase = 0x1C00; vsConstMax = 168; psConstMax = 64; ConstMax = 232;}}; ++ ++ if (VertexUniforms != gcvNULL) ++ { ++ /* Return the vs shader const count. */ ++ *VertexUniforms = vsConstMax; ++ } ++ ++ if (FragmentUniforms != gcvNULL) ++ { ++ /* Return the ps shader const count. */ ++ *FragmentUniforms = psConstMax; ++ } ++ ++ if (UnifiedUnforms != gcvNULL) ++ { ++ /* Return whether the uniformas are unified. */ ++ *UnifiedUnforms = unifiedConst; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckHARDWARE_SetMMU ++** ++** Set the page table base address. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Logical address of the page table. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_SetMMU( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 address = 0; ++ gctUINT32 idle; ++ gctUINT32 timer = 0, delay = 1; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (Hardware->mmuVersion == 0) ++ { ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ /* Convert the logical address into physical address. */ ++ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, Logical, &address)); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Setting page table to 0x%08X", ++ address); ++ ++ /* Write the AQMemoryFePageTable register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00400, ++ address)); ++ ++ /* Write the AQMemoryRaPageTable register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00410, ++ address)); ++ ++ /* Write the AQMemoryTxPageTable register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00404, ++ address)); ++ ++ ++ /* Write the AQMemoryPePageTable register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00408, ++ address)); ++ ++ /* Write the AQMemoryPezPageTable register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0040C, ++ address)); ++ } ++ else if (Hardware->enableMMU == gcvTRUE) ++ { ++ /* Execute prepared command sequence. */ ++ gcmkONERROR(gckHARDWARE_Execute( ++ Hardware, ++ Hardware->functions[gcvHARDWARE_FUNCTION_MMU].address, ++ Hardware->functions[gcvHARDWARE_FUNCTION_MMU].bytes ++ )); ++ ++ /* Wait until MMU configure finishes. */ ++ do ++ { ++ gckOS_Delay(Hardware->os, delay); ++ ++ gcmkONERROR(gckOS_ReadRegisterEx( ++ Hardware->os, ++ Hardware->core, ++ 0x00004, ++ &idle)); ++ ++ timer += delay; ++ delay *= 2; ++ ++#if gcdGPU_TIMEOUT ++ if (timer >= Hardware->kernel->timeOut) ++ { ++ /* Even if hardware is not reset correctly, let software ++ ** continue to avoid software stuck. Software will timeout again ++ ** and try to recover GPU in next timeout. ++ */ ++ gcmkONERROR(gcvSTATUS_DEVICE); ++ } ++#endif ++ } ++ while (!(((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )); ++ ++ /* Enable MMU. */ ++ gcmkONERROR(gckOS_WriteRegisterEx( ++ Hardware->os, ++ Hardware->core, ++ 0x0018C, ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (gcvTRUE) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ )); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_FlushMMU ++** ++** Flush the page table. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_FlushMMU( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gckCOMMAND command; ++ gctUINT32_PTR buffer; ++ gctUINT32 bufferSize; ++ gctPOINTER pointer = gcvNULL; ++ gctUINT32 flushSize; ++ gctUINT32 count; ++ gctUINT32 physical; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Verify the gckCOMMAND object pointer. */ ++ command = Hardware->kernel->command; ++ ++ /* Flush the memory controller. */ ++ if (Hardware->mmuVersion == 0) ++ { ++ gcmkONERROR(gckCOMMAND_Reserve( ++ command, 8, &pointer, &bufferSize ++ )); ++ ++ buffer = (gctUINT32_PTR) pointer; ++ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ buffer[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); ++ ++ gcmkONERROR(gckCOMMAND_Execute(command, 8)); ++ } ++ else ++ { ++ flushSize = 16 * 4; ++ ++ gcmkONERROR(gckCOMMAND_Reserve( ++ command, flushSize, &pointer, &bufferSize ++ )); ++ ++ buffer = (gctUINT32_PTR) pointer; ++ ++ count = ((gctUINT)bufferSize - flushSize + 7) >> 3; ++ ++ gcmkONERROR(gckOS_GetPhysicalAddress(command->os, buffer, &physical)); ++ ++ /* Flush cache. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++ ++ /* Arm the PE-FE Semaphore. */ ++ buffer[2] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[3] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* STALL FE until PE is done flushing. */ ++ buffer[4] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ buffer[5] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* LINK to next slot to flush FE FIFO. */ ++ buffer[6] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[7] ++ = physical + 8 * gcmSIZEOF(gctUINT32); ++ ++ /* Flush MMU cache. */ ++ buffer[8] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ buffer[9] ++ = (((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) & ((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)))); ++ ++ /* Arm the PE-FE Semaphore. */ ++ buffer[10] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[11] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* STALL FE until PE is done flushing. */ ++ buffer[12] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ buffer[13] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* LINK to next slot to flush FE FIFO. */ ++ buffer[14] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (count) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[15] ++ = physical + flushSize; ++ ++ gcmkONERROR(gckCOMMAND_Execute(command, flushSize)); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_SetMMUStates( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER MtlbAddress, ++ IN gceMMU_MODE Mode, ++ IN gctPOINTER SafeAddress, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 config, address; ++ gctUINT32_PTR buffer; ++ gctBOOL ace; ++ gctUINT32 reserveBytes = 16 + 4 * 4; ++ ++ gctBOOL config2D; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Hardware->mmuVersion != 0); ++ ++ ace = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_ACE); ++ ++ if (ace) ++ { ++ reserveBytes += 8; ++ } ++ ++ config2D = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_3D) ++ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_2D); ++ ++ if (config2D) ++ { ++ reserveBytes += ++ /* Pipe Select. */ ++ 4 * 4 ++ /* Configure MMU States. */ ++ + 4 * 4 ++ /* Semaphore stall */ ++ + 4 * 8; ++ } ++ ++ /* Convert logical address into physical address. */ ++ gcmkONERROR( ++ gckOS_GetPhysicalAddress(Hardware->os, MtlbAddress, &config)); ++ ++ gcmkONERROR( ++ gckOS_GetPhysicalAddress(Hardware->os, SafeAddress, &address)); ++ ++ if (address & 0x3F) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_ALIGNED); ++ } ++ ++ switch (Mode) ++ { ++ case gcvMMU_MODE_1K: ++ if (config & 0x3FF) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_ALIGNED); ++ } ++ ++ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ break; ++ ++ case gcvMMU_MODE_4K: ++ if (config & 0xFFF) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_ALIGNED); ++ } ++ ++ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ break; ++ ++ default: ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ if (Logical != gcvNULL) ++ { ++ buffer = Logical; ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ = config; ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ = address; ++ ++ if (ace) ++ { ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0068) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ = 0; ++ } ++ ++ do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);; ++ ++ if (config2D) ++ { ++ /* LoadState(AQPipeSelect, 1), pipe. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ = 0x1; ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ = config; ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ = address; ++ ++ do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);; ++ ++ /* LoadState(AQPipeSelect, 1), pipe. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ = 0x0; ++ ++ do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);; ++ } ++ ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ *Bytes = reserveBytes; ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER_NO(); ++ return status; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if gcdPROCESS_ADDRESS_SPACE ++/******************************************************************************* ++** ++** gckHARDWARE_ConfigMMU ++** ++** Append a MMU Configuration command sequence at the specified location in the command ++** queue. That command sequence consists of mmu configuration, LINK and WAIT/LINK. ++** LINK is fetched and paresed with new mmu configuration. ++** ++** If MMU Configuration is not changed between commit, change last WAIT/LINK to ++** link to ENTRY. ++** ++** -+-----------+-----------+----------------------------------------- ++** | WAIT/LINK | WAIT/LINK | ++** -+-----------+-----------+----------------------------------------- ++** | /|\ ++** \|/ | ++** +--------------------+ ++** | ENTRY | ... | LINK | ++** +--------------------+ ++** ++** If MMU Configuration is changed between commit, change last WAIT/LINK to ++** link to MMU CONFIGURATION command sequence, and there are an EVNET and ++** an END at the end of this command sequence, when interrupt handler ++** receives this event, it will start FE at ENTRY to continue the command ++** buffer execution. ++** ++** -+-----------+-------------------+---------+---------+-----------+-- ++** | WAIT/LINK | MMU CONFIGURATION | EVENT | END | WAIT/LINK | ++** -+-----------+-------------------+---------+---------+-----------+-- ++** | /|\ /|\ ++** +-------------+ | ++** +--------------------+ ++** | ENTRY | ... | LINK | ++** +--------------------+ ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command queue to append ++** command sequence at or gcvNULL just to query the size of the ++** command sequence. ++** ++** gctPOINTER MtlbLogical ++** Pointer to the current Master TLB. ++** ++** gctUINT32 Offset ++** Offset into command buffer required for alignment. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the command ++** sequence. If 'Logical' is gcvNULL, this argument will be ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** by the command sequence. If 'Bytes' is gcvNULL, nothing will ++** be returned. ++** ++** gctUINT32 * WaitLinkOffset ++** Pointer to a variable that will receive the offset of the WAIT/LINK command ++** from the specified logcial pointer. ++** If 'WaitLinkOffset' is gcvNULL nothing will be returned. ++** ++** gctSIZE_T * WaitLinkBytes ++** Pointer to a variable that will receive the number of bytes used by ++** the WAIT command. ++** If 'WaitLinkBytes' is gcvNULL nothing will be returned. ++*/ ++gceSTATUS ++gckHARDWARE_ConfigMMU( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctPOINTER MtlbLogical, ++ IN gctUINT32 Offset, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctSIZE_T * WaitLinkOffset, ++ OUT gctSIZE_T * WaitLinkBytes ++ ) ++{ ++ gceSTATUS status; ++ gctSIZE_T bytes, bytesAligned; ++ gctUINT32 config; ++ gctUINT32_PTR buffer = (gctUINT32_PTR) Logical; ++ gctUINT32 physical; ++ gctUINT32 event; ++ ++ gcmkHEADER_ARG("Hardware=0x%08X Logical=0x%08x MtlbLogical=0x%08X", ++ Hardware, Logical, MtlbLogical); ++ ++ bytes ++ /* Flush cache states. */ ++ = 18 * 4 ++ /* MMU configuration states. */ ++ + 6 * 4 ++ /* EVENT. */ ++ + 2 * 4 ++ /* END. */ ++ + 2 * 4 ++ /* WAIT/LINK. */ ++ + 4 * 4; ++ ++ /* Compute number of bytes required. */ ++ bytesAligned = gcmALIGN(Offset + bytes, 8) - Offset; ++ ++ if (buffer != gcvNULL) ++ { ++ if (MtlbLogical == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Get physical address of this command buffer segment. */ ++ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, buffer, &physical)); ++ ++ /* Get physical address of Master TLB. */ ++ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, MtlbLogical, &config)); ++ ++ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); ++ ++ /* Flush cache. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++ ++ /* Flush tile status cache. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ /* Arm the PE-FE Semaphore. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* STALL FE until PE is done flushing. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* LINK to next slot to flush FE FIFO. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = physical + 10 * gcmSIZEOF(gctUINT32); ++ ++ /* Configure MMU. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ ++ = (((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) & ((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)))); ++ ++ /* Arm the PE-FE Semaphore. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* STALL FE until PE is done flushing. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* LINK to next slot to flush FE FIFO. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = physical + 18 * 4; ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *buffer++ ++ = config; ++ ++ /* Arm the PE-FE Semaphore. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* STALL FE until PE is done flushing. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* Event 29. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ event = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++ event = ((((gctUINT32) (event)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (29) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))); ++ ++ *buffer++ ++ = event; ++ ++ /* Append END. */ ++ *buffer++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ *Bytes = bytesAligned; ++ } ++ ++ if (WaitLinkOffset != gcvNULL) ++ { ++ *WaitLinkOffset = bytes - 4 * 4; ++ } ++ ++ if (WaitLinkBytes != gcvNULL) ++ { ++ *WaitLinkBytes = 4 * 4; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckHARDWARE_BuildVirtualAddress ++** ++** Build a virtual address. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gctUINT32 Index ++** Index into page table. ++** ++** gctUINT32 Offset ++** Offset into page. ++** ++** OUTPUT: ++** ++** gctUINT32 * Address ++** Pointer to a variable receiving te hardware address. ++*/ ++gceSTATUS ++gckHARDWARE_BuildVirtualAddress( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Index, ++ IN gctUINT32 Offset, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x Index=%u Offset=%u", Hardware, Index, Offset); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ /* Build virtual address. */ ++ *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (Offset | (Index << 12)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Address=0x%08x", *Address); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckHARDWARE_GetIdle( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Wait, ++ OUT gctUINT32 * Data ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 idle = 0; ++ gctINT retry, poll, pollCount; ++ gctUINT32 address; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Wait=%d", Hardware, Wait); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Data != gcvNULL); ++ ++ ++ /* If we have to wait, try 100 polls per millisecond. */ ++ pollCount = Wait ? 100 : 1; ++ ++ /* At most, try for 1 second. */ ++ for (retry = 0; retry < 1000; ++retry) ++ { ++ /* If we have to wait, try 100 polls per millisecond. */ ++ for (poll = pollCount; poll > 0; --poll) ++ { ++ /* Read register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle)); ++ ++ /* Read the current FE address. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00664, ++ &address)); ++ ++ ++ /* See if we have to wait for FE idle. */ ++ if (_IsGPUIdle(idle) ++ && (address == Hardware->lastEnd + 8) ++ ) ++ { ++ /* FE is idle. */ ++ break; ++ } ++ } ++ ++ /* Check if we need to wait for FE and FE is busy. */ ++ if (Wait && !_IsGPUIdle(idle)) ++ { ++ /* Wait a little. */ ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HARDWARE, ++ "%s: Waiting for idle: 0x%08X", ++ __FUNCTION__, idle); ++ ++ gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1)); ++ } ++ else ++ { ++ break; ++ } ++ } ++ ++ /* Return idle to caller. */ ++ *Data = idle; ++ ++#if defined(EMULATOR) ++ /* Wait a little while until CModel FE gets END. ++ * END is supposed to be appended by caller. ++ */ ++ gckOS_Delay(gcvNULL, 100); ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Data=0x%08x", *Data); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/* Flush the caches. */ ++gceSTATUS ++gckHARDWARE_Flush( ++ IN gckHARDWARE Hardware, ++ IN gceKERNEL_FLUSH Flush, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gctUINT32 pipe; ++ gctUINT32 flush = 0; ++ gctBOOL flushTileStatus; ++ gctUINT32_PTR logical = (gctUINT32_PTR) Logical; ++ gceSTATUS status; ++ gctUINT32 reserveBytes ++ /* Semaphore/Stall */ ++ = 4 * gcmSIZEOF(gctUINT32); ++ ++ gcmkHEADER_ARG("Hardware=0x%x Flush=0x%x Logical=0x%x *Bytes=%lu", ++ Hardware, Flush, Logical, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Get current pipe. */ ++ pipe = Hardware->kernel->command->pipeSelect; ++ ++ /* Flush tile status cache. */ ++ flushTileStatus = Flush & gcvFLUSH_TILE_STATUS; ++ ++ /* Flush 3D color cache. */ ++ if ((Flush & gcvFLUSH_COLOR) && (pipe == 0x0)) ++ { ++ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))); ++ } ++ ++ /* Flush 3D depth cache. */ ++ if ((Flush & gcvFLUSH_DEPTH) && (pipe == 0x0)) ++ { ++ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ } ++ ++ /* Flush 3D texture cache. */ ++ if ((Flush & gcvFLUSH_TEXTURE) && (pipe == 0x0)) ++ { ++ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); ++ } ++ ++ /* Flush 2D cache. */ ++ if ((Flush & gcvFLUSH_2D) && (pipe == 0x1)) ++ { ++ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))); ++ } ++ ++ /* Determine reserve bytes. */ ++ if (flush) ++ { ++ reserveBytes += 2 * gcmSIZEOF(gctUINT32); ++ } ++ ++ if (flushTileStatus) ++ { ++ reserveBytes += 2 * gcmSIZEOF(gctUINT32); ++ } ++ ++ /* See if there is a valid flush. */ ++ if ((flush == 0) && (flushTileStatus == gcvFALSE)) ++ { ++ if (Bytes != gcvNULL) ++ { ++ /* No bytes required. */ ++ *Bytes = 0; ++ } ++ } ++ ++ else ++ { ++ /* Copy to command queue. */ ++ if (Logical != gcvNULL) ++ { ++ if (*Bytes < reserveBytes) ++ { ++ /* Command queue too small. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ ++ if (flush) ++ { ++ /* Append LOAD_STATE to AQFlush. */ ++ *logical++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *logical++ ++ = flush; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%x: FLUSH 0x%x", logical - 1, flush); ++ } ++ ++ if (flushTileStatus) ++ { ++ *logical++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ *logical++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "0x%x: FLUSH TILE STATUS 0x%x", logical - 1, logical[-1]); ++ } ++ ++ /* Semaphore. */ ++ *logical++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ *logical++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ ++ /* Stall. */ ++ *logical++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ ++ *logical++ ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x05 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* bytes required. */ ++ *Bytes = reserveBytes; ++ } ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_SetFastClear( ++ IN gckHARDWARE Hardware, ++ IN gctINT Enable, ++ IN gctINT Compression ++ ) ++{ ++#if gcdENABLE_3D ++ gctUINT32 debug; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Enable=%d Compression=%d", ++ Hardware, Enable, Compression); ++ ++ /* Only process if fast clear is available. */ ++ if ((((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) ++ { ++ if (Enable == -1) ++ { ++ /* Determine automatic value for fast clear. */ ++ Enable = ((Hardware->identity.chipModel != gcv500) ++ || (Hardware->identity.chipRevision >= 3) ++ ) ? 1 : 0; ++ } ++ ++ if (Compression == -1) ++ { ++ /* Determine automatic value for compression. */ ++ Compression = Enable ++ & (((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) ); ++ } ++ ++ /* Read AQMemoryDebug register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00414, &debug)); ++ ++ /* Set fast clear bypass. */ ++ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))); ++ ++ if ( ++ ((((gctUINT32) (Hardware->identity.chipMinorFeatures2)) >> (0 ? 27:27) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) || ++ (Hardware->identity.chipModel >= gcv4000)) ++ { ++ /* Set compression bypass. */ ++ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))) | (((gctUINT32) ((gctUINT32) (Compression == 0) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))); ++ } ++ ++ /* Write back AQMemoryDebug register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00414, ++ debug)); ++ ++ /* Store fast clear and comprersison flags. */ ++ Hardware->allowFastClear = Enable; ++ Hardware->allowCompression = Compression; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "FastClear=%d Compression=%d", Enable, Compression); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++#else ++ return gcvSTATUS_OK; ++#endif ++} ++ ++typedef enum ++{ ++ gcvPOWER_FLAG_INITIALIZE = 1 << 0, ++ gcvPOWER_FLAG_STALL = 1 << 1, ++ gcvPOWER_FLAG_STOP = 1 << 2, ++ gcvPOWER_FLAG_START = 1 << 3, ++ gcvPOWER_FLAG_RELEASE = 1 << 4, ++ gcvPOWER_FLAG_DELAY = 1 << 5, ++ gcvPOWER_FLAG_SAVE = 1 << 6, ++ gcvPOWER_FLAG_ACQUIRE = 1 << 7, ++ gcvPOWER_FLAG_POWER_OFF = 1 << 8, ++ gcvPOWER_FLAG_CLOCK_OFF = 1 << 9, ++ gcvPOWER_FLAG_CLOCK_ON = 1 << 10, ++} ++gcePOWER_FLAGS; ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++static gctCONST_STRING ++_PowerEnum(gceCHIPPOWERSTATE State) ++{ ++ const gctCONST_STRING states[] = ++ { ++ gcmSTRING(gcvPOWER_ON), ++ gcmSTRING(gcvPOWER_OFF), ++ gcmSTRING(gcvPOWER_IDLE), ++ gcmSTRING(gcvPOWER_SUSPEND), ++ gcmSTRING(gcvPOWER_SUSPEND_ATPOWERON), ++ gcmSTRING(gcvPOWER_OFF_ATPOWERON), ++ gcmSTRING(gcvPOWER_IDLE_BROADCAST), ++ gcmSTRING(gcvPOWER_SUSPEND_BROADCAST), ++ gcmSTRING(gcvPOWER_OFF_BROADCAST), ++ gcmSTRING(gcvPOWER_OFF_RECOVERY), ++ gcmSTRING(gcvPOWER_OFF_TIMEOUT), ++ gcmSTRING(gcvPOWER_ON_AUTO) ++ }; ++ ++ if ((State >= gcvPOWER_ON) && (State <= gcvPOWER_ON_AUTO)) ++ { ++ return states[State - gcvPOWER_ON]; ++ } ++ ++ return "unknown"; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckHARDWARE_SetPowerManagementState ++** ++** Set GPU to a specified power state. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gceCHIPPOWERSTATE State ++** Power State. ++** ++*/ ++gceSTATUS ++gckHARDWARE_SetPowerManagementState( ++ IN gckHARDWARE Hardware, ++ IN gceCHIPPOWERSTATE State ++ ) ++{ ++ gceSTATUS status; ++ gckCOMMAND command = gcvNULL; ++ gckOS os; ++ gctUINT flag, clock; ++ gctPOINTER buffer; ++ gctUINT32 bytes, requested; ++ gctBOOL acquired = gcvFALSE; ++ gctBOOL mutexAcquired = gcvFALSE; ++ gctBOOL stall = gcvTRUE; ++ gctBOOL broadcast = gcvFALSE; ++#if gcdPOWEROFF_TIMEOUT ++ gctBOOL timeout = gcvFALSE; ++ gctBOOL isAfter = gcvFALSE; ++ gctUINT32 currentTime; ++#endif ++ gctUINT32 process, thread; ++ gctBOOL commitEntered = gcvFALSE; ++ gctBOOL commandStarted = gcvFALSE; ++ gctBOOL isrStarted = gcvFALSE; ++ ++#if gcdENABLE_PROFILING ++ gctUINT64 time, freq, mutexTime, onTime, stallTime, stopTime, delayTime, ++ initTime, offTime, startTime, totalTime; ++#endif ++ gctBOOL global = gcvFALSE; ++ gctBOOL globalAcquired = gcvFALSE; ++ gctBOOL configMmu = gcvFALSE; ++ ++ /* State transition flags. */ ++ static const gctUINT flags[4][4] = ++ { ++ /* gcvPOWER_ON */ ++ { /* ON */ 0, ++ /* OFF */ gcvPOWER_FLAG_ACQUIRE | ++ gcvPOWER_FLAG_STALL | ++ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_POWER_OFF | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ /* IDLE */ gcvPOWER_FLAG_ACQUIRE | ++ gcvPOWER_FLAG_STALL, ++ /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE | ++ gcvPOWER_FLAG_STALL | ++ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ }, ++ ++ /* gcvPOWER_OFF */ ++ { /* ON */ gcvPOWER_FLAG_INITIALIZE | ++ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_RELEASE | ++ gcvPOWER_FLAG_DELAY, ++ /* OFF */ 0, ++ /* IDLE */ gcvPOWER_FLAG_INITIALIZE | ++ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_DELAY, ++ /* SUSPEND */ gcvPOWER_FLAG_INITIALIZE | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ }, ++ ++ /* gcvPOWER_IDLE */ ++ { /* ON */ gcvPOWER_FLAG_RELEASE, ++ /* OFF */ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_POWER_OFF | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ /* IDLE */ 0, ++ /* SUSPEND */ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ }, ++ ++ /* gcvPOWER_SUSPEND */ ++ { /* ON */ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_RELEASE | ++ gcvPOWER_FLAG_DELAY | ++ gcvPOWER_FLAG_CLOCK_ON, ++ /* OFF */ gcvPOWER_FLAG_SAVE | ++ gcvPOWER_FLAG_POWER_OFF | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ /* IDLE */ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_DELAY | ++ gcvPOWER_FLAG_CLOCK_ON, ++ /* SUSPEND */ 0, ++ }, ++ }; ++ ++ /* Clocks. */ ++ static const gctUINT clocks[4] = ++ { ++ /* gcvPOWER_ON */ ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (64) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), ++ ++ /* gcvPOWER_OFF */ ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), ++ ++ /* gcvPOWER_IDLE */ ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), ++ ++ /* gcvPOWER_SUSPEND */ ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), ++ }; ++ ++ gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State); ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Switching to power state %d(%s)", ++ State, _PowerEnum(State)); ++#endif ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Get the gckOS object pointer. */ ++ os = Hardware->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Get the gckCOMMAND object pointer. */ ++ gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL); ++ command = Hardware->kernel->command; ++ gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); ++ ++ /* Start profiler. */ ++ gcmkPROFILE_INIT(freq, time); ++ ++ /* Convert the broadcast power state. */ ++ switch (State) ++ { ++ case gcvPOWER_SUSPEND_ATPOWERON: ++ /* Convert to SUSPEND and don't wait for STALL. */ ++ State = gcvPOWER_SUSPEND; ++ stall = gcvFALSE; ++ break; ++ ++ case gcvPOWER_OFF_ATPOWERON: ++ /* Convert to OFF and don't wait for STALL. */ ++ State = gcvPOWER_OFF; ++ stall = gcvFALSE; ++ break; ++ ++ case gcvPOWER_IDLE_BROADCAST: ++ /* Convert to IDLE and note we are inside broadcast. */ ++ State = gcvPOWER_IDLE; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_SUSPEND_BROADCAST: ++ /* Convert to SUSPEND and note we are inside broadcast. */ ++ State = gcvPOWER_SUSPEND; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_OFF_BROADCAST: ++ /* Convert to OFF and note we are inside broadcast. */ ++ State = gcvPOWER_OFF; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_OFF_RECOVERY: ++ /* Convert to OFF and note we are inside recovery. */ ++ State = gcvPOWER_OFF; ++ stall = gcvFALSE; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_ON_AUTO: ++ /* Convert to ON and note we are inside recovery. */ ++ State = gcvPOWER_ON; ++ break; ++ ++ case gcvPOWER_ON: ++ case gcvPOWER_IDLE: ++ case gcvPOWER_SUSPEND: ++ case gcvPOWER_OFF: ++ /* Mark as global power management. */ ++ global = gcvTRUE; ++ break; ++ ++#if gcdPOWEROFF_TIMEOUT ++ case gcvPOWER_OFF_TIMEOUT: ++ /* Convert to OFF and note we are inside broadcast. */ ++ State = gcvPOWER_OFF; ++ broadcast = gcvTRUE; ++ /* Check time out */ ++ timeout = gcvTRUE; ++ break; ++#endif ++ ++ default: ++ break; ++ } ++ ++ if (Hardware->powerManagement == gcvFALSE ++ && State != gcvPOWER_ON ++ ) ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* Get current process and thread IDs. */ ++ gcmkONERROR(gckOS_GetProcessID(&process)); ++ gcmkONERROR(gckOS_GetThreadID(&thread)); ++ ++ if (broadcast) ++ { ++ /* Try to acquire the power mutex. */ ++ status = gckOS_AcquireMutex(os, Hardware->powerMutex, 3); ++ ++ if (status == gcvSTATUS_TIMEOUT) ++ { ++ /* Check if we already own this mutex. */ ++ if ((Hardware->powerProcess == process) ++ && (Hardware->powerThread == thread) ++ ) ++ { ++ /* Bail out on recursive power management. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ else if (State != gcvPOWER_ON) ++ { ++ /* Called from IST, ++ ** so waiting here will cause deadlock, ++ ** if lock holder call gckCOMMAND_Stall() */ ++ gcmkONWARNING(gcvSTATUS_INVALID_REQUEST); ++ } ++ else ++ { ++ /* Acquire the power mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(os, ++ Hardware->powerMutex, ++ gcvINFINITE)); ++ } ++ } ++ } ++ else ++ { ++ /* Acquire the power mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE)); ++ } ++ ++ /* Before we grab locks see if this is actually a needed change */ ++ if (State == Hardware->chipPowerState) ++ { ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* Get time until mutex acquired. */ ++ gcmkPROFILE_QUERY(time, mutexTime); ++ ++ Hardware->powerProcess = process; ++ Hardware->powerThread = thread; ++ mutexAcquired = gcvTRUE; ++ ++ /* Grab control flags and clock. */ ++ flag = flags[Hardware->chipPowerState][State]; ++ clock = clocks[State]; ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ if (State == gcvPOWER_ON) ++ { ++ clock = ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (Hardware->powerOnFscaleVal) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))); ++ } ++#endif ++ ++ if (State == gcvPOWER_SUSPEND && Hardware->chipPowerState == gcvPOWER_OFF && broadcast) ++ { ++#if gcdPOWER_SUSPEND_WHEN_IDLE ++ /* Do nothing */ ++ ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++#else ++ /* Clock should be on when switch power from off to suspend */ ++ clock = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) ; ++#endif ++ } ++ ++#if gcdPOWEROFF_TIMEOUT ++ if (timeout) ++ { ++ gcmkONERROR(gckOS_GetTicks(¤tTime)); ++ ++ gcmkONERROR( ++ gckOS_TicksAfter(Hardware->powerOffTime, currentTime, &isAfter)); ++ ++ /* powerOffTime is pushed forward, give up.*/ ++ if (isAfter ++ /* Expect a transition start from IDLE or SUSPEND. */ ++ || (Hardware->chipPowerState == gcvPOWER_ON) ++ || (Hardware->chipPowerState == gcvPOWER_OFF) ++ ) ++ { ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ /* No need to do anything. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Power Off GPU[%d] at %u [supposed to be at %u]", ++ Hardware->core, currentTime, Hardware->powerOffTime); ++ } ++ ++ if (State == gcvPOWER_ON || State == gcvPOWER_OFF) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "Cancel powerOfftimer"); ++ ++ /* Cancel running timer when GPU enters ON or OFF. */ ++ gcmkVERIFY_OK(gckOS_StopTimer(os, Hardware->powerOffTimer)); ++ } ++#endif ++ ++ if (flag == 0) ++ { ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ /* No need to do anything. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* If this is an internal power management, we have to check if we can grab ++ ** the global power semaphore. If we cannot, we have to wait until the ++ ** external world changes power management. */ ++ if (!global) ++ { ++ /* Try to acquire the global semaphore. */ ++ status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore); ++ if (status == gcvSTATUS_TIMEOUT) ++ { ++ if (State == gcvPOWER_IDLE || State == gcvPOWER_SUSPEND) ++ { ++ /* Called from thread routine which should NEVER sleep.*/ ++ gcmkONWARNING(gcvSTATUS_INVALID_REQUEST); ++ } ++ ++ /* Release the power mutex. */ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Releasing the power mutex."); ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ mutexAcquired = gcvFALSE; ++ ++ /* Wait for the semaphore. */ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Waiting for global semaphore."); ++ gcmkONERROR(gckOS_AcquireSemaphore(os, Hardware->globalSemaphore)); ++ globalAcquired = gcvTRUE; ++ ++ /* Acquire the power mutex. */ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Reacquiring the power mutex."); ++ gcmkONERROR(gckOS_AcquireMutex(os, ++ Hardware->powerMutex, ++ gcvINFINITE)); ++ mutexAcquired = gcvTRUE; ++ ++ /* chipPowerState may be changed by external world during the time ++ ** we give up powerMutex, so updating flag now is necessary. */ ++ flag = flags[Hardware->chipPowerState][State]; ++ ++ if (flag == 0) ++ { ++ gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore)); ++ globalAcquired = gcvFALSE; ++ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ mutexAcquired = gcvFALSE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ } ++ else ++ { ++ /* Error. */ ++ gcmkONERROR(status); ++ } ++ ++ /* Release the global semaphore again. */ ++ gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore)); ++ globalAcquired = gcvFALSE; ++ } ++ else ++ { ++ if (State == gcvPOWER_OFF || State == gcvPOWER_SUSPEND || State == gcvPOWER_IDLE) ++ { ++ gctBOOL idle; ++ /* Check for idle. */ ++ gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle)); ++ ++ if (!idle) ++ { ++ gcmkONWARNING(gcvSTATUS_CHIP_NOT_READY); ++ } ++ ++ /* Acquire the global semaphore if it has not been acquired. */ ++ status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore); ++ if (status == gcvSTATUS_OK) ++ { ++ globalAcquired = gcvTRUE; ++ } ++ else if (status != gcvSTATUS_TIMEOUT) ++ { ++ /* Other errors. */ ++ gcmkONERROR(status); ++ } ++ /* Ignore gcvSTATUS_TIMEOUT and leave globalAcquired as gcvFALSE. ++ ** gcvSTATUS_TIMEOUT means global semaphore has already ++ ** been acquired before this operation, so even if we fail, ++ ** we should not release it in our error handling. It should be ++ ** released by the next successful global gcvPOWER_ON. */ ++ } ++ ++ /* Global power management can't be aborted, so sync with ++ ** proceeding last commit. */ ++ if (flag & gcvPOWER_FLAG_ACQUIRE) ++ { ++ /* Acquire the power management semaphore. */ ++ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); ++ acquired = gcvTRUE; ++ ++ /* avoid acquiring again. */ ++ flag &= ~gcvPOWER_FLAG_ACQUIRE; ++ } ++ } ++ ++ if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON)) ++ { ++ /* Turn on the power. */ ++ gcmkONERROR(gckOS_SetGPUPower(os, Hardware->core, gcvTRUE, gcvTRUE)); ++ ++ /* Mark clock and power as enabled. */ ++ Hardware->clockState = gcvTRUE; ++ Hardware->powerState = gcvTRUE; ++ ++ for (;;) ++ { ++ /* Check if GPU is present and awake. */ ++ status = _IsGPUPresent(Hardware); ++ ++ /* Check if the GPU is not responding. */ ++ if (status == gcvSTATUS_GPU_NOT_RESPONDING) ++ { ++ /* Turn off the power and clock. */ ++ gcmkONERROR(gckOS_SetGPUPower(os, Hardware->core, gcvFALSE, gcvFALSE)); ++ ++ Hardware->clockState = gcvFALSE; ++ Hardware->powerState = gcvFALSE; ++ ++ /* Wait a little. */ ++ gckOS_Delay(os, 1); ++ ++ /* Turn on the power and clock. */ ++ gcmkONERROR(gckOS_SetGPUPower(os, Hardware->core, gcvTRUE, gcvTRUE)); ++ ++ Hardware->clockState = gcvTRUE; ++ Hardware->powerState = gcvTRUE; ++ ++ /* We need to initialize the hardware and start the command ++ * processor. */ ++ flag |= gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_START; ++ } ++ else ++ { ++ /* Test for error. */ ++ gcmkONERROR(status); ++ ++ /* Break out of loop. */ ++ break; ++ } ++ } ++ } ++ ++ /* Get time until powered on. */ ++ gcmkPROFILE_QUERY(time, onTime); ++ ++ if ((flag & gcvPOWER_FLAG_STALL) && stall) ++ { ++ gctBOOL idle; ++ gctINT32 atomValue; ++ ++ /* For global operation, all pending commits have already been ++ ** blocked by globalSemaphore or powerSemaphore.*/ ++ if (!global) ++ { ++ /* Check commit atom. */ ++ gcmkONERROR(gckOS_AtomGet(os, command->atomCommit, &atomValue)); ++ ++ if (atomValue > 0) ++ { ++ /* Commits are pending - abort power management. */ ++ status = broadcast ? gcvSTATUS_CHIP_NOT_READY ++ : gcvSTATUS_MORE_DATA; ++ goto OnError; ++ } ++ } ++ ++ if (broadcast) ++ { ++ /* Check for idle. */ ++ gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle)); ++ ++ if (!idle) ++ { ++ status = gcvSTATUS_CHIP_NOT_READY; ++ goto OnError; ++ } ++ } ++ ++ else ++ { ++ /* Acquire the command queue. */ ++ gcmkONERROR(gckCOMMAND_EnterCommit(command, gcvTRUE)); ++ commitEntered = gcvTRUE; ++ ++ /* Get the size of the flush command. */ ++ gcmkONERROR(gckHARDWARE_Flush(Hardware, ++ gcvFLUSH_ALL, ++ gcvNULL, ++ &requested)); ++ ++ /* Reserve space in the command queue. */ ++ gcmkONERROR(gckCOMMAND_Reserve(command, ++ requested, ++ &buffer, ++ &bytes)); ++ ++ /* Append a flush. */ ++ gcmkONERROR(gckHARDWARE_Flush( ++ Hardware, gcvFLUSH_ALL, buffer, &bytes ++ )); ++ ++ /* Execute the command queue. */ ++ gcmkONERROR(gckCOMMAND_Execute(command, requested)); ++ ++ /* Release the command queue. */ ++ gcmkONERROR(gckCOMMAND_ExitCommit(command, gcvTRUE)); ++ commitEntered = gcvFALSE; ++ ++ /* Wait to finish all commands. */ ++ gcmkONERROR(gckCOMMAND_Stall(command, gcvTRUE)); ++ } ++ } ++ ++ /* Get time until stalled. */ ++ gcmkPROFILE_QUERY(time, stallTime); ++ ++ if (flag & gcvPOWER_FLAG_ACQUIRE) ++ { ++ /* Acquire the power management semaphore. */ ++ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); ++ acquired = gcvTRUE; ++ } ++ ++ if (flag & gcvPOWER_FLAG_STOP) ++ { ++ /* Stop the command parser. */ ++ gcmkONERROR(gckCOMMAND_Stop(command, gcvFALSE)); ++ ++ /* Stop the Isr. */ ++ if (Hardware->stopIsr) ++ { ++ gcmkONERROR(Hardware->stopIsr(Hardware->isrContext, Hardware->core)); ++ } ++ } ++ ++ /* Flush Cache before Power Off. */ ++ if (flag & gcvPOWER_FLAG_POWER_OFF) ++ { ++ if (Hardware->clockState == gcvFALSE) ++ { ++ /* Turn off the GPU power. */ ++ gcmkONERROR( ++ gckOS_SetGPUPower(os, ++ Hardware->core, ++ gcvTRUE, ++ gcvTRUE)); ++ ++ Hardware->clockState = gcvTRUE; ++ ++ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_DYNAMIC_FREQUENCY_SCALING) != gcvTRUE) ++ { ++ /* Write the clock control register. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(os, ++ Hardware->core, ++ 0x00000, ++ clocks[0])); ++ ++ /* Done loading the frequency scaler. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (clocks[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); ++ } ++ } ++ ++ gcmkONERROR(gckCOMMAND_Start(command)); ++ ++ gcmkONERROR(_FlushCache(Hardware, command)); ++ ++ gckOS_Delay(gcvNULL, 1); ++ ++ /* Stop the command parser. */ ++ gcmkONERROR(gckCOMMAND_Stop(command, gcvFALSE)); ++ ++ flag |= gcvPOWER_FLAG_CLOCK_OFF; ++ } ++ ++ /* Get time until stopped. */ ++ gcmkPROFILE_QUERY(time, stopTime); ++ ++ /* Only process this when hardware is enabled. */ ++ if (Hardware->clockState && Hardware->powerState ++ /* Don't touch clock control if dynamic frequency scaling is available. */ ++ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_DYNAMIC_FREQUENCY_SCALING) != gcvTRUE ++ ) ++ { ++ if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF)) ++ { ++ if (Hardware->identity.chipModel == gcv4000 ++ && ((Hardware->identity.chipRevision == 0x5208) || (Hardware->identity.chipRevision == 0x5222))) ++ { ++ clock &= ~2U; ++ } ++ } ++ ++ /* Write the clock control register. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(os, ++ Hardware->core, ++ 0x00000, ++ clock)); ++ ++ /* Done loading the frequency scaler. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); ++ } ++ ++ if (flag & gcvPOWER_FLAG_DELAY) ++ { ++ /* Wait for the specified amount of time to settle coming back from ++ ** power-off or suspend state. */ ++ gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY)); ++ } ++ ++ /* Get time until delayed. */ ++ gcmkPROFILE_QUERY(time, delayTime); ++ ++ if (flag & gcvPOWER_FLAG_INITIALIZE) ++ { ++ /* Initialize hardware. */ ++ gcmkONERROR(gckHARDWARE_InitializeHardware(Hardware)); ++ ++ gcmkONERROR(gckHARDWARE_SetFastClear(Hardware, ++ Hardware->allowFastClear, ++ Hardware->allowCompression)); ++ ++ /* Force the command queue to reload the next context. */ ++ command->currContext = gcvNULL; ++ ++ /* Need to config mmu after command start. */ ++ configMmu = gcvTRUE; ++ } ++ ++ /* Get time until initialized. */ ++ gcmkPROFILE_QUERY(time, initTime); ++ ++ if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF)) ++ { ++ /* Turn off the GPU power. */ ++ gcmkONERROR( ++ gckOS_SetGPUPower(os, ++ Hardware->core, ++ (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE ++ : gcvTRUE, ++ (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE ++ : gcvTRUE)); ++ ++ /* Save current hardware power and clock states. */ ++ Hardware->clockState = (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE ++ : gcvTRUE; ++ Hardware->powerState = (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE ++ : gcvTRUE; ++ } ++ ++ /* Get time until off. */ ++ gcmkPROFILE_QUERY(time, offTime); ++ ++ if (flag & gcvPOWER_FLAG_START) ++ { ++ /* Start the command processor. */ ++ gcmkONERROR(gckCOMMAND_Start(command)); ++ commandStarted = gcvTRUE; ++ ++ if (Hardware->startIsr) ++ { ++ /* Start the Isr. */ ++ gcmkONERROR(Hardware->startIsr(Hardware->isrContext, Hardware->core)); ++ isrStarted = gcvTRUE; ++ } ++ } ++ ++ /* Get time until started. */ ++ gcmkPROFILE_QUERY(time, startTime); ++ ++ if (flag & gcvPOWER_FLAG_RELEASE) ++ { ++ /* Release the power management semaphore. */ ++ gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore)); ++ acquired = gcvFALSE; ++ ++ if (global) ++ { ++ /* Verify global semaphore has been acquired already before ++ ** we release it. ++ ** If it was acquired, gckOS_TryAcquireSemaphore will return ++ ** gcvSTATUS_TIMEOUT and we release it. Otherwise, global ++ ** semaphore will be acquried now, but it still is released ++ ** immediately. */ ++ status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore); ++ if (status != gcvSTATUS_TIMEOUT) ++ { ++ gcmkONERROR(status); ++ } ++ ++ /* Release the global semaphore. */ ++ gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore)); ++ globalAcquired = gcvFALSE; ++ } ++ } ++ ++ /* Save the new power state. */ ++ Hardware->chipPowerState = State; ++ ++#if gcdDVFS ++ if (State == gcvPOWER_ON && Hardware->kernel->dvfs) ++ { ++ gckDVFS_Start(Hardware->kernel->dvfs); ++ } ++#endif ++ ++#if gcdPOWEROFF_TIMEOUT ++ if (State == gcvPOWER_IDLE || State == gcvPOWER_SUSPEND) ++ { ++ gcmkONERROR(gckOS_GetTicks(¤tTime)); ++ ++ Hardware->powerOffTime = currentTime + Hardware->powerOffTimeout; ++ /* Start a timer to power off GPU when GPU enters IDLE or SUSPEND. */ ++ gcmkVERIFY_OK(gckOS_StartTimer(os, ++ Hardware->powerOffTimer, ++ Hardware->powerOffTimeout)); ++ } ++#endif ++ ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ /* Get total time. */ ++ gcmkPROFILE_QUERY(time, totalTime); ++#if gcdENABLE_PROFILING ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "PROF(%llu): mutex:%llu on:%llu stall:%llu stop:%llu", ++ freq, mutexTime, onTime, stallTime, stopTime); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ " delay:%llu init:%llu off:%llu start:%llu total:%llu", ++ delayTime, initTime, offTime, startTime, totalTime); ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (commandStarted) ++ { ++ gcmkVERIFY_OK(gckCOMMAND_Stop(command, gcvFALSE)); ++ } ++ ++ if (isrStarted) ++ { ++ gcmkVERIFY_OK(Hardware->stopIsr(Hardware->isrContext, Hardware->core)); ++ } ++ ++ if (commitEntered) ++ { ++ /* Release the command queue mutex. */ ++ gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, gcvTRUE)); ++ } ++ ++ if (acquired) ++ { ++ /* Release semaphore. */ ++ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os, ++ command->powerSemaphore)); ++ } ++ ++ if (globalAcquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os, ++ Hardware->globalSemaphore)); ++ } ++ ++ if (mutexAcquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_QueryPowerManagementState ++** ++** Get GPU power state. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gceCHIPPOWERSTATE* State ++** Power State. ++** ++*/ ++gceSTATUS ++gckHARDWARE_QueryPowerManagementState( ++ IN gckHARDWARE Hardware, ++ OUT gceCHIPPOWERSTATE* State ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(State != gcvNULL); ++ ++ /* Return the statue. */ ++ *State = Hardware->chipPowerState; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*State=%d", *State); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_SetPowerManagement ++** ++** Configure GPU power management function. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gctBOOL PowerManagement ++** Power Mangement State. ++** ++*/ ++gceSTATUS ++gckHARDWARE_SetPowerManagement( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL PowerManagement ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ if(!Hardware->powerManagementLock) ++ { ++ gcmkVERIFY_OK( ++ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE)); ++ ++ Hardware->powerManagement = PowerManagement; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); ++ } ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_SetPowerManagementLock ++** ++** Disable dynamic GPU power management switch. ++** Only used in driver initialization stage. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gctBOOL Lock ++** Power Mangement Lock State. ++** ++*/ ++gceSTATUS ++gckHARDWARE_SetPowerManagementLock( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Lock ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ Hardware->powerManagementLock = Lock; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++/******************************************************************************* ++** ++** gckHARDWARE_SetGpuProfiler ++** ++** Configure GPU profiler function. ++** Only used in driver initialization stage. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gctBOOL GpuProfiler ++** GOU Profiler State. ++** ++*/ ++gceSTATUS ++gckHARDWARE_SetGpuProfiler( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL GpuProfiler ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (GpuProfiler == gcvTRUE) ++ { ++ gctUINT32 data = 0; ++ ++ /* Need to disable clock gating when doing profiling. */ ++ gcmkVERIFY_OK( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress + ++ 0x00100, ++ &data)); ++ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ ++ ++ gcmkVERIFY_OK( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00100, ++ data)); ++ } ++ ++ Hardware->gpuProfiler = GpuProfiler; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++gceSTATUS ++gckHARDWARE_SetFscaleValue( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 FscaleValue ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 clock; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Hardware=0x%x FscaleValue=%d", Hardware, FscaleValue); ++ ++ gcmkVERIFY_ARGUMENT(FscaleValue > 0 && FscaleValue <= 64); ++ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ Hardware->powerOnFscaleVal = FscaleValue; ++ ++ if (Hardware->chipPowerState == gcvPOWER_ON) ++ { ++ gctUINT32 data; ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ &data)); ++ ++ /* Disable all clock gating. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))))); ++ ++ clock = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (FscaleValue) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ clock)); ++ ++ /* Done loading the frequency scaler. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); ++ ++ /* Restore all clock gating. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ Hardware->powerBaseAddress ++ + 0x00104, ++ data)); ++ } ++ ++ gcmkVERIFY(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_GetFscaleValue( ++ IN gckHARDWARE Hardware, ++ IN gctUINT * FscaleValue, ++ IN gctUINT * MinFscaleValue, ++ IN gctUINT * MaxFscaleValue ++ ) ++{ ++ *FscaleValue = Hardware->powerOnFscaleVal; ++ *MinFscaleValue = Hardware->minFscaleValue; ++ *MaxFscaleValue = 64; ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckHARDWARE_SetMinFscaleValue( ++ IN gckHARDWARE Hardware, ++ IN gctUINT MinFscaleValue ++ ) ++{ ++ if (MinFscaleValue >= 1 && MinFscaleValue <= 64) ++ { ++ Hardware->minFscaleValue = MinFscaleValue; ++ } ++ ++ return gcvSTATUS_OK; ++} ++#endif ++ ++#if gcdPOWEROFF_TIMEOUT ++gceSTATUS ++gckHARDWARE_SetPowerOffTimeout( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Timeout ++) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x Timeout=%d", Hardware, Timeout); ++ ++ Hardware->powerOffTimeout = Timeout; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++ ++gceSTATUS ++gckHARDWARE_QueryPowerOffTimeout( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32* Timeout ++) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ *Timeout = Hardware->powerOffTimeout; ++ ++ gcmkFOOTER_ARG("*Timeout=%d", *Timeout); ++ return gcvSTATUS_OK; ++} ++#endif ++ ++gceSTATUS ++gckHARDWARE_QueryIdle( ++ IN gckHARDWARE Hardware, ++ OUT gctBOOL_PTR IsIdle ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 idle, address; ++ gctBOOL isIdle; ++ ++#if gcdINTERRUPT_STATISTIC ++ gctINT32 pendingInterrupt; ++#endif ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL); ++ ++ /* We are idle when the power is not ON. */ ++ if (Hardware->chipPowerState != gcvPOWER_ON) ++ { ++ isIdle = gcvTRUE; ++ } ++ ++ else ++ { ++ /* Read idle register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle)); ++ ++ /* Pipe must be idle. */ ++ if (((((((gctUINT32) (idle)) >> (0 ? 1:1)) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 3:3)) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 4:4)) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 6:6)) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 7:7)) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 2:2)) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1)))))) ) != 1) ++ ) ++ { ++ /* Something is busy. */ ++ isIdle = gcvFALSE; ++ } ++ ++ else ++ { ++ /* Read the current FE address. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00664, ++ &address)); ++ ++ /* Test if address is inside the last WAIT/LINK sequence. */ ++ if ((address >= Hardware->lastWaitLink) ++ && (address <= Hardware->lastWaitLink + 16) ++ ) ++ { ++ /* FE is in last WAIT/LINK and the pipe is idle. */ ++ isIdle = gcvTRUE; ++ } ++ else ++ { ++ /* FE is not in WAIT/LINK yet. */ ++ isIdle = gcvFALSE; ++ } ++ } ++ } ++ ++#if gcdINTERRUPT_STATISTIC ++ gcmkONERROR(gckOS_AtomGet( ++ Hardware->os, ++ Hardware->kernel->eventObj->interruptCount, ++ &pendingInterrupt ++ )); ++ ++ if (pendingInterrupt) ++ { ++ isIdle = gcvFALSE; ++ } ++#endif ++ ++ *IsIdle = isIdle; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** Handy macros that will help in reading those debug registers. ++*/ ++ ++#define gcmkREAD_DEBUG_REGISTER(control, block, index, data) \ ++ gcmkONERROR(\ ++ gckOS_WriteRegisterEx(Hardware->os, \ ++ Hardware->core, \ ++ GC_DEBUG_CONTROL##control##_Address, \ ++ gcmSETFIELD(0, \ ++ GC_DEBUG_CONTROL##control, \ ++ block, \ ++ index))); \ ++ gcmkONERROR(\ ++ gckOS_ReadRegisterEx(Hardware->os, \ ++ Hardware->core, \ ++ GC_DEBUG_SIGNALS_##block##_Address, \ ++ &profiler->data)) ++ ++#define gcmkREAD_DEBUG_REGISTER_N(control, block, index, data) \ ++ gcmkONERROR(\ ++ gckOS_WriteRegisterEx(Hardware->os, \ ++ Hardware->core, \ ++ GC_DEBUG_CONTROL##control##_Address, \ ++ gcmSETFIELD(0, \ ++ GC_DEBUG_CONTROL##control, \ ++ block, \ ++ index))); \ ++ gcmkONERROR(\ ++ gckOS_ReadRegisterEx(Hardware->os, \ ++ Hardware->core, \ ++ GC_DEBUG_SIGNALS_##block##_Address, \ ++ &data)) ++ ++#define gcmkRESET_DEBUG_REGISTER(control, block) \ ++ gcmkONERROR(\ ++ gckOS_WriteRegisterEx(Hardware->os, \ ++ Hardware->core, \ ++ GC_DEBUG_CONTROL##control##_Address, \ ++ gcmSETFIELD(0, \ ++ GC_DEBUG_CONTROL##control, \ ++ block, \ ++ 15))); \ ++ gcmkONERROR(\ ++ gckOS_WriteRegisterEx(Hardware->os, \ ++ Hardware->core, \ ++ GC_DEBUG_CONTROL##control##_Address, \ ++ gcmSETFIELD(0, \ ++ GC_DEBUG_CONTROL##control, \ ++ block, \ ++ 0))) ++ ++/******************************************************************************* ++** ++** gckHARDWARE_ProfileEngine2D ++** ++** Read the profile registers available in the 2D engine and sets them in the ++** profile. The function will also reset the pixelsRendered counter every time. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** OPTIONAL gcs2D_PROFILE_PTR Profile ++** Pointer to a gcs2D_Profile structure. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_ProfileEngine2D( ++ IN gckHARDWARE Hardware, ++ OPTIONAL gcs2D_PROFILE_PTR Profile ++ ) ++{ ++ gceSTATUS status; ++ gcs2D_PROFILE_PTR profiler = Profile; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (Profile != gcvNULL) ++ { ++ /* Read the cycle count. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00438, ++ &Profile->cycleCount)); ++ ++ /* Read pixels rendered by 2D engine. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &profiler->pixelsRendered)); ++ ++ /* Reset counter. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ++)); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if VIVANTE_PROFILER ++gceSTATUS ++gckHARDWARE_QueryProfileRegisters( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Reset, ++ OUT gcsPROFILER_COUNTERS * Counters ++ ) ++{ ++ gceSTATUS status; ++ gcsPROFILER_COUNTERS * profiler = Counters; ++ gctUINT i, clock; ++ gctUINT32 colorKilled, colorDrawn, depthKilled, depthDrawn; ++ gctUINT32 totalRead, totalWrite; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Counters=0x%x", Hardware, Counters); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Read the counters. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00438, ++ &profiler->gpuCyclesCounter)); ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00078, ++ &profiler->gpuTotalCyclesCounter)); ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0007C, ++ &profiler->gpuIdleCyclesCounter)); ++ ++ ++ /* Read clock control register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ &clock)); ++ ++ profiler->gpuTotalRead64BytesPerFrame = 0; ++ profiler->gpuTotalWrite64BytesPerFrame = 0; ++ profiler->pe_pixel_count_killed_by_color_pipe = 0; ++ profiler->pe_pixel_count_killed_by_depth_pipe = 0; ++ profiler->pe_pixel_count_drawn_by_color_pipe = 0; ++ profiler->pe_pixel_count_drawn_by_depth_pipe = 0; ++ ++ /* Walk through all avaiable pixel pipes. */ ++ for (i = 0; i < Hardware->identity.pixelPipes; ++i) ++ { ++ /* Select proper pipe. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))))); ++ ++ /* BW */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00040, ++ &totalRead)); ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00044, ++ &totalWrite)); ++ ++ profiler->gpuTotalRead64BytesPerFrame += totalRead; ++ profiler->gpuTotalWrite64BytesPerFrame += totalWrite; ++ ++ /* PE */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &colorKilled)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &depthKilled)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &colorDrawn)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &depthDrawn)); ++ ++ profiler->pe_pixel_count_killed_by_color_pipe += colorKilled; ++ profiler->pe_pixel_count_killed_by_depth_pipe += depthKilled; ++ profiler->pe_pixel_count_drawn_by_color_pipe += colorDrawn; ++ profiler->pe_pixel_count_drawn_by_depth_pipe += depthDrawn; ++ } ++ ++ /* Reset clock control register. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ clock)); ++ ++ /* Reset counters. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 1)); ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 0)); ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00438, 0)); ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00078, 0)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ++)); ++ ++ /* SH */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->ps_inst_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->rendered_pixel_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vs_inst_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->rendered_vertice_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vtx_branch_inst_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vtx_texld_inst_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->pxl_branch_inst_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->pxl_texld_inst_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ++)); ++ ++ /* PA */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_input_vtx_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_input_prim_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_output_prim_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_depth_clipped_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_trivial_rejected_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_culled_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ++)); ++ ++ /* SE */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler->se_culled_triangle_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler->se_culled_lines_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ++)); ++ ++ /* RA */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_valid_pixel_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_total_quad_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_valid_quad_count_after_early_z)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_total_primitive_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_pipe_cache_miss_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_prefetch_cache_miss_counter)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ++)); ++ ++ /* TX */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_bilinear_requests)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_trilinear_requests)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_discarded_texture_requests)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_texture_requests)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_mem_read_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_mem_read_in_8B_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_miss_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_hit_texel_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_miss_texel_count)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ++)); ++ ++ /* MC */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_read_req_8B_from_pipeline)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_read_req_8B_from_IP)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_write_req_8B_from_pipeline)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ++)); ++ ++ /* HI */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_read_request_stalled)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_write_request_stalled)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_write_data_stalled)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ++)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++ ++#if VIVANTE_PROFILER_CONTEXT ++#define gcmkUPDATE_PROFILE_DATA(data) \ ++ profilerHistroy->data += profiler->data ++ ++gceSTATUS ++gckHARDWARE_QueryContextProfile( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Reset, ++ IN gckCONTEXT Context, ++ OUT gcsPROFILER_COUNTERS * Counters ++ ) ++{ ++ gceSTATUS status; ++ gckCOMMAND command = Hardware->kernel->command; ++ gcsPROFILER_COUNTERS * profiler = Counters; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Counters=0x%x", Hardware, Counters); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Acquire the context sequnence mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex( ++ command->os, command->mutexContextSeq, gcvINFINITE ++ )); ++ ++ /* Read the counters. */ ++ gcmkVERIFY_OK(gckOS_MemCopy( ++ profiler, &Context->histroyProfiler, gcmSIZEOF(gcsPROFILER_COUNTERS) ++ )); ++ ++ /* Reset counters. */ ++ gcmkVERIFY_OK(gckOS_ZeroMemory( ++ &Context->histroyProfiler, gcmSIZEOF(gcsPROFILER_COUNTERS) ++ )); ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex( ++ command->os, command->mutexContextSeq ++ )); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gctUINT32 ++CalcDelta( ++ IN gctUINT32 new, ++ IN gctUINT32 old ++ ) ++{ ++ if (new >= old) ++ { ++ return new - old; ++ } ++ else ++ { ++ return (gctUINT32)((gctUINT64)new + 0x100000000ll - old); ++ } ++} ++ ++gceSTATUS ++gckHARDWARE_UpdateContextProfile( ++ IN gckHARDWARE Hardware, ++ IN gckCONTEXT Context ++ ) ++{ ++ gceSTATUS status; ++ gcsPROFILER_COUNTERS * profiler = &Context->latestProfiler; ++ gcsPROFILER_COUNTERS * profilerHistroy = &Context->histroyProfiler; ++ gctUINT i, clock; ++ gctUINT32 colorKilled = 0, colorDrawn = 0, depthKilled = 0, depthDrawn = 0; ++ gctUINT32 totalRead, totalWrite; ++ gceCHIPMODEL chipModel; ++ gctUINT32 chipRevision; ++ gctUINT32 temp; ++ gctBOOL needResetShader = gcvFALSE; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Context=0x%x", Hardware, Context); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT); ++ ++ chipModel = Hardware->identity.chipModel; ++ chipRevision = Hardware->identity.chipRevision; ++ if (chipModel == gcv2000 || (chipModel == gcv2100 && chipRevision == 0x5118)) ++ { ++ needResetShader = gcvTRUE; ++ } ++ ++ /* Read the counters. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00438, ++ &profiler->gpuCyclesCounter)); ++ gcmkUPDATE_PROFILE_DATA(gpuCyclesCounter); ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00078, ++ &profiler->gpuTotalCyclesCounter)); ++ gcmkUPDATE_PROFILE_DATA(gpuTotalCyclesCounter); ++ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0007C, ++ &profiler->gpuIdleCyclesCounter)); ++ gcmkUPDATE_PROFILE_DATA(gpuIdleCyclesCounter); ++ ++ /* Read clock control register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ &clock)); ++ ++ profiler->gpuTotalRead64BytesPerFrame = 0; ++ profiler->gpuTotalWrite64BytesPerFrame = 0; ++ profiler->pe_pixel_count_killed_by_color_pipe = 0; ++ profiler->pe_pixel_count_killed_by_depth_pipe = 0; ++ profiler->pe_pixel_count_drawn_by_color_pipe = 0; ++ profiler->pe_pixel_count_drawn_by_depth_pipe = 0; ++ ++ /* Walk through all avaiable pixel pipes. */ ++ for (i = 0; i < Hardware->identity.pixelPipes; ++i) ++ { ++ /* Select proper pipe. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))))); ++ ++ /* BW */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00040, ++ &totalRead)); ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00044, ++ &totalWrite)); ++ ++ profiler->gpuTotalRead64BytesPerFrame += totalRead; ++ profiler->gpuTotalWrite64BytesPerFrame += totalWrite; ++ gcmkUPDATE_PROFILE_DATA(gpuTotalRead64BytesPerFrame); ++ gcmkUPDATE_PROFILE_DATA(gpuTotalWrite64BytesPerFrame); ++ ++ /* PE */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &colorKilled)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &depthKilled)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &colorDrawn)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &depthDrawn)); ++ ++ profiler->pe_pixel_count_killed_by_color_pipe += colorKilled; ++ profiler->pe_pixel_count_killed_by_depth_pipe += depthKilled; ++ profiler->pe_pixel_count_drawn_by_color_pipe += colorDrawn; ++ profiler->pe_pixel_count_drawn_by_depth_pipe += depthDrawn; ++ gcmkUPDATE_PROFILE_DATA(pe_pixel_count_killed_by_color_pipe); ++ gcmkUPDATE_PROFILE_DATA(pe_pixel_count_killed_by_depth_pipe); ++ gcmkUPDATE_PROFILE_DATA(pe_pixel_count_drawn_by_color_pipe); ++ gcmkUPDATE_PROFILE_DATA(pe_pixel_count_drawn_by_depth_pipe); ++ } ++ ++ /* Reset clock control register. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ clock)); ++ ++ ++ /* Reset counters. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 1)); ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 0)); ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00438, 0)); ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00078, 0)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ++)); ++ ++ /* SH */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->ps_inst_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->ps_inst_counter; ++ profiler->ps_inst_counter = CalcDelta(temp, Context->prevPSInstCount); ++ Context->prevPSInstCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(ps_inst_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->rendered_pixel_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->rendered_pixel_counter; ++ profiler->rendered_pixel_counter = CalcDelta(temp, Context->prevPSPixelCount); ++ Context->prevPSPixelCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(rendered_pixel_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vs_inst_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->vs_inst_counter; ++ profiler->vs_inst_counter = CalcDelta(temp, Context->prevVSInstCount); ++ Context->prevVSInstCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(vs_inst_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->rendered_vertice_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->rendered_vertice_counter; ++ profiler->rendered_vertice_counter = CalcDelta(temp, Context->prevVSVertexCount); ++ Context->prevVSVertexCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(rendered_vertice_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vtx_branch_inst_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->vtx_branch_inst_counter; ++ profiler->vtx_branch_inst_counter = CalcDelta(temp, Context->prevVSBranchInstCount); ++ Context->prevVSBranchInstCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(vtx_branch_inst_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vtx_texld_inst_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->vtx_texld_inst_counter; ++ profiler->vtx_texld_inst_counter = CalcDelta(temp, Context->prevVSTexInstCount); ++ Context->prevVSTexInstCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(vtx_texld_inst_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->pxl_branch_inst_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->pxl_branch_inst_counter; ++ profiler->pxl_branch_inst_counter = CalcDelta(temp, Context->prevPSBranchInstCount); ++ Context->prevPSBranchInstCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(pxl_branch_inst_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->pxl_texld_inst_counter)); ++ if (needResetShader) ++ { ++ temp = profiler->pxl_texld_inst_counter; ++ profiler->pxl_texld_inst_counter = CalcDelta(temp, Context->prevPSTexInstCount); ++ Context->prevPSTexInstCount = temp; ++ } ++ gcmkUPDATE_PROFILE_DATA(pxl_texld_inst_counter); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ++)); ++ ++ /* PA */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_input_vtx_counter)); ++ gcmkUPDATE_PROFILE_DATA(pa_input_vtx_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_input_prim_counter)); ++ gcmkUPDATE_PROFILE_DATA(pa_input_prim_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_output_prim_counter)); ++ gcmkUPDATE_PROFILE_DATA(pa_output_prim_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_depth_clipped_counter)); ++ gcmkUPDATE_PROFILE_DATA(pa_depth_clipped_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_trivial_rejected_counter)); ++ gcmkUPDATE_PROFILE_DATA(pa_trivial_rejected_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_culled_counter)); ++ gcmkUPDATE_PROFILE_DATA(pa_culled_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ++)); ++ ++ /* SE */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler->se_culled_triangle_count)); ++ gcmkUPDATE_PROFILE_DATA(se_culled_triangle_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler->se_culled_lines_count)); ++ gcmkUPDATE_PROFILE_DATA(se_culled_lines_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ++)); ++ ++ /* RA */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_valid_pixel_count)); ++ gcmkUPDATE_PROFILE_DATA(ra_valid_pixel_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_total_quad_count)); ++ gcmkUPDATE_PROFILE_DATA(ra_total_quad_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_valid_quad_count_after_early_z)); ++ gcmkUPDATE_PROFILE_DATA(ra_valid_quad_count_after_early_z); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_total_primitive_count)); ++ gcmkUPDATE_PROFILE_DATA(ra_total_primitive_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_pipe_cache_miss_counter)); ++ gcmkUPDATE_PROFILE_DATA(ra_pipe_cache_miss_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_prefetch_cache_miss_counter)); ++ gcmkUPDATE_PROFILE_DATA(ra_prefetch_cache_miss_counter); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ? 23:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ++)); ++ ++ /* TX */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_bilinear_requests)); ++ gcmkUPDATE_PROFILE_DATA(tx_total_bilinear_requests); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_trilinear_requests)); ++ gcmkUPDATE_PROFILE_DATA(tx_total_trilinear_requests); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_discarded_texture_requests)); ++ gcmkUPDATE_PROFILE_DATA(tx_total_discarded_texture_requests); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_texture_requests)); ++ gcmkUPDATE_PROFILE_DATA(tx_total_texture_requests); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_mem_read_count)); ++ gcmkUPDATE_PROFILE_DATA(tx_mem_read_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_mem_read_in_8B_count)); ++ gcmkUPDATE_PROFILE_DATA(tx_mem_read_in_8B_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_miss_count)); ++ gcmkUPDATE_PROFILE_DATA(tx_cache_miss_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_hit_texel_count)); ++ gcmkUPDATE_PROFILE_DATA(tx_cache_hit_texel_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_miss_texel_count)); ++ gcmkUPDATE_PROFILE_DATA(tx_cache_miss_texel_count); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ++)); ++ ++ /* MC */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_read_req_8B_from_pipeline)); ++ gcmkUPDATE_PROFILE_DATA(mc_total_read_req_8B_from_pipeline); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_read_req_8B_from_IP)); ++ gcmkUPDATE_PROFILE_DATA(mc_total_read_req_8B_from_IP); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_write_req_8B_from_pipeline)); ++ gcmkUPDATE_PROFILE_DATA(mc_total_write_req_8B_from_pipeline); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ++)); ++ ++ /* HI */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_read_request_stalled)); ++ gcmkUPDATE_PROFILE_DATA(hi_axi_cycles_read_request_stalled); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_write_request_stalled)); ++ gcmkUPDATE_PROFILE_DATA(hi_axi_cycles_write_request_stalled); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_write_data_stalled)); ++ gcmkUPDATE_PROFILE_DATA(hi_axi_cycles_write_data_stalled); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) )); ++gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ++)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++ ++#if VIVANTE_PROFILER_NEW ++gceSTATUS ++gckHARDWARE_InitProfiler( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 control; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ &control)); ++ /* Enable debug register. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))))); ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++static gceSTATUS ++_ResetGPU( ++ IN gckHARDWARE Hardware, ++ IN gckOS Os, ++ IN gceCORE Core ++ ) ++{ ++ gctUINT32 control, idle; ++ gceSTATUS status; ++ ++ for (;;) ++ { ++ /* Disable clock gating. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ Hardware->powerBaseAddress + ++ 0x00104, ++ 0x00000000)); ++ ++ control = ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))); ++ ++ /* Disable pulse-eater. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x0010C, ++ control)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x0010C, ++ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x0010C, ++ control)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x00000, ++ ((((gctUINT32) (0x00000900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x00000, ++ 0x00000900)); ++ ++ /* Wait for clock being stable. */ ++ gcmkONERROR(gckOS_Delay(Os, 1)); ++ ++ /* Isolate the GPU. */ ++ control = ((((gctUINT32) (0x00000900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x00000, ++ control)); ++ ++ /* Set soft reset. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x00000, ++ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); ++ ++ /* Wait for reset. */ ++ gcmkONERROR(gckOS_Delay(Os, 1)); ++ ++ /* Reset soft reset bit. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x00000, ++ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); ++ ++ /* Reset GPU isolation. */ ++ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ Core, ++ 0x00000, ++ control)); ++ ++ /* Read idle register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, ++ Core, ++ 0x00004, ++ &idle)); ++ ++ if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0) ++ { ++ continue; ++ } ++ ++ /* Read reset register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, ++ Core, ++ 0x00000, ++ &control)); ++ ++ if (((((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ) == 0) ++ || ((((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) ) == 0) ++ ) ++ { ++ continue; ++ } ++ ++ /* GPU is idle. */ ++ break; ++ } ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ /* Return the error. */ ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_Reset( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL); ++ ++ /* Hardware reset. */ ++ status = gckOS_ResetGPU(Hardware->os, Hardware->core); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ if (Hardware->identity.chipRevision < 0x4600) ++ { ++ /* Not supported - we need the isolation bit. */ ++ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); ++ } ++ ++ /* Soft reset. */ ++ gcmkONERROR(_ResetGPU(Hardware, Hardware->os, Hardware->core)); ++ } ++ ++ /* Initialize hardware. */ ++ gcmkONERROR(gckHARDWARE_InitializeHardware(Hardware)); ++ ++ /* Jump to address into which GPU should run if it doesn't stuck. */ ++ gcmkONERROR(gckHARDWARE_Execute(Hardware, Hardware->kernel->restoreAddress, 16)); ++ ++ gcmkPRINT("[galcore]: recovery done"); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkPRINT("[galcore]: Hardware not reset successfully, give up"); ++ ++ /* Return the error. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_GetBaseAddress( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32_PTR BaseAddress ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); ++ ++ /* Test if we have a new Memory Controller. */ ++ if (((((gctUINT32) (Hardware->identity.chipMinorFeatures)) >> (0 ? 22:22) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))))) ++ { ++ /* No base address required. */ ++ *BaseAddress = 0; ++ } ++ else ++ { ++ /* Get the base address from the OS. */ ++ gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, BaseAddress)); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_NeedBaseAddress( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 State, ++ OUT gctBOOL_PTR NeedBase ++ ) ++{ ++ gctBOOL need = gcvFALSE; ++ ++ gcmkHEADER_ARG("Hardware=0x%x State=0x%08x", Hardware, State); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(NeedBase != gcvNULL); ++ ++ /* Make sure this is a load state. */ ++ if (((((gctUINT32) (State)) >> (0 ? 31:27) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))))) ++ { ++#if gcdENABLE_3D ++ /* Get the state address. */ ++ switch ((((((gctUINT32) (State)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) )) ++ { ++ case 0x0596: ++ case 0x0597: ++ case 0x0599: ++ case 0x059A: ++ case 0x05A9: ++ /* These states need a TRUE physical address. */ ++ need = gcvTRUE; ++ break; ++ } ++#else ++ /* 2D addresses don't need a base address. */ ++#endif ++ } ++ ++ /* Return the flag. */ ++ *NeedBase = need; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*NeedBase=%d", *NeedBase); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckHARDWARE_SetIsrManager( ++ IN gckHARDWARE Hardware, ++ IN gctISRMANAGERFUNC StartIsr, ++ IN gctISRMANAGERFUNC StopIsr, ++ IN gctPOINTER Context ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ ++ gcmkHEADER_ARG("Hardware=0x%x, StartIsr=0x%x, StopIsr=0x%x, Context=0x%x", ++ Hardware, StartIsr, StopIsr, Context); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (StartIsr == gcvNULL || ++ StopIsr == gcvNULL || ++ Context == gcvNULL) ++ { ++ status = gcvSTATUS_INVALID_ARGUMENT; ++ ++ gcmkFOOTER(); ++ return status; ++ } ++ ++ Hardware->startIsr = StartIsr; ++ Hardware->stopIsr = StopIsr; ++ Hardware->isrContext = Context; ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_Compose ++** ++** Start a composition. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_Compose( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Offset, ++ IN gctSIZE_T Size, ++ IN gctUINT8 EventID ++ ) ++{ ++#if gcdENABLE_3D ++ gceSTATUS status; ++ gctUINT32_PTR triggerState; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Physical=0x%x Logical=0x%x" ++ " Offset=%d Size=%d EventID=%d", ++ Hardware, Physical, Logical, Offset, Size, EventID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(((Size + 8) & 63) == 0); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ /* Program the trigger state. */ ++ triggerState = (gctUINT32_PTR) ((gctUINT8_PTR) Logical + Offset + Size); ++ triggerState[0] = 0x0C03; ++ triggerState[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:4) - (0 ? 5:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ? 5:4) - (0 ? 5:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:16) - (0 ? 20:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ? 20:16))) | (((gctUINT32) ((gctUINT32) (EventID) & ((gctUINT32) ((((1 ? 20:16) - (0 ? 20:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ? 20:16))) ++ ; ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the cache for the wait/link. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Hardware->os, ProcessID, gcvNULL, ++ (gctUINT32)Physical, Logical, Offset + Size ++ )); ++#endif ++ ++ /* Start composition. */ ++ gcmkONERROR(gckOS_WriteRegisterEx( ++ Hardware->os, Hardware->core, 0x00554, ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) ++ )); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++#else ++ /* Return the status. */ ++ return gcvSTATUS_NOT_SUPPORTED; ++#endif ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_IsFeatureAvailable ++** ++** Verifies whether the specified feature is available in hardware. ++** ++** INPUT: ++** ++** gckHARDWARE Hardware ++** Pointer to an gckHARDWARE object. ++** ++** gceFEATURE Feature ++** Feature to be verified. ++*/ ++gceSTATUS ++gckHARDWARE_IsFeatureAvailable( ++ IN gckHARDWARE Hardware, ++ IN gceFEATURE Feature ++ ) ++{ ++ gctBOOL available; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Feature=%d", Hardware, Feature); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Only features needed by common kernel logic added here. */ ++ switch (Feature) ++ { ++ case gcvFEATURE_END_EVENT: ++ /*available = gcmVERIFYFIELDVALUE(Hardware->identity.chipMinorFeatures2, ++ GC_MINOR_FEATURES2, END_EVENT, AVAILABLE ++ );*/ ++ available = gcvFALSE; ++ break; ++ ++ case gcvFEATURE_MC20: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures)) >> (0 ? 22:22) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1))))))); ++ break; ++ ++ case gcvFEATURE_EARLY_Z: ++ available = ((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 16:16) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))); ++ break; ++ ++ case gcvFEATURE_HZ: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures)) >> (0 ? 27:27) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))); ++ break; ++ ++ case gcvFEATURE_NEW_HZ: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures3)) >> (0 ? 26:26) & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))); ++ break; ++ ++ case gcvFEATURE_FAST_MSAA: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures3)) >> (0 ? 8:8) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1))))))); ++ break; ++ ++ case gcvFEATURE_SMALL_MSAA: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures4)) >> (0 ? 18:18) & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1))))))); ++ break; ++ ++ case gcvFEATURE_DYNAMIC_FREQUENCY_SCALING: ++ /* This feature doesn't apply for 2D cores. */ ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures2)) >> (0 ? 14:14) & ((gctUINT32) ((((1 ? 14:14) - (0 ? 14:14) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 14:14) - (0 ? 14:14) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 14:14) - (0 ? 14:14) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 14:14) - (0 ? 14:14) + 1))))))) ++ && ((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 2:2) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))); ++ ++ if (Hardware->identity.chipModel == gcv1000 && ++ (Hardware->identity.chipRevision == 0x5039 || ++ Hardware->identity.chipRevision == 0x5040)) ++ { ++ available = gcvFALSE; ++ } ++ break; ++ ++ case gcvFEATURE_ACE: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures3)) >> (0 ? 18:18) & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1))))))); ++ break; ++ ++ case gcvFEATURE_HALTI2: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures4)) >> (0 ? 16:16) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))); ++ break; ++ ++ case gcvFEATURE_PIPE_2D: ++ available = ((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 9:9) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))); ++ break; ++ ++ case gcvFEATURE_PIPE_3D: ++#if gcdENABLE_3D ++ available = ((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 2:2) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))); ++#else ++ available = gcvFALSE; ++#endif ++ break; ++ ++ case gcvFEATURE_FC_FLUSH_STALL: ++ available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures1)) >> (0 ? 31:31) & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))); ++ break; ++ ++ default: ++ gcmkFATAL("Invalid feature has been requested."); ++ available = gcvFALSE; ++ } ++ ++ /* Return result. */ ++ gcmkFOOTER_ARG("%d", available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE); ++ return available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_DumpMMUException ++** ++** Dump the MMU debug info on an MMU exception. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_DumpMMUException( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gctUINT32 mmu = 0; ++ gctUINT32 mmuStatus = 0; ++ gctUINT32 address = 0; ++ gctUINT32 i = 0; ++ gctUINT32 mtlb = 0; ++ gctUINT32 stlb = 0; ++ gctUINT32 offset = 0; ++#if gcdPROCESS_ADDRESS_SPACE ++ gcsDATABASE_PTR database; ++#endif ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ gcmkPRINT("GPU[%d](ChipModel=0x%x ChipRevision=0x%x):\n", ++ Hardware->core, ++ Hardware->identity.chipModel, ++ Hardware->identity.chipRevision); ++ ++ gcmkPRINT("**************************\n"); ++ gcmkPRINT("*** MMU ERROR DUMP ***\n"); ++ gcmkPRINT("**************************\n"); ++ ++ gcmkVERIFY_OK( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00188, ++ &mmuStatus)); ++ ++ gcmkPRINT(" MMU status = 0x%08X\n", mmuStatus); ++ ++ for (i = 0; i < 4; i += 1) ++ { ++ mmu = mmuStatus & 0xF; ++ mmuStatus >>= 4; ++ ++ if (mmu == 0) ++ { ++ continue; ++ } ++ ++ switch (mmu) ++ { ++ case 1: ++ gcmkPRINT(" MMU%d: slave not present\n", i); ++ break; ++ ++ case 2: ++ gcmkPRINT(" MMU%d: page not present\n", i); ++ break; ++ ++ case 3: ++ gcmkPRINT(" MMU%d: write violation\n", i); ++ break; ++ ++ default: ++ gcmkPRINT(" MMU%d: unknown state\n", i); ++ } ++ ++ gcmkVERIFY_OK( ++ gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00190 + i * 4, ++ &address)); ++ ++ mtlb = (address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT; ++ stlb = (address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT; ++ offset = address & gcdMMU_OFFSET_4K_MASK; ++ ++ gcmkPRINT(" MMU%d: exception address = 0x%08X\n", i, address); ++ ++ gcmkPRINT(" MTLB entry = %d\n", mtlb); ++ ++ gcmkPRINT(" STLB entry = %d\n", stlb); ++ ++ gcmkPRINT(" Offset = 0x%08X (%d)\n", offset, offset); ++ ++ gckMMU_DumpPageTableEntry(Hardware->kernel->mmu, address); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ for (i = 0; i < gcmCOUNTOF(Hardware->kernel->db->db); ++i) ++ { ++ for (database = Hardware->kernel->db->db[i]; ++ database != gcvNULL; ++ database = database->next) ++ { ++ gcmkPRINT(" database [%d] :", database->processID); ++ gckMMU_DumpPageTableEntry(database->mmu, address); ++ } ++ } ++#endif ++ } ++ ++ gckHARDWARE_DumpGPUState(Hardware); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_DumpGPUState ++** ++** Dump the GPU debug registers. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckHARDWARE_DumpGPUState( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ static gctCONST_STRING _cmdState[] = ++ { ++ "PAR_IDLE_ST", "PAR_DEC_ST", "PAR_ADR0_ST", "PAR_LOAD0_ST", ++ "PAR_ADR1_ST", "PAR_LOAD1_ST", "PAR_3DADR_ST", "PAR_3DCMD_ST", ++ "PAR_3DCNTL_ST", "PAR_3DIDXCNTL_ST", "PAR_INITREQDMA_ST", ++ "PAR_DRAWIDX_ST", "PAR_DRAW_ST", "PAR_2DRECT0_ST", "PAR_2DRECT1_ST", ++ "PAR_2DDATA0_ST", "PAR_2DDATA1_ST", "PAR_WAITFIFO_ST", "PAR_WAIT_ST", ++ "PAR_LINK_ST", "PAR_END_ST", "PAR_STALL_ST" ++ }; ++ ++ static gctCONST_STRING _cmdDmaState[] = ++ { ++ "CMD_IDLE_ST", "CMD_START_ST", "CMD_REQ_ST", "CMD_END_ST" ++ }; ++ ++ static gctCONST_STRING _cmdFetState[] = ++ { ++ "FET_IDLE_ST", "FET_RAMVALID_ST", "FET_VALID_ST" ++ }; ++ ++ static gctCONST_STRING _reqDmaState[] = ++ { ++ "REQ_IDLE_ST", "REQ_WAITIDX_ST", "REQ_CAL_ST" ++ }; ++ ++ static gctCONST_STRING _calState[] = ++ { ++ "CAL_IDLE_ST", "CAL_LDADR_ST", "CAL_IDXCALC_ST" ++ }; ++ ++ static gctCONST_STRING _veReqState[] = ++ { ++ "VER_IDLE_ST", "VER_CKCACHE_ST", "VER_MISS_ST" ++ }; ++ ++ static gcsiDEBUG_REGISTERS _dbgRegs[] = ++ { ++ { "RA", 0x474, 16, 0x448, 16, 0x12344321 }, ++ { "TX", 0x474, 24, 0x44C, 16, 0x12211221 }, ++ { "FE", 0x470, 0, 0x450, 16, 0xBABEF00D }, ++ { "PE", 0x470, 16, 0x454, 16, 0xBABEF00D }, ++ { "DE", 0x470, 8, 0x458, 16, 0xBABEF00D }, ++ { "SH", 0x470, 24, 0x45C, 16, 0xDEADBEEF }, ++ { "PA", 0x474, 0, 0x460, 16, 0x0000AAAA }, ++ { "SE", 0x474, 8, 0x464, 16, 0x5E5E5E5E }, ++ { "MC", 0x478, 0, 0x468, 16, 0x12345678 }, ++ { "HI", 0x478, 8, 0x46C, 16, 0xAAAAAAAA } ++ }; ++ ++ static gctUINT32 _otherRegs[] = ++ { ++ 0x040, 0x044, 0x04C, 0x050, 0x054, 0x058, 0x05C, 0x060, ++ 0x43c, 0x440, 0x444, 0x414, ++ }; ++ ++ gceSTATUS status; ++ gckKERNEL kernel = gcvNULL; ++ gctUINT32 idle = 0, axi = 0; ++ gctUINT32 dmaAddress1 = 0, dmaAddress2 = 0; ++ gctUINT32 dmaState1 = 0, dmaState2 = 0; ++ gctUINT32 dmaLow = 0, dmaHigh = 0; ++ gctUINT32 cmdState = 0, cmdDmaState = 0, cmdFetState = 0; ++ gctUINT32 dmaReqState = 0, calState = 0, veReqState = 0; ++ gctUINT i; ++ gctUINT pipe = 0, pixelPipes = 0; ++ gctUINT32 control = 0, oldControl = 0; ++ gckOS os = Hardware->os; ++ gceCORE core = Hardware->core; ++ ++ gcmkHEADER_ARG("Hardware=0x%X", Hardware); ++ ++ kernel = Hardware->kernel; ++ ++ gcmkPRINT_N(12, "GPU[%d](ChipModel=0x%x ChipRevision=0x%x):\n", ++ core, ++ Hardware->identity.chipModel, ++ Hardware->identity.chipRevision); ++ ++ pixelPipes = Hardware->identity.pixelPipes ++ ? Hardware->identity.pixelPipes ++ : 1; ++ ++ /* Reset register values. */ ++ idle = axi = ++ dmaState1 = dmaState2 = ++ dmaAddress1 = dmaAddress2 = ++ dmaLow = dmaHigh = 0; ++ ++ /* Verify whether DMA is running. */ ++ gcmkONERROR(_VerifyDMA( ++ os, core, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2 ++ )); ++ ++ cmdState = dmaState2 & 0x1F; ++ cmdDmaState = (dmaState2 >> 8) & 0x03; ++ cmdFetState = (dmaState2 >> 10) & 0x03; ++ dmaReqState = (dmaState2 >> 12) & 0x03; ++ calState = (dmaState2 >> 14) & 0x03; ++ veReqState = (dmaState2 >> 16) & 0x03; ++ ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x004, &idle)); ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x00C, &axi)); ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x668, &dmaLow)); ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x66C, &dmaHigh)); ++ ++ gcmkPRINT_N(0, "**************************\n"); ++ gcmkPRINT_N(0, "*** GPU STATE DUMP ***\n"); ++ gcmkPRINT_N(0, "**************************\n"); ++ ++ gcmkPRINT_N(4, " axi = 0x%08X\n", axi); ++ ++ gcmkPRINT_N(4, " idle = 0x%08X\n", idle); ++ if ((idle & 0x00000001) == 0) gcmkPRINT_N(0, " FE not idle\n"); ++ if ((idle & 0x00000002) == 0) gcmkPRINT_N(0, " DE not idle\n"); ++ if ((idle & 0x00000004) == 0) gcmkPRINT_N(0, " PE not idle\n"); ++ if ((idle & 0x00000008) == 0) gcmkPRINT_N(0, " SH not idle\n"); ++ if ((idle & 0x00000010) == 0) gcmkPRINT_N(0, " PA not idle\n"); ++ if ((idle & 0x00000020) == 0) gcmkPRINT_N(0, " SE not idle\n"); ++ if ((idle & 0x00000040) == 0) gcmkPRINT_N(0, " RA not idle\n"); ++ if ((idle & 0x00000080) == 0) gcmkPRINT_N(0, " TX not idle\n"); ++ if ((idle & 0x00000100) == 0) gcmkPRINT_N(0, " VG not idle\n"); ++ if ((idle & 0x00000200) == 0) gcmkPRINT_N(0, " IM not idle\n"); ++ if ((idle & 0x00000400) == 0) gcmkPRINT_N(0, " FP not idle\n"); ++ if ((idle & 0x00000800) == 0) gcmkPRINT_N(0, " TS not idle\n"); ++ if ((idle & 0x80000000) != 0) gcmkPRINT_N(0, " AXI low power mode\n"); ++ ++ if ( ++ (dmaAddress1 == dmaAddress2) ++ && (dmaState1 == dmaState2) ++ ) ++ { ++ gcmkPRINT_N(0, " DMA appears to be stuck at this address:\n"); ++ gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1); ++ } ++ else ++ { ++ if (dmaAddress1 == dmaAddress2) ++ { ++ gcmkPRINT_N(0, " DMA address is constant, but state is changing:\n"); ++ gcmkPRINT_N(4, " 0x%08X\n", dmaState1); ++ gcmkPRINT_N(4, " 0x%08X\n", dmaState2); ++ } ++ else ++ { ++ gcmkPRINT_N(0, " DMA is running; known addresses are:\n"); ++ gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1); ++ gcmkPRINT_N(4, " 0x%08X\n", dmaAddress2); ++ } ++ } ++ ++ gcmkPRINT_N(4, " dmaLow = 0x%08X\n", dmaLow); ++ gcmkPRINT_N(4, " dmaHigh = 0x%08X\n", dmaHigh); ++ gcmkPRINT_N(4, " dmaState = 0x%08X\n", dmaState2); ++ gcmkPRINT_N(8, " command state = %d (%s)\n", cmdState, _cmdState [cmdState]); ++ gcmkPRINT_N(8, " command DMA state = %d (%s)\n", cmdDmaState, _cmdDmaState[cmdDmaState]); ++ gcmkPRINT_N(8, " command fetch state = %d (%s)\n", cmdFetState, _cmdFetState[cmdFetState]); ++ gcmkPRINT_N(8, " DMA request state = %d (%s)\n", dmaReqState, _reqDmaState[dmaReqState]); ++ gcmkPRINT_N(8, " cal state = %d (%s)\n", calState, _calState [calState]); ++ gcmkPRINT_N(8, " VE request state = %d (%s)\n", veReqState, _veReqState [veReqState]); ++ ++ /* Record control. */ ++ gckOS_ReadRegisterEx(os, core, 0x0, &oldControl); ++ ++ for (pipe = 0; pipe < pixelPipes; pipe++) ++ { ++ gcmkPRINT_N(4, " Debug registers of pipe[%d]:\n", pipe); ++ ++ /* Switch pipe. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0, &control)); ++ control &= ~(0xF << 20); ++ control |= (pipe << 20); ++ gcmkONERROR(gckOS_WriteRegisterEx(os, core, 0x0, control)); ++ ++ for (i = 0; i < gcmCOUNTOF(_dbgRegs); i += 1) ++ { ++ gcmkONERROR(_DumpDebugRegisters(os, core, &_dbgRegs[i])); ++ } ++ ++ gcmkPRINT_N(0, " Other Registers:\n"); ++ for (i = 0; i < gcmCOUNTOF(_otherRegs); i += 1) ++ { ++ gctUINT32 read; ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, _otherRegs[i], &read)); ++ gcmkPRINT_N(12, " [0x%04X] 0x%08X\n", _otherRegs[i], read); ++ } ++ } ++ ++ if (kernel->hardware->identity.chipFeatures & (1 << 4)) ++ { ++ gctUINT32 read0, read1, write; ++ ++ read0 = read1 = write = 0; ++ ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x43C, &read0)); ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x440, &read1)); ++ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x444, &write)); ++ ++ gcmkPRINT_N(4, " read0 = 0x%08X\n", read0); ++ gcmkPRINT_N(4, " read1 = 0x%08X\n", read1); ++ gcmkPRINT_N(4, " write = 0x%08X\n", write); ++ } ++ ++ /* Restore control. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(os, core, 0x0, oldControl)); ++ ++ /* dump stack. */ ++ gckOS_DumpCallStack(os); ++ ++OnError: ++ ++ /* Return the error. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++gckHARDWARE_ReadPerformanceRegister( ++ IN gckHARDWARE Hardware, ++ IN gctUINT PerformanceAddress, ++ IN gctUINT IndexAddress, ++ IN gctUINT IndexShift, ++ IN gctUINT Index, ++ OUT gctUINT32_PTR Value ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x PerformanceAddress=0x%x IndexAddress=0x%x " ++ "IndexShift=%u Index=%u", ++ Hardware, PerformanceAddress, IndexAddress, IndexShift, ++ Index); ++ ++ /* Write the index. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ IndexAddress, ++ Index << IndexShift)); ++ ++ /* Read the register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ PerformanceAddress, ++ Value)); ++ ++ /* Test for reset. */ ++ if (Index == 15) ++ { ++ /* Index another register to get out of reset. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, IndexAddress, 0)); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Value=0x%x", *Value); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_GetFrameInfo( ++ IN gckHARDWARE Hardware, ++ OUT gcsHAL_FRAME_INFO * FrameInfo ++ ) ++{ ++ gceSTATUS status; ++ gctUINT i, clock; ++ gcsHAL_FRAME_INFO info; ++#if gcdFRAME_DB_RESET ++ gctUINT reset; ++#endif ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Get profile tick. */ ++ gcmkONERROR(gckOS_GetProfileTick(&info.ticks)); ++ ++ /* Read SH counters and reset them. */ ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0045C, ++ 0x00470, ++ 24, ++ 4, ++ &info.shaderCycles)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0045C, ++ 0x00470, ++ 24, ++ 9, ++ &info.vsInstructionCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0045C, ++ 0x00470, ++ 24, ++ 12, ++ &info.vsTextureCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0045C, ++ 0x00470, ++ 24, ++ 7, ++ &info.psInstructionCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0045C, ++ 0x00470, ++ 24, ++ 14, ++ &info.psTextureCount)); ++#if gcdFRAME_DB_RESET ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0045C, ++ 0x00470, ++ 24, ++ 15, ++ &reset)); ++#endif ++ ++ /* Read PA counters and reset them. */ ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00460, ++ 0x00474, ++ 0, ++ 3, ++ &info.vertexCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00460, ++ 0x00474, ++ 0, ++ 4, ++ &info.primitiveCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00460, ++ 0x00474, ++ 0, ++ 7, ++ &info.rejectedPrimitives)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00460, ++ 0x00474, ++ 0, ++ 8, ++ &info.culledPrimitives)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00460, ++ 0x00474, ++ 0, ++ 6, ++ &info.clippedPrimitives)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00460, ++ 0x00474, ++ 0, ++ 5, ++ &info.outPrimitives)); ++#if gcdFRAME_DB_RESET ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00460, ++ 0x00474, ++ 0, ++ 15, ++ &reset)); ++#endif ++ ++ /* Read RA counters and reset them. */ ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00448, ++ 0x00474, ++ 16, ++ 3, ++ &info.inPrimitives)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00448, ++ 0x00474, ++ 16, ++ 11, ++ &info.culledQuadCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00448, ++ 0x00474, ++ 16, ++ 1, ++ &info.totalQuadCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00448, ++ 0x00474, ++ 16, ++ 2, ++ &info.quadCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00448, ++ 0x00474, ++ 16, ++ 0, ++ &info.totalPixelCount)); ++#if gcdFRAME_DB_RESET ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00448, ++ 0x00474, ++ 16, ++ 15, ++ &reset)); ++#endif ++ ++ /* Read TX counters and reset them. */ ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0044C, ++ 0x00474, ++ 24, ++ 0, ++ &info.bilinearRequests)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0044C, ++ 0x00474, ++ 24, ++ 1, ++ &info.trilinearRequests)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0044C, ++ 0x00474, ++ 24, ++ 8, ++ &info.txHitCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0044C, ++ 0x00474, ++ 24, ++ 9, ++ &info.txMissCount)); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0044C, ++ 0x00474, ++ 24, ++ 6, ++ &info.txBytes8)); ++#if gcdFRAME_DB_RESET ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x0044C, ++ 0x00474, ++ 24, ++ 15, ++ &reset)); ++#endif ++ ++ /* Read clock control register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ &clock)); ++ ++ /* Walk through all avaiable pixel pipes. */ ++ for (i = 0; i < Hardware->identity.pixelPipes; ++i) ++ { ++ /* Select proper pipe. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))))); ++ ++ /* Read cycle registers. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00078, ++ &info.cycles[i])); ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0007C, ++ &info.idleCycles[i])); ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00438, ++ &info.mcCycles[i])); ++ ++ /* Read bandwidth registers. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0005C, ++ &info.readRequests[i])); ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00040, ++ &info.readBytes8[i])); ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00050, ++ &info.writeRequests[i])); ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00044, ++ &info.writeBytes8[i])); ++ ++ /* Read PE counters. */ ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00454, ++ 0x00470, ++ 16, ++ 0, ++ &info.colorKilled[i])); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00454, ++ 0x00470, ++ 16, ++ 2, ++ &info.colorDrawn[i])); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00454, ++ 0x00470, ++ 16, ++ 1, ++ &info.depthKilled[i])); ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00454, ++ 0x00470, ++ 16, ++ 3, ++ &info.depthDrawn[i])); ++ } ++ ++ /* Zero out remaning reserved counters. */ ++ for (; i < 8; ++i) ++ { ++ info.readBytes8[i] = 0; ++ info.writeBytes8[i] = 0; ++ info.cycles[i] = 0; ++ info.idleCycles[i] = 0; ++ info.mcCycles[i] = 0; ++ info.readRequests[i] = 0; ++ info.writeRequests[i] = 0; ++ info.colorKilled[i] = 0; ++ info.colorDrawn[i] = 0; ++ info.depthKilled[i] = 0; ++ info.depthDrawn[i] = 0; ++ } ++ ++ /* Reset clock control register. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00000, ++ clock)); ++ ++ /* Reset cycle and bandwidth counters. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0003C, ++ 1)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0003C, ++ 0)); ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00078, ++ 0)); ++ ++#if gcdFRAME_DB_RESET ++ /* Reset PE counters. */ ++ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( ++ Hardware, ++ 0x00454, ++ 0x00470, ++ 16, ++ 15, ++ &reset)); ++#endif ++ ++ /* Copy to user. */ ++ gcmkONERROR(gckOS_CopyToUserData(Hardware->os, ++ &info, ++ FrameInfo, ++ gcmSIZEOF(info))); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if gcdDVFS ++#define READ_FROM_EATER1 0 ++ ++gceSTATUS ++gckHARDWARE_QueryLoad( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32 * Load ++ ) ++{ ++ gctUINT32 debug1; ++ gceSTATUS status; ++ gcmkHEADER_ARG("Hardware=0x%X", Hardware); ++ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Load != gcvNULL); ++ ++ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE); ++ ++ if (Hardware->chipPowerState == gcvPOWER_ON) ++ { ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00110, ++ Load)); ++#if READ_FROM_EATER1 ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00134, ++ Load)); ++#endif ++ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00114, ++ &debug1)); ++ ++ /* Patch result of 0x110 with result of 0x114. */ ++ if ((debug1 & 0xFF) == 1) ++ { ++ *Load &= ~0xFF; ++ *Load |= 1; ++ } ++ ++ if (((debug1 & 0xFF00) >> 8) == 1) ++ { ++ *Load &= ~(0xFF << 8); ++ *Load |= 1 << 8; ++ } ++ ++ if (((debug1 & 0xFF0000) >> 16) == 1) ++ { ++ *Load &= ~(0xFF << 16); ++ *Load |= 1 << 16; ++ } ++ ++ if (((debug1 & 0xFF000000) >> 24) == 1) ++ { ++ *Load &= ~(0xFF << 24); ++ *Load |= 1 << 24; ++ } ++ } ++ else ++ { ++ status = gcvSTATUS_INVALID_REQUEST; ++ } ++ ++OnError: ++ ++ gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex); ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_SetDVFSPeroid( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32 Frequency ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 period; ++ gctUINT32 eater; ++ ++#if READ_FROM_EATER1 ++ gctUINT32 period1; ++ gctUINT32 eater1; ++#endif ++ ++ gcmkHEADER_ARG("Hardware=0x%X Frequency=%d", Hardware, Frequency); ++ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ period = 0; ++ ++ while((64 << period) < (gcdDVFS_ANAYLSE_WINDOW * Frequency * 1000) ) ++ { ++ period++; ++ } ++ ++#if READ_FROM_EATER1 ++ /* ++ * Peroid = F * 1000 * 1000 / (60 * 16 * 1024); ++ */ ++ period1 = Frequency * 6250 / 6114; ++#endif ++ ++ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE); ++ ++ if (Hardware->chipPowerState == gcvPOWER_ON) ++ { ++ /* Get current configure. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ &eater)); ++ ++ /* Change peroid. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ ((((gctUINT32) (eater)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) | (((gctUINT32) ((gctUINT32) (period) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))))); ++ ++#if READ_FROM_EATER1 ++ /* Config eater1. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00130, ++ &eater1)); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x00130, ++ ((((gctUINT32) (eater1)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:16) - (0 ? 31:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16))) | (((gctUINT32) ((gctUINT32) (period1) & ((gctUINT32) ((((1 ? 31:16) - (0 ? 31:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16))))); ++#endif ++ } ++ else ++ { ++ status = gcvSTATUS_INVALID_REQUEST; ++ } ++ ++OnError: ++ gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex); ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckHARDWARE_InitDVFS( ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 data; ++ ++ gcmkHEADER_ARG("Hardware=0x%X", Hardware); ++ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ &data)); ++ ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1))))))) << (0 ? 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1))))))) << (0 ? 18:18))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23))); ++ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22))); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "DVFS Configure=0x%X", ++ data); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, ++ Hardware->core, ++ 0x0010C, ++ data)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckHARDWARE_PrepareFunctions ++** ++** Generate command buffer snippets which will be used by gckHARDWARE, by which ++** gckHARDWARE can manipulate GPU by FE command without using gckCOMMAND to avoid ++** race condition and deadlock. ++** ++** Notice: ++** 1. Each snippet can only be executed when GPU is idle. ++** 2. Execution is triggered by AHB (0x658) ++** 3. Each snippet followed by END so software can sync with GPU by checking GPU ++** idle ++** 4. It is transparent to gckCOMMAND command buffer. ++** ++** Existing Snippets: ++** 1. MMU Configure ++** For new MMU, after GPU is reset, FE execute this command sequence to enble MMU. ++*/ ++gceSTATUS ++gckHARDWARE_PrepareFunctions( ++ gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gckOS os; ++ gctUINT32 offset = 0; ++ gctUINT32 mmuBytes; ++ gctUINT32 endBytes; ++ gctUINT8_PTR logical; ++ ++ gcmkHEADER_ARG("%x", Hardware); ++ ++ os = Hardware->os; ++ ++ gcmkVERIFY_OK(gckOS_GetPageSize(os, &Hardware->functionBytes)); ++ ++ /* Allocate a command buffer. */ ++ gcmkONERROR(gckOS_AllocateNonPagedMemory( ++ os, ++ gcvFALSE, ++ &Hardware->functionBytes, ++ &Hardware->functionPhysical, ++ &Hardware->functionLogical ++ )); ++ ++ gcmkONERROR(gckOS_GetPhysicalAddress( ++ os, ++ Hardware->functionLogical, ++ &Hardware->functionAddress ++ )); ++ ++ if (Hardware->mmuVersion > 0) ++ { ++ /* MMU configure command sequence. */ ++ logical = (gctUINT8_PTR)Hardware->functionLogical + offset; ++ ++ Hardware->functions[gcvHARDWARE_FUNCTION_MMU].address ++ = Hardware->functionAddress + offset; ++ ++ gcmkONERROR(gckHARDWARE_SetMMUStates( ++ Hardware, ++ Hardware->kernel->mmu->mtlbLogical, ++ gcvMMU_MODE_4K, ++ (gctUINT8_PTR)Hardware->kernel->mmu->mtlbLogical + gcdMMU_MTLB_SIZE, ++ logical, ++ &mmuBytes ++ )); ++ ++ offset += mmuBytes; ++ ++ logical = (gctUINT8_PTR)Hardware->functionLogical + offset; ++ ++ gcmkONERROR(gckHARDWARE_End( ++ Hardware, ++ gcvNULL, ++ &endBytes ++ )); ++ ++ gcmkONERROR(gckHARDWARE_End( ++ Hardware, ++ logical, ++ &endBytes ++ )); ++ ++ offset += endBytes; ++ ++ Hardware->functions[gcvHARDWARE_FUNCTION_MMU].bytes = mmuBytes + endBytes; ++ } ++ ++ gcmkASSERT(offset < Hardware->functionBytes); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h +--- linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h 2016-06-19 22:11:55.129151555 +0200 +@@ -0,0 +1,160 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_hardware_h_ ++#define __gc_hal_kernel_hardware_h_ ++ ++#if gcdENABLE_VG ++#include "gc_hal_kernel_hardware_vg.h" ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef enum { ++ gcvHARDWARE_FUNCTION_MMU, ++ gcvHARDWARE_FUNCTION_FLUSH, ++ ++ gcvHARDWARE_FUNCTION_NUM, ++} ++gceHARDWARE_FUNCTION; ++ ++ ++typedef struct _gcsHARWARE_FUNCTION ++{ ++ /* Entry of the function. */ ++ gctUINT32 address; ++ ++ /* Bytes of the function. */ ++ gctUINT32 bytes; ++} ++gcsHARDWARE_FUNCTION; ++ ++/* gckHARDWARE object. */ ++struct _gckHARDWARE ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gctKERNEL object. */ ++ gckKERNEL kernel; ++ ++ /* Pointer to gctOS object. */ ++ gckOS os; ++ ++ /* Core */ ++ gceCORE core; ++ ++ /* Chip characteristics. */ ++ gcsHAL_QUERY_CHIP_IDENTITY identity; ++ gctBOOL allowFastClear; ++ gctBOOL allowCompression; ++ gctUINT32 powerBaseAddress; ++ gctBOOL extraEventStates; ++ ++ /* Big endian */ ++ gctBOOL bigEndian; ++ ++ /* Chip status */ ++ gctPOINTER powerMutex; ++ gctUINT32 powerProcess; ++ gctUINT32 powerThread; ++ gceCHIPPOWERSTATE chipPowerState; ++ gctUINT32 lastWaitLink; ++ gctUINT32 lastEnd; ++ gctBOOL clockState; ++ gctBOOL powerState; ++ gctPOINTER globalSemaphore; ++ ++ gctISRMANAGERFUNC startIsr; ++ gctISRMANAGERFUNC stopIsr; ++ gctPOINTER isrContext; ++ ++ gctUINT32 mmuVersion; ++ ++ /* Whether use new MMU. It is meaningless ++ ** for old MMU since old MMU is always enabled. ++ */ ++ gctBOOL enableMMU; ++ ++ /* Type */ ++ gceHARDWARE_TYPE type; ++ ++#if gcdPOWEROFF_TIMEOUT ++ gctUINT32 powerOffTime; ++ gctUINT32 powerOffTimeout; ++ gctPOINTER powerOffTimer; ++#endif ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ gctUINT32 powerOnFscaleVal; ++#endif ++ gctPOINTER pageTableDirty; ++ ++#if gcdLINK_QUEUE_SIZE ++ struct _gckLINKQUEUE linkQueue; ++#endif ++ ++ gctBOOL powerManagement; ++ gctBOOL powerManagementLock; ++ gctBOOL gpuProfiler; ++ ++ gctBOOL endAfterFlushMmuCache; ++ ++ gctUINT32 minFscaleValue; ++ ++ gctPOINTER pendingEvent; ++ ++ /* Function used by gckHARDWARE. */ ++ gctPHYS_ADDR functionPhysical; ++ gctPOINTER functionLogical; ++ gctUINT32 functionAddress; ++ gctSIZE_T functionBytes; ++ ++ gcsHARDWARE_FUNCTION functions[gcvHARDWARE_FUNCTION_NUM]; ++}; ++ ++gceSTATUS ++gckHARDWARE_GetBaseAddress( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32_PTR BaseAddress ++ ); ++ ++gceSTATUS ++gckHARDWARE_NeedBaseAddress( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 State, ++ OUT gctBOOL_PTR NeedBase ++ ); ++ ++gceSTATUS ++gckHARDWARE_GetFrameInfo( ++ IN gckHARDWARE Hardware, ++ OUT gcsHAL_FRAME_INFO * FrameInfo ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_kernel_hardware_h_ */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c +--- linux-3.14.72.orig/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c 2016-06-19 22:11:55.129151555 +0200 +@@ -0,0 +1,679 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal.h" ++#include "gc_hal_kernel.h" ++#include "gc_hal_kernel_context.h" ++ ++/* ++ * ----------------------- ++ * HARDWARE STATE RECORDER ++ * ----------------------- ++ * ++ * State mirror buffer is used to 'mirror' hardware states since hardware ++ * states can't be dumpped. It is a context buffer which stores 'global' ++ * context. ++ * ++ * For each commit, state recorder ++ * 1) Records context buffer (if there is) and command buffers in this commit. ++ * 2) Parse those buffers to estimate the state changed. ++ * 3) Stores result to a mirror buffer. ++ * ++ * == Commit 0 ==================================================================== ++ * ++ * Context Buffer 0 ++ * ++ * Command Buffer 0 ++ * ++ * Mirror Buffer 0 <- Context Buffer 0 + Command Buffer 0 ++ * ++ * == Commit 1 ==================================================================== ++ * ++ * Command Buffer 1 ++ * ++ * Mirror Buffer 1 <- Command buffer 1 + Mirror Buffer 0 ++ * ++ * == Commit 2 ==================================================================== ++ * ++ * Context Buffer 2 (optional) ++ * ++ * Command Buffer 2 ++ * ++ * Mirror Buffer 2 <- Command buffer 2 + Context Buffer 2 + Mirror Buffer 1 ++ * ++ * == Commit N ==================================================================== ++ * ++ * For Commit N, these buffers are needed to reproduce hardware's behavior in ++ * this commit. ++ * ++ * Mirror Buffer [N - 1] : State Mirror accumlated by past commits, ++ * which is used to restore hardware state. ++ * Context Buffer [N] : ++ * Command Buffer [N] : Command buffer executed by hardware in this commit. ++ * ++ * If sequence of states programming matters, hardware's behavior can't be reproduced, ++ * but the state values stored in mirror buffer are assuring. ++ */ ++ ++/* Queue size. */ ++#define gcdNUM_RECORDS 6 ++ ++typedef struct _gcsPARSER_HANDLER * gckPARSER_HANDLER; ++ ++typedef void ++(*HandlerFunction)( ++ IN gckPARSER_HANDLER Handler, ++ IN gctUINT32 Addr, ++ IN gctUINT32 Data ++ ); ++ ++typedef struct _gcsPARSER_HANDLER ++{ ++ gctUINT32 type; ++ gctUINT32 cmd; ++ gctPOINTER private; ++ HandlerFunction function; ++} ++gcsPARSER_HANDLER; ++ ++typedef struct _gcsPARSER * gckPARSER; ++typedef struct _gcsPARSER ++{ ++ gctUINT8_PTR currentCmdBufferAddr; ++ ++ /* Current command. */ ++ gctUINT32 lo; ++ gctUINT32 hi; ++ ++ gctUINT8 cmdOpcode; ++ gctUINT16 cmdAddr; ++ gctUINT32 cmdSize; ++ gctUINT32 cmdRectCount; ++ gctUINT8 skip; ++ gctUINT32 skipCount; ++ ++ gctBOOL allow; ++ ++ /* Callback used by parser to handle a command. */ ++ gckPARSER_HANDLER commandHandler; ++} ++gcsPARSER; ++ ++typedef struct _gcsMIRROR ++{ ++ gctUINT32_PTR logical[gcdNUM_RECORDS]; ++ gctUINT32 bytes; ++ gcsSTATE_MAP_PTR map; ++ gctUINT32 stateCount; ++} ++gcsMIRROR; ++ ++typedef struct _gcsDELTA ++{ ++ gctUINT64 commitStamp; ++ gctUINT32_PTR command; ++ gctUINT32 commandBytes; ++ gctUINT32_PTR context; ++ gctUINT32 contextBytes; ++} ++gcsDELTA; ++ ++typedef struct _gcsRECORDER ++{ ++ gckOS os; ++ gcsMIRROR mirror; ++ gcsDELTA deltas[gcdNUM_RECORDS]; ++ ++ /* Index of current record. */ ++ gctUINT index; ++ ++ /* Number of records. */ ++ gctUINT num; ++ ++ /* Plugin used by gckPARSER. */ ++ gcsPARSER_HANDLER recorderHandler; ++ gckPARSER parser; ++} ++gcsRECORDER; ++ ++ ++/******************************************************************************\ ++***************************** Command Buffer Parser **************************** ++\******************************************************************************/ ++ ++/* ++** Command buffer parser checks command buffer in FE's view to make sure there ++** is no format error. ++** ++** Parser provide a callback mechnisam, so plug-in can be added to implement ++** other functions. ++*/ ++ ++static void ++_HandleLoadState( ++ IN OUT gckPARSER Parser ++ ) ++{ ++ gctUINT i; ++ gctUINT32_PTR data = (gctUINT32_PTR)Parser->currentCmdBufferAddr; ++ gctUINT32 cmdAddr = Parser->cmdAddr; ++ ++ if (Parser->commandHandler == gcvNULL ++ || Parser->commandHandler->cmd != 0x01 ++ ) ++ { ++ /* No handler for this command. */ ++ return; ++ } ++ ++ for (i = 0; i < Parser->cmdSize; i++) ++ { ++ Parser->commandHandler->function(Parser->commandHandler, cmdAddr, *data); ++ ++ /* Advance to next state. */ ++ cmdAddr++; ++ data++; ++ } ++} ++ ++static void ++_GetCommand( ++ IN OUT gckPARSER Parser ++ ) ++{ ++ gctUINT32 * buffer = (gctUINT32 *)Parser->currentCmdBufferAddr; ++ ++ gctUINT16 cmdRectCount; ++ gctUINT16 cmdDataCount; ++ ++ Parser->hi = buffer[0]; ++ Parser->lo = buffer[1]; ++ ++ Parser->cmdOpcode = (((((gctUINT32) (Parser->hi)) >> (0 ? 31:27)) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) ); ++ Parser->cmdRectCount = 1; ++ ++ switch (Parser->cmdOpcode) ++ { ++ case 0x01: ++ /* Extract count. */ ++ Parser->cmdSize = (((((gctUINT32) (Parser->hi)) >> (0 ? 25:16)) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1)))))) ); ++ if (Parser->cmdSize == 0) ++ { ++ /* 0 means 1024. */ ++ Parser->cmdSize = 1024; ++ } ++ Parser->skip = (Parser->cmdSize & 0x1) ? 0 : 1; ++ ++ /* Extract address. */ ++ Parser->cmdAddr = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) ); ++ ++ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 4; ++ Parser->skipCount = Parser->cmdSize + Parser->skip; ++ break; ++ ++ case 0x05: ++ Parser->cmdSize = 4; ++ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2); ++ break; ++ ++ case 0x06: ++ Parser->cmdSize = 5; ++ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2); ++ break; ++ ++ case 0x0C: ++ Parser->cmdSize = 3; ++ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2); ++ break; ++ ++ case 0x09: ++ Parser->cmdSize = 2; ++ Parser->cmdAddr = 0x0F16; ++ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2); ++ break; ++ ++ case 0x04: ++ Parser->cmdSize = 1; ++ Parser->cmdAddr = 0x0F06; ++ ++ cmdRectCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:8)) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1)))))) ); ++ cmdDataCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 26:16)) & ((gctUINT32) ((((1 ? 26:16) - (0 ? 26:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:16) - (0 ? 26:16) + 1)))))) ); ++ ++ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2) ++ + cmdRectCount * 2 ++ + gcmALIGN(cmdDataCount, 2); ++ ++ Parser->cmdRectCount = cmdRectCount; ++ break; ++ ++ case 0x03: ++ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8; ++ Parser->skipCount = 0; ++ break; ++ ++ case 0x02: ++ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8; ++ Parser->skipCount = 0; ++ break; ++ ++ default: ++ /* Unknown command is a risk. */ ++ Parser->allow = gcvFALSE; ++ break; ++ } ++} ++ ++static void ++_ParseCommand( ++ IN OUT gckPARSER Parser ++ ) ++{ ++ switch(Parser->cmdOpcode) ++ { ++ case 0x01: ++ _HandleLoadState(Parser); ++ break; ++ case 0x05: ++ case 0x06: ++ case 0x0C: ++ break; ++ case 0x04: ++ break; ++ default: ++ break; ++ } ++ ++ /* Advance to next command. */ ++ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr ++ + (Parser->skipCount << 2); ++} ++ ++gceSTATUS ++gckPARSER_Parse( ++ IN gckPARSER Parser, ++ IN gctUINT8_PTR Buffer, ++ IN gctUINT32 Bytes ++ ) ++{ ++ gckPARSER parser = Parser; ++ gctUINT8_PTR end = (gctUINT8_PTR)Buffer + Bytes; ++ ++ /* Initialize parser. */ ++ parser->currentCmdBufferAddr = (gctUINT8_PTR)Buffer; ++ parser->skip = 0; ++ parser->allow = gcvTRUE; ++ ++ /* Go through command buffer until reaching the end ++ ** or meeting an error. */ ++ do ++ { ++ _GetCommand(parser); ++ ++ _ParseCommand(parser); ++ } ++ while ((parser->currentCmdBufferAddr < end) && (parser->allow == gcvTRUE)); ++ ++ if (parser->allow == gcvFALSE) ++ { ++ /* Error detected. */ ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckPARSER_RegisterCommandHandler ++** ++** Register a command handler which will be called when parser get a command. ++** ++*/ ++gceSTATUS ++gckPARSER_RegisterCommandHandler( ++ IN gckPARSER Parser, ++ IN gckPARSER_HANDLER Handler ++ ) ++{ ++ Parser->commandHandler = Handler; ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckPARSER_Construct( ++ IN gckOS Os, ++ IN gckPARSER_HANDLER Handler, ++ OUT gckPARSER * Parser ++ ) ++{ ++ gceSTATUS status; ++ gckPARSER pointer; ++ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsPARSER), (gctPOINTER *)&pointer)); ++ ++ /* Put it here temp, should have a more general plug-in mechnisam. */ ++ pointer->commandHandler = Handler; ++ ++ *Parser = pointer; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++void ++gckPARSER_Destroy( ++ IN gckOS Os, ++ IN gckPARSER Parser ++ ) ++{ ++ gcmkOS_SAFE_FREE(Os, Parser); ++} ++ ++/******************************************************************************\ ++**************************** Hardware States Recorder ************************** ++\******************************************************************************/ ++ ++static void ++_RecodeState( ++ IN gckPARSER_HANDLER Handler, ++ IN gctUINT32 Addr, ++ IN gctUINT32 Data ++ ) ++{ ++ gcmkVERIFY_OK(gckRECORDER_UpdateMirror(Handler->private, Addr, Data)); ++} ++ ++static gctUINT ++_Previous( ++ IN gctUINT Index ++ ) ++{ ++ if (Index == 0) ++ { ++ return gcdNUM_RECORDS - 1; ++ } ++ ++ return Index - 1; ++} ++ ++static gctUINT ++_Next( ++ IN gctUINT Index ++ ) ++{ ++ return (Index + 1) % gcdNUM_RECORDS; ++} ++ ++gceSTATUS ++gckRECORDER_Construct( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ OUT gckRECORDER * Recorder ++ ) ++{ ++ gceSTATUS status; ++ gckCONTEXT context = gcvNULL; ++ gckRECORDER recorder = gcvNULL; ++ gctUINT32 mapSize; ++ gctUINT i; ++ gctBOOL virtualCommandBuffer = Hardware->kernel->virtualCommandBuffer; ++ ++ /* TODO: We only need context buffer and state map, it should be able to get without construct a ++ ** new context. ++ ** Now it is leaked, since we can't free it when command buffer is gone. ++ */ ++ ++ /* MMU is not ready now. */ ++ Hardware->kernel->virtualCommandBuffer = gcvFALSE; ++ ++ gcmkONERROR(gckCONTEXT_Construct(Os, Hardware, 0, &context)); ++ ++ /* Restore. */ ++ Hardware->kernel->virtualCommandBuffer = virtualCommandBuffer; ++ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsRECORDER), (gctPOINTER *)&recorder)); ++ ++ gckOS_ZeroMemory(recorder, gcmSIZEOF(gcsRECORDER)); ++ ++ /* Copy state map. */ ++ recorder->mirror.stateCount = context->stateCount; ++ ++ mapSize = context->stateCount * gcmSIZEOF(gcsSTATE_MAP); ++ ++ gcmkONERROR(gckOS_Allocate(Os, mapSize, (gctPOINTER *)&recorder->mirror.map)); ++ ++ gckOS_MemCopy(recorder->mirror.map, context->map, mapSize); ++ ++ /* Copy context buffer. */ ++ recorder->mirror.bytes = context->totalSize; ++ ++ for (i = 0; i < gcdNUM_RECORDS; i++) ++ { ++ gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->mirror.logical[i])); ++ gckOS_MemCopy(recorder->mirror.logical[i], context->buffer->logical, context->totalSize); ++ } ++ ++ for (i = 0; i < gcdNUM_RECORDS; i++) ++ { ++ /* TODO : Optimize size. */ ++ gcmkONERROR(gckOS_Allocate(Os, gcdCMD_BUFFER_SIZE, (gctPOINTER *)&recorder->deltas[i].command)); ++ gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->deltas[i].context)); ++ } ++ ++ recorder->index = 0; ++ recorder->num = 0; ++ ++ /* Initialize Parser plugin. */ ++ recorder->recorderHandler.cmd = 0x01; ++ recorder->recorderHandler.private = recorder; ++ recorder->recorderHandler.function = _RecodeState; ++ ++ gcmkONERROR(gckPARSER_Construct(Os, &recorder->recorderHandler, &recorder->parser)); ++ ++ recorder->os = Os; ++ ++ *Recorder = recorder; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (recorder) ++ { ++ gckRECORDER_Destory(Os, recorder); ++ } ++ ++ return status; ++} ++ ++gceSTATUS ++gckRECORDER_Destory( ++ IN gckOS Os, ++ IN gckRECORDER Recorder ++ ) ++{ ++ gctUINT i; ++ ++ if (Recorder->mirror.map) ++ { ++ gcmkOS_SAFE_FREE(Os, Recorder->mirror.map); ++ } ++ ++ for (i = 0; i < gcdNUM_RECORDS; i++) ++ { ++ if (Recorder->mirror.logical[i]) ++ { ++ gcmkOS_SAFE_FREE(Os, Recorder->mirror.logical[i]); ++ } ++ } ++ ++ for (i = 0; i < gcdNUM_RECORDS; i++) ++ { ++ if (Recorder->deltas[i].command) ++ { ++ gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].command); ++ } ++ ++ if (Recorder->deltas[i].context) ++ { ++ gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].context); ++ } ++ } ++ ++ if (Recorder->parser) ++ { ++ gckPARSER_Destroy(Os, Recorder->parser); ++ } ++ ++ gcmkOS_SAFE_FREE(Os, Recorder); ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckRECORDER_UpdateMirror( ++ IN gckRECORDER Recorder, ++ IN gctUINT32 State, ++ IN gctUINT32 Data ++ ) ++{ ++ gctUINT32 index; ++ gcsSTATE_MAP_PTR map = Recorder->mirror.map; ++ gctUINT32_PTR buffer = Recorder->mirror.logical[Recorder->index]; ++ ++ if (State >= Recorder->mirror.stateCount) ++ { ++ /* Ignore them just like HW does. */ ++ return gcvSTATUS_OK; ++ } ++ ++ index = map[State].index; ++ ++ if (index) ++ { ++ buffer[index] = Data; ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++void ++gckRECORDER_AdvanceIndex( ++ IN gckRECORDER Recorder, ++ IN gctUINT64 CommitStamp ++ ) ++{ ++ /* Get next record. */ ++ gctUINT next = (Recorder->index + 1) % gcdNUM_RECORDS; ++ ++ /* Record stamp of this commit. */ ++ Recorder->deltas[Recorder->index].commitStamp = CommitStamp; ++ ++ /* Mirror of next record is mirror of this record and delta in next record. */ ++ gckOS_MemCopy(Recorder->mirror.logical[next], ++ Recorder->mirror.logical[Recorder->index], Recorder->mirror.bytes); ++ ++ /* Advance to next record. */ ++ Recorder->index = next; ++ ++ Recorder->num = gcmMIN(Recorder->num + 1, gcdNUM_RECORDS - 1); ++ ++ ++ /* Reset delta. */ ++ Recorder->deltas[Recorder->index].commandBytes = 0; ++ Recorder->deltas[Recorder->index].contextBytes = 0; ++} ++ ++void ++gckRECORDER_Record( ++ IN gckRECORDER Recorder, ++ IN gctUINT8_PTR CommandBuffer, ++ IN gctUINT32 CommandBytes, ++ IN gctUINT8_PTR ContextBuffer, ++ IN gctUINT32 ContextBytes ++ ) ++{ ++ gcsDELTA * delta = &Recorder->deltas[Recorder->index]; ++ ++ if (CommandBytes != 0xFFFFFFFF) ++ { ++ gckPARSER_Parse(Recorder->parser, CommandBuffer, CommandBytes); ++ gckOS_MemCopy(delta->command, CommandBuffer, CommandBytes); ++ delta->commandBytes = CommandBytes; ++ } ++ ++ if (ContextBytes != 0xFFFFFFFF) ++ { ++ gckPARSER_Parse(Recorder->parser, ContextBuffer, ContextBytes); ++ gckOS_MemCopy(delta->context, ContextBuffer, ContextBytes); ++ delta->contextBytes = ContextBytes; ++ } ++} ++ ++void ++gckRECORDER_Dump( ++ IN gckRECORDER Recorder ++ ) ++{ ++ gctUINT last = Recorder->index; ++ gctUINT previous; ++ gctUINT i; ++ gcsMIRROR *mirror = &Recorder->mirror; ++ gcsDELTA *delta; ++ gckOS os = Recorder->os; ++ ++ for (i = 0; i < Recorder->num; i++) ++ { ++ last = _Previous(last); ++ } ++ ++ for (i = 0; i < Recorder->num; i++) ++ { ++ delta = &Recorder->deltas[last]; ++ ++ /* Dump record */ ++ gcmkPRINT("#[commit %llu]", delta->commitStamp); ++ ++ if (delta->commitStamp) ++ { ++ previous = _Previous(last); ++ ++ gcmkPRINT("#[mirror]"); ++ gckOS_DumpBuffer(os, mirror->logical[previous], mirror->bytes, gceDUMP_BUFFER_CONTEXT, gcvTRUE); ++ gcmkPRINT("@[kernel.execute]"); ++ } ++ ++ if (delta->contextBytes) ++ { ++ gckOS_DumpBuffer(os, delta->context, delta->contextBytes, gceDUMP_BUFFER_CONTEXT, gcvTRUE); ++ gcmkPRINT("@[kernel.execute]"); ++ } ++ ++ gckOS_DumpBuffer(os, delta->command, delta->commandBytes, gceDUMP_BUFFER_USER, gcvTRUE); ++ gcmkPRINT("@[kernel.execute]"); ++ ++ last = _Next(last); ++ } ++} ++ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c +--- linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c 2016-06-19 22:11:55.129151555 +0200 +@@ -0,0 +1,932 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal.h" ++#include "gc_hal_kernel.h" ++ ++#if gcdENABLE_VG ++ ++#include "gc_hal_kernel_hardware_command_vg.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_COMMAND ++ ++/******************************************************************************\ ++****************************** gckVGCOMMAND API code ***************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_InitializeInfo ++** ++** Initialize architecture dependent command buffer information. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to the Command object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckVGCOMMAND_InitializeInfo( ++ IN gckVGCOMMAND Command ++ ) ++{ ++ gceSTATUS status; ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ do ++ { ++ /* Reset interrupts. */ ++ Command->info.feBufferInt = -1; ++ Command->info.tsOverflowInt = -1; ++ ++ /* Set command buffer attributes. */ ++ Command->info.addressAlignment = 64; ++ Command->info.commandAlignment = 8; ++ ++ /* Determine command alignment address mask. */ ++ Command->info.addressMask = ((((gctUINT32) (Command->info.addressAlignment - 1)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) ((gctUINT32) (0 ) & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))); ++ ++ /* Query the number of bytes needed by the STATE command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_StateCommand( ++ Command, 0x0, gcvNULL, (gctUINT32)~0, 0, ++ &Command->info.stateCommandSize ++ )); ++ ++ /* Query the number of bytes needed by the RESTART command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_RestartCommand( ++ Command, gcvNULL, (gctUINT32)~0, 0, ++ &Command->info.restartCommandSize ++ )); ++ ++ /* Query the number of bytes needed by the FETCH command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_FetchCommand( ++ Command, gcvNULL, (gctUINT32)~0, 0, ++ &Command->info.fetchCommandSize ++ )); ++ ++ /* Query the number of bytes needed by the CALL command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_CallCommand( ++ Command, gcvNULL, (gctUINT32)~0, 0, ++ &Command->info.callCommandSize ++ )); ++ ++ /* Query the number of bytes needed by the RETURN command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_ReturnCommand( ++ Command, gcvNULL, ++ &Command->info.returnCommandSize ++ )); ++ ++ /* Query the number of bytes needed by the EVENT command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_EventCommand( ++ Command, gcvNULL, gcvBLOCK_PIXEL, -1, ++ &Command->info.eventCommandSize ++ )); ++ ++ /* Query the number of bytes needed by the END command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_EndCommand( ++ Command, gcvNULL, -1, ++ &Command->info.endCommandSize ++ )); ++ ++ /* Determine the tail reserve size. */ ++ Command->info.staticTailSize = gcmMAX( ++ Command->info.fetchCommandSize, ++ gcmMAX( ++ Command->info.returnCommandSize, ++ Command->info.endCommandSize ++ ) ++ ); ++ ++ /* Determine the maximum tail size. */ ++ Command->info.dynamicTailSize ++ = Command->info.staticTailSize ++ + Command->info.eventCommandSize * gcvBLOCK_COUNT; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_StateCommand ++** ++** Append a STATE command at the specified location in the command buffer. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to an gckVGCOMMAND object. ++** ++** gctUINT32 Pipe ++** Harwdare destination pipe. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command buffer to append ++** STATE command at or gcvNULL to query the size of the command. ++** ++** gctUINT32 Address ++** Starting register address of the state buffer. ++** If 'Logical' is gcvNULL, this argument is ignored. ++** ++** gctUINT32 Count ++** Number of states in state buffer. ++** If 'Logical' is gcvNULL, this argument is ignored. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the STATE command. ++** If 'Logical' is gcvNULL, the value from this argument is ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the STATE command. If 'Bytes' is gcvNULL, nothing is returned. ++*/ ++gceSTATUS ++gckVGCOMMAND_StateCommand( ++ IN gckVGCOMMAND Command, ++ IN gctUINT32 Pipe, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Address, ++ IN gctUINT32 Count, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Pipe=0x%x Logical=0x%x Address=0x%x Count=0x%x Bytes = 0x%x", ++ Command, Pipe, Logical, Address, Count, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->fe20) ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append STATE. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:0) - (0 ? 11:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ? 11:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 11:0) - (0 ? 11:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ? 11:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:16) - (0 ? 27:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:16) - (0 ? 27:16) + 1))))))) << (0 ? 27:16))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ? 27:16) - (0 ? 27:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:16) - (0 ? 27:16) + 1))))))) << (0 ? 27:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 13:12) - (0 ? 13:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12))) | (((gctUINT32) ((gctUINT32) (Pipe) & ((gctUINT32) ((((1 ? 13:12) - (0 ? 13:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12))); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the STATE command. */ ++ *Bytes = 4 * (Count + 1); ++ } ++ } ++ else ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append LOAD_STATE. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the STATE command. */ ++ *Bytes = 4 * (Count + 1); ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_RestartCommand ++** ++** Form a RESTART command at the specified location in the command buffer. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to an gckVGCOMMAND object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command buffer to append ++** RESTART command at or gcvNULL to query the size of the command. ++** ++** gctUINT32 FetchAddress ++** The address of another command buffer to be executed by this RESTART ++** command. If 'Logical' is gcvNULL, this argument is ignored. ++** ++** gctUINT FetchCount ++** The number of 64-bit data quantities in another command buffer to ++** be executed by this RESTART command. If 'Logical' is gcvNULL, this ++** argument is ignored. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the RESTART command. ++** If 'Logical' is gcvNULL, the value from this argument is ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the RESTART command. If 'Bytes' is gcvNULL, nothing is returned. ++*/ ++gceSTATUS ++gckVGCOMMAND_RestartCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT FetchCount, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x", ++ Command, Logical, FetchAddress, FetchCount, Bytes); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->fe20) ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ gctUINT32 beginEndMark; ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Determine Begin/End flag. */ ++ beginEndMark = (FetchCount > 0) ++ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))) ++ : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))); ++ ++ /* Append RESTART. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x9 & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:0) - (0 ? 20:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ? 20:0) - (0 ? 20:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0))) ++ | beginEndMark; ++ ++ buffer[1] ++ = FetchAddress; ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the RESTART command. */ ++ *Bytes = 8; ++ } ++ } ++ else ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_FetchCommand ++** ++** Form a FETCH command at the specified location in the command buffer. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to an gckVGCOMMAND object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command buffer to append ++** FETCH command at or gcvNULL to query the size of the command. ++** ++** gctUINT32 FetchAddress ++** The address of another command buffer to be executed by this FETCH ++** command. If 'Logical' is gcvNULL, this argument is ignored. ++** ++** gctUINT FetchCount ++** The number of 64-bit data quantities in another command buffer to ++** be executed by this FETCH command. If 'Logical' is gcvNULL, this ++** argument is ignored. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the FETCH command. ++** If 'Logical' is gcvNULL, the value from this argument is ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the FETCH command. If 'Bytes' is gcvNULL, nothing is returned. ++*/ ++gceSTATUS ++gckVGCOMMAND_FetchCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT FetchCount, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x", ++ Command, Logical, FetchAddress, FetchCount, Bytes); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->fe20) ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append FETCH. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x5 & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:0) - (0 ? 20:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ? 20:0) - (0 ? 20:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0))); ++ ++ buffer[1] ++ = gcmkFIXADDRESS(FetchAddress); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the FETCH command. */ ++ *Bytes = 8; ++ } ++ } ++ else ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append LINK. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); ++ ++ buffer[1] ++ = gcmkFIXADDRESS(FetchAddress); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the LINK command. */ ++ *Bytes = 8; ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_CallCommand ++** ++** Append a CALL command at the specified location in the command buffer. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to an gckVGCOMMAND object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command buffer to append ++** CALL command at or gcvNULL to query the size of the command. ++** ++** gctUINT32 FetchAddress ++** The address of another command buffer to be executed by this CALL ++** command. If 'Logical' is gcvNULL, this argument is ignored. ++** ++** gctUINT FetchCount ++** The number of 64-bit data quantities in another command buffer to ++** be executed by this CALL command. If 'Logical' is gcvNULL, this ++** argument is ignored. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the CALL command. ++** If 'Logical' is gcvNULL, the value from this argument is ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the CALL command. If 'Bytes' is gcvNULL, nothing is returned. ++*/ ++gceSTATUS ++gckVGCOMMAND_CallCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT FetchCount, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x", ++ Command, Logical, FetchAddress, FetchCount, Bytes); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->fe20) ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append CALL. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x6 & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:0) - (0 ? 20:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ? 20:0) - (0 ? 20:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0))); ++ ++ buffer[1] ++ = gcmkFIXADDRESS(FetchAddress); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the CALL command. */ ++ *Bytes = 8; ++ } ++ } ++ else ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_ReturnCommand ++** ++** Append a RETURN command at the specified location in the command buffer. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to an gckVGCOMMAND object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command buffer to append ++** RETURN command at or gcvNULL to query the size of the command. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the RETURN command. ++** If 'Logical' is gcvNULL, the value from this argument is ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the RETURN command. If 'Bytes' is gcvNULL, nothing is returned. ++*/ ++gceSTATUS ++gckVGCOMMAND_ReturnCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Logical=0x%x Bytes = 0x%x", ++ Command, Logical, Bytes); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->fe20) ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append RETURN. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x7 & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the RETURN command. */ ++ *Bytes = 8; ++ } ++ } ++ else ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_EventCommand ++** ++** Form an EVENT command at the specified location in the command buffer. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to the Command object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command buffer to append ++** EVENT command at or gcvNULL to query the size of the command. ++** ++** gctINT32 InterruptId ++** The ID of the interrupt to generate. ++** If 'Logical' is gcvNULL, this argument is ignored. ++** ++** gceBLOCK Block ++** Block that will generate the interrupt. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the EVENT command. ++** If 'Logical' is gcvNULL, the value from this argument is ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the END command. If 'Bytes' is gcvNULL, nothing is returned. ++*/ ++gceSTATUS ++gckVGCOMMAND_EventCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gceBLOCK Block, ++ IN gctINT32 InterruptId, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Logical=0x%x Block=0x%x InterruptId=0x%x Bytes = 0x%x", ++ Command, Logical, Block, InterruptId, Bytes); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->fe20) ++ { ++ typedef struct _gcsEVENTSTATES ++ { ++ /* Chips before VG21 use these values. */ ++ gctUINT eventFromFE; ++ gctUINT eventFromPE; ++ ++ /* VG21 chips and later use SOURCE field. */ ++ gctUINT eventSource; ++ } ++ gcsEVENTSTATES; ++ ++ static gcsEVENTSTATES states[] = ++ { ++ /* gcvBLOCK_COMMAND */ ++ { ++ (gctUINT)~0, ++ (gctUINT)~0, ++ (gctUINT)~0 ++ }, ++ ++ /* gcvBLOCK_TESSELLATOR */ ++ { ++ 0x0, ++ 0x1, ++ 0x10 ++ }, ++ ++ /* gcvBLOCK_TESSELLATOR2 */ ++ { ++ 0x0, ++ 0x1, ++ 0x12 ++ }, ++ ++ /* gcvBLOCK_TESSELLATOR3 */ ++ { ++ 0x0, ++ 0x1, ++ 0x14 ++ }, ++ ++ /* gcvBLOCK_RASTER */ ++ { ++ 0x0, ++ 0x1, ++ 0x07, ++ }, ++ ++ /* gcvBLOCK_VG */ ++ { ++ 0x0, ++ 0x1, ++ 0x0F ++ }, ++ ++ /* gcvBLOCK_VG2 */ ++ { ++ 0x0, ++ 0x1, ++ 0x11 ++ }, ++ ++ /* gcvBLOCK_VG3 */ ++ { ++ 0x0, ++ 0x1, ++ 0x13 ++ }, ++ ++ /* gcvBLOCK_PIXEL */ ++ { ++ 0x0, ++ 0x1, ++ 0x07 ++ }, ++ }; ++ ++ /* Verify block ID. */ ++ gcmkVERIFY_ARGUMENT(gcmIS_VALID_INDEX(Block, states)); ++ ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Verify the event ID. */ ++ gcmkVERIFY_ARGUMENT(InterruptId >= 0); ++ gcmkVERIFY_ARGUMENT(InterruptId <= ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1)))))); ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append EVENT. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:0) - (0 ? 11:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ? 11:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 11:0) - (0 ? 11:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ? 11:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:16) - (0 ? 27:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:16) - (0 ? 27:16) + 1))))))) << (0 ? 27:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 27:16) - (0 ? 27:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:16) - (0 ? 27:16) + 1))))))) << (0 ? 27:16))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 13:12) - (0 ? 13:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 13:12) - (0 ? 13:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12))); ++ ++ /* Determine chip version. */ ++ if (Command->vg21) ++ { ++ /* Get the event source for the block. */ ++ gctUINT eventSource = states[Block].eventSource; ++ ++ /* Supported? */ ++ if (eventSource == ~0) ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ buffer[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) ((gctUINT32) (eventSource) & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); ++ } ++ else ++ { ++ /* Get the event source for the block. */ ++ gctUINT eventFromFE = states[Block].eventFromFE; ++ gctUINT eventFromPE = states[Block].eventFromPE; ++ ++ /* Supported? */ ++ if (eventFromFE == ~0) ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ buffer[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (eventFromFE) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) ((gctUINT32) (eventFromPE) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++ } ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Make sure the events are directly supported for the block. */ ++ if (states[Block].eventSource == ~0) ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ /* Return number of bytes required by the END command. */ ++ *Bytes = 8; ++ } ++ } ++ else ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Verify the event ID. */ ++ gcmkVERIFY_ARGUMENT(InterruptId >= 0); ++ gcmkVERIFY_ARGUMENT(InterruptId <= ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1)))))); ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append EVENT. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ /* Determine event source. */ ++ if (Block == gcvBLOCK_COMMAND) ++ { ++ buffer[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); ++ } ++ else ++ { ++ buffer[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++ } ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the EVENT and END commands. */ ++ *Bytes = 8; ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGCOMMAND_EndCommand ++** ++** Form an END command at the specified location in the command buffer. ++** ++** INPUT: ++** ++** gckVGCOMMAND Command ++** Pointer to the Command object. ++** ++** gctPOINTER Logical ++** Pointer to the current location inside the command buffer to append ++** END command at or gcvNULL to query the size of the command. ++** ++** gctINT32 InterruptId ++** The ID of the interrupt to generate. ++** If 'Logical' is gcvNULL, this argument will be ignored. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes available for the END command. ++** If 'Logical' is gcvNULL, the value from this argument is ignored. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that will receive the number of bytes required ++** for the END command. If 'Bytes' is gcvNULL, nothing is returned. ++*/ ++gceSTATUS ++gckVGCOMMAND_EndCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctINT32 InterruptId, ++ IN OUT gctUINT32 * Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Logical=0x%x InterruptId=0x%x Bytes = 0x%x", ++ Command, Logical, InterruptId, Bytes); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->fe20) ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR buffer; ++ ++ /* Verify the event ID. */ ++ gcmkVERIFY_ARGUMENT(InterruptId >= 0); ++ ++ /* Cast the buffer pointer. */ ++ buffer = (gctUINT32_PTR) Logical; ++ ++ /* Append END. */ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the END command. */ ++ *Bytes = 8; ++ } ++ } ++ else ++ { ++ if (Logical != gcvNULL) ++ { ++ gctUINT32_PTR memory; ++ ++ /* Verify the event ID. */ ++ gcmkVERIFY_ARGUMENT(InterruptId >= 0); ++ ++ /* Cast the buffer pointer. */ ++ memory = (gctUINT32_PTR) Logical; ++ ++ /* Append EVENT. */ ++ memory[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ memory[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); ++ ++ /* Append END. */ ++ memory[2] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return number of bytes required by the EVENT and END commands. */ ++ *Bytes = 16; ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++#endif /* gcdENABLE_VG */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h +--- linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h 2016-06-19 22:11:55.129151555 +0200 +@@ -0,0 +1,319 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_hardware_command_vg_h_ ++#define __gc_hal_kernel_hardware_command_vg_h_ ++ ++/******************************************************************************\ ++******************* Task and Interrupt Management Structures. ****************** ++\******************************************************************************/ ++ ++/* Task storage header. */ ++typedef struct _gcsTASK_STORAGE * gcsTASK_STORAGE_PTR; ++typedef struct _gcsTASK_STORAGE ++{ ++ /* Next allocated storage buffer. */ ++ gcsTASK_STORAGE_PTR next; ++} ++gcsTASK_STORAGE; ++ ++/* Task container header. */ ++typedef struct _gcsTASK_CONTAINER * gcsTASK_CONTAINER_PTR; ++typedef struct _gcsTASK_CONTAINER ++{ ++ /* The number of tasks left to be processed in the container. */ ++ gctINT referenceCount; ++ ++ /* Size of the buffer. */ ++ gctUINT size; ++ ++ /* Link to the previous and the next allocated containers. */ ++ gcsTASK_CONTAINER_PTR allocPrev; ++ gcsTASK_CONTAINER_PTR allocNext; ++ ++ /* Link to the previous and the next containers in the free list. */ ++ gcsTASK_CONTAINER_PTR freePrev; ++ gcsTASK_CONTAINER_PTR freeNext; ++} ++gcsTASK_CONTAINER; ++ ++/* Kernel space task master table entry. */ ++typedef struct _gcsBLOCK_TASK_ENTRY * gcsBLOCK_TASK_ENTRY_PTR; ++typedef struct _gcsBLOCK_TASK_ENTRY ++{ ++ /* Pointer to the current task container for the block. */ ++ gcsTASK_CONTAINER_PTR container; ++ ++ /* Pointer to the current task data within the container. */ ++ gcsTASK_HEADER_PTR task; ++ ++ /* Pointer to the last link task within the container. */ ++ gcsTASK_LINK_PTR link; ++ ++ /* Number of interrupts allocated for this block. */ ++ gctUINT interruptCount; ++ ++ /* The index of the current interrupt. */ ++ gctUINT interruptIndex; ++ ++ /* Interrupt semaphore. */ ++ gctSEMAPHORE interruptSemaphore; ++ ++ /* Interrupt value array. */ ++ gctINT32 interruptArray[32]; ++} ++gcsBLOCK_TASK_ENTRY; ++ ++ ++/******************************************************************************\ ++********************* Command Queue Management Structures. ********************* ++\******************************************************************************/ ++ ++/* Command queue kernel element pointer. */ ++typedef struct _gcsKERNEL_CMDQUEUE * gcsKERNEL_CMDQUEUE_PTR; ++ ++/* Command queue object handler function type. */ ++typedef gceSTATUS (* gctOBJECT_HANDLER) ( ++ gckVGKERNEL Kernel, ++ gcsKERNEL_CMDQUEUE_PTR Entry ++ ); ++ ++/* Command queue kernel element. */ ++typedef struct _gcsKERNEL_CMDQUEUE ++{ ++ /* The number of buffers in the queue. */ ++ gcsCMDBUFFER_PTR commandBuffer; ++ ++ /* Pointer to the object handler function. */ ++ gctOBJECT_HANDLER handler; ++} ++gcsKERNEL_CMDQUEUE; ++ ++/* Command queue header. */ ++typedef struct _gcsKERNEL_QUEUE_HEADER * gcsKERNEL_QUEUE_HEADER_PTR; ++typedef struct _gcsKERNEL_QUEUE_HEADER ++{ ++ /* The size of the buffer in bytes. */ ++ gctUINT size; ++ ++ /* The number of pending entries to be processed. */ ++ volatile gctUINT pending; ++ ++ /* The current command queue entry. */ ++ gcsKERNEL_CMDQUEUE_PTR currentEntry; ++ ++ /* Next buffer. */ ++ gcsKERNEL_QUEUE_HEADER_PTR next; ++} ++gcsKERNEL_QUEUE_HEADER; ++ ++ ++/******************************************************************************\ ++******************************* gckVGCOMMAND Object ******************************* ++\******************************************************************************/ ++ ++/* gckVGCOMMAND object. */ ++struct _gckVGCOMMAND ++{ ++ /*************************************************************************** ++ ** Object data and pointers. ++ */ ++ ++ gcsOBJECT object; ++ gckVGKERNEL kernel; ++ gckOS os; ++ gckVGHARDWARE hardware; ++ ++ /* Features. */ ++ gctBOOL fe20; ++ gctBOOL vg20; ++ gctBOOL vg21; ++ ++ ++ /*************************************************************************** ++ ** Enable command queue dumping. ++ */ ++ ++ gctBOOL enableDumping; ++ ++ ++ /*************************************************************************** ++ ** Bus Error interrupt. ++ */ ++ ++ gctINT32 busErrorInt; ++ ++ ++ /*************************************************************************** ++ ** Command buffer information. ++ */ ++ ++ gcsCOMMAND_BUFFER_INFO info; ++ ++ ++ /*************************************************************************** ++ ** Synchronization objects. ++ */ ++ ++ gctPOINTER queueMutex; ++ gctPOINTER taskMutex; ++ gctPOINTER commitMutex; ++ ++ ++ /*************************************************************************** ++ ** Task management. ++ */ ++ ++ /* The head of the storage buffer linked list. */ ++ gcsTASK_STORAGE_PTR taskStorage; ++ ++ /* Allocation size. */ ++ gctUINT taskStorageGranularity; ++ gctUINT taskStorageUsable; ++ ++ /* The free container list. */ ++ gcsTASK_CONTAINER_PTR taskFreeHead; ++ gcsTASK_CONTAINER_PTR taskFreeTail; ++ ++ /* Task table */ ++ gcsBLOCK_TASK_ENTRY taskTable[gcvBLOCK_COUNT]; ++ ++ ++ /*************************************************************************** ++ ** Command queue. ++ */ ++ ++ /* Pointer to the allocated queue memory. */ ++ gcsKERNEL_QUEUE_HEADER_PTR queue; ++ ++ /* Pointer to the current available queue from which new queue entries ++ will be allocated. */ ++ gcsKERNEL_QUEUE_HEADER_PTR queueHead; ++ ++ /* If different from queueHead, points to the command queue which is ++ currently being executed by the hardware. */ ++ gcsKERNEL_QUEUE_HEADER_PTR queueTail; ++ ++ /* Points to the queue to merge the tail with when the tail is processed. */ ++ gcsKERNEL_QUEUE_HEADER_PTR mergeQueue; ++ ++ /* Queue overflow counter. */ ++ gctUINT queueOverflow; ++ ++ ++ /*************************************************************************** ++ ** Context. ++ */ ++ ++ /* Context counter used for unique ID. */ ++ gctUINT64 contextCounter; ++ ++ /* Current context ID. */ ++ gctUINT64 currentContext; ++ ++ /* Command queue power semaphore. */ ++ gctPOINTER powerSemaphore; ++ gctINT32 powerStallInt; ++ gcsCMDBUFFER_PTR powerStallBuffer; ++ gctSIGNAL powerStallSignal; ++ ++}; ++ ++/******************************************************************************\ ++************************ gckVGCOMMAND Object Internal API. *********************** ++\******************************************************************************/ ++ ++/* Initialize architecture dependent command buffer information. */ ++gceSTATUS ++gckVGCOMMAND_InitializeInfo( ++ IN gckVGCOMMAND Command ++ ); ++ ++/* Form a STATE command at the specified location in the command buffer. */ ++gceSTATUS ++gckVGCOMMAND_StateCommand( ++ IN gckVGCOMMAND Command, ++ IN gctUINT32 Pipe, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Address, ++ IN gctUINT32 Count, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Form a RESTART command at the specified location in the command buffer. */ ++gceSTATUS ++gckVGCOMMAND_RestartCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT FetchCount, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Form a FETCH command at the specified location in the command buffer. */ ++gceSTATUS ++gckVGCOMMAND_FetchCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT FetchCount, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Form a CALL command at the specified location in the command buffer. */ ++gceSTATUS ++gckVGCOMMAND_CallCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT FetchCount, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Form a RETURN command at the specified location in the command buffer. */ ++gceSTATUS ++gckVGCOMMAND_ReturnCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Form an EVENT command at the specified location in the command buffer. */ ++gceSTATUS ++gckVGCOMMAND_EventCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gceBLOCK Block, ++ IN gctINT32 InterruptId, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Form an END command at the specified location in the command buffer. */ ++gceSTATUS ++gckVGCOMMAND_EndCommand( ++ IN gckVGCOMMAND Command, ++ IN gctPOINTER Logical, ++ IN gctINT32 InterruptId, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++#endif /* __gc_hal_kernel_hardware_command_h_ */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c +--- linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c 2016-06-19 22:11:55.133151292 +0200 +@@ -0,0 +1,2119 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal.h" ++#include "gc_hal_kernel.h" ++#include "gc_hal_kernel_hardware_command_vg.h" ++ ++#if gcdENABLE_VG ++ ++#define _GC_OBJ_ZONE gcvZONE_HARDWARE ++ ++typedef enum ++{ ++ gcvPOWER_FLAG_INITIALIZE = 1 << 0, ++ gcvPOWER_FLAG_STALL = 1 << 1, ++ gcvPOWER_FLAG_STOP = 1 << 2, ++ gcvPOWER_FLAG_START = 1 << 3, ++ gcvPOWER_FLAG_RELEASE = 1 << 4, ++ gcvPOWER_FLAG_DELAY = 1 << 5, ++ gcvPOWER_FLAG_SAVE = 1 << 6, ++ gcvPOWER_FLAG_ACQUIRE = 1 << 7, ++ gcvPOWER_FLAG_POWER_OFF = 1 << 8, ++ gcvPOWER_FLAG_CLOCK_OFF = 1 << 9, ++ gcvPOWER_FLAG_CLOCK_ON = 1 << 10, ++ gcvPOWER_FLAG_NOP = 1 << 11, ++} ++gcePOWER_FLAGS; ++ ++/******************************************************************************\ ++********************************* Support Code ********************************* ++\******************************************************************************/ ++static gceSTATUS ++_ResetGPU( ++ IN gckOS Os ++ ) ++{ ++ gctUINT32 control, idle; ++ gceSTATUS status; ++ ++ /* Read register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00000, ++ &control)); ++ ++ for (;;) ++ { ++ /* Disable clock gating. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00104, ++ 0x00000000)); ++ ++ /* Wait for clock being stable. */ ++ gcmkONERROR(gckOS_Delay(Os, 1)); ++ ++ /* Isolate the GPU. */ ++ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00000, ++ control)); ++ ++ /* Set soft reset. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00000, ++ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); ++ ++ /* Wait for reset. */ ++ gcmkONERROR(gckOS_Delay(Os, 1)); ++ ++ /* Reset soft reset bit. */ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00000, ++ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); ++ ++ /* Reset GPU isolation. */ ++ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); ++ ++ gcmkONERROR(gckOS_WriteRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00000, ++ control)); ++ ++ /* Read idle register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00004, ++ &idle)); ++ ++ if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0) ++ { ++ continue; ++ } ++ ++ /* Read reset register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx(Os, ++ gcvCORE_VG, ++ 0x00000, ++ &control)); ++ ++ if (((((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ) == 0) ++ || ((((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) ) == 0) ++ ) ++ { ++ continue; ++ } ++ ++ /* GPU is idle. */ ++ break; ++ } ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ /* Return the error. */ ++ return status; ++} ++ ++ ++static gceSTATUS ++_IdentifyHardware( ++ IN gckOS Os, ++ OUT gceCHIPMODEL * ChipModel, ++ OUT gctUINT32 * ChipRevision, ++ OUT gctUINT32 * ChipFeatures, ++ OUT gctUINT32 * ChipMinorFeatures, ++ OUT gctUINT32 * ChipMinorFeatures2 ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 chipIdentity; ++ ++ do ++ { ++ /* Read chip identity register. */ ++ gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG, 0x00018, &chipIdentity)); ++ ++ /* Special case for older graphic cores. */ ++ if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))))) ++ { ++ *ChipModel = gcv500; ++ *ChipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) ); ++ } ++ ++ else ++ { ++ /* Read chip identity register. */ ++ gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG, ++ 0x00020, ++ (gctUINT32 *) ChipModel)); ++ ++ /* Read CHIP_REV register. */ ++ gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG, ++ 0x00024, ++ ChipRevision)); ++ } ++ ++ /* Read chip feature register. */ ++ gcmkERR_BREAK(gckOS_ReadRegisterEx( ++ Os, gcvCORE_VG, 0x0001C, ChipFeatures ++ )); ++ ++ /* Read chip minor feature register. */ ++ gcmkERR_BREAK(gckOS_ReadRegisterEx( ++ Os, gcvCORE_VG, 0x00034, ChipMinorFeatures ++ )); ++ ++ /* Read chip minor feature register #2. */ ++ gcmkERR_BREAK(gckOS_ReadRegisterEx( ++ Os, gcvCORE_VG, 0x00074, ChipMinorFeatures2 ++ )); ++ ++ gcmkTRACE( ++ gcvLEVEL_VERBOSE, ++ "ChipModel=0x%08X\n" ++ "ChipRevision=0x%08X\n" ++ "ChipFeatures=0x%08X\n" ++ "ChipMinorFeatures=0x%08X\n" ++ "ChipMinorFeatures2=0x%08X\n", ++ *ChipModel, ++ *ChipRevision, ++ *ChipFeatures, ++ *ChipMinorFeatures, ++ *ChipMinorFeatures2 ++ ); ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Return the status. */ ++ return status; ++} ++ ++#if gcdPOWEROFF_TIMEOUT ++void ++_VGPowerTimerFunction( ++ gctPOINTER Data ++ ) ++{ ++ gckVGHARDWARE hardware = (gckVGHARDWARE)Data; ++ gcmkVERIFY_OK( ++ gckVGHARDWARE_SetPowerManagementState(hardware, gcvPOWER_OFF_TIMEOUT)); ++} ++#endif ++ ++/******************************************************************************\ ++****************************** gckVGHARDWARE API code ***************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_Construct ++** ++** Construct a new gckVGHARDWARE object. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an initialized gckOS object. ++** ++** OUTPUT: ++** ++** gckVGHARDWARE * Hardware ++** Pointer to a variable that will hold the pointer to the gckVGHARDWARE ++** object. ++*/ ++gceSTATUS ++gckVGHARDWARE_Construct( ++ IN gckOS Os, ++ OUT gckVGHARDWARE * Hardware ++ ) ++{ ++ gckVGHARDWARE hardware = gcvNULL; ++ gceSTATUS status; ++ gceCHIPMODEL chipModel; ++ gctUINT32 chipRevision; ++ gctUINT32 chipFeatures; ++ gctUINT32 chipMinorFeatures; ++ gctUINT32 chipMinorFeatures2; ++ ++ gcmkHEADER_ARG("Os=0x%x Hardware=0x%x ", Os, Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Hardware != gcvNULL); ++ ++ do ++ { ++ gcmkERR_BREAK(gckOS_SetGPUPower(Os, gcvCORE_VG, gcvTRUE, gcvTRUE)); ++ ++ status = _ResetGPU(Os); ++ ++ if (status != gcvSTATUS_OK) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "_ResetGPU failed: status=%d\n", status); ++ } ++ ++ /* Identify the hardware. */ ++ gcmkERR_BREAK(_IdentifyHardware(Os, ++ &chipModel, &chipRevision, ++ &chipFeatures, &chipMinorFeatures, &chipMinorFeatures2 ++ )); ++ ++ /* Allocate the gckVGHARDWARE object. */ ++ gcmkERR_BREAK(gckOS_Allocate(Os, ++ gcmSIZEOF(struct _gckVGHARDWARE), (gctPOINTER *) &hardware ++ )); ++ ++ /* Initialize the gckVGHARDWARE object. */ ++ hardware->object.type = gcvOBJ_HARDWARE; ++ hardware->os = Os; ++ ++ /* Set chip identity. */ ++ hardware->chipModel = chipModel; ++ hardware->chipRevision = chipRevision; ++ hardware->chipFeatures = chipFeatures; ++ hardware->chipMinorFeatures = chipMinorFeatures; ++ hardware->chipMinorFeatures2 = chipMinorFeatures2; ++ ++ hardware->powerMutex = gcvNULL; ++ hardware->chipPowerState = gcvPOWER_ON; ++ hardware->chipPowerStateGlobal = gcvPOWER_ON; ++ hardware->clockState = gcvTRUE; ++ hardware->powerState = gcvTRUE; ++ ++#if gcdPOWEROFF_TIMEOUT ++ hardware->powerOffTime = 0; ++ hardware->powerOffTimeout = gcdPOWEROFF_TIMEOUT; ++ ++ gcmkVERIFY_OK(gckOS_CreateTimer(Os, ++ _VGPowerTimerFunction, ++ (gctPOINTER)hardware, ++ &hardware->powerOffTimer)); ++#endif ++ ++ /* Determine whether FE 2.0 is present. */ ++ hardware->fe20 = ((((gctUINT32) (hardware->chipFeatures)) >> (0 ? 28:28) & ((gctUINT32) ((((1 ? 28:28) - (0 ? 28:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 28:28) - (0 ? 28:28) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 28:28) - (0 ? 28:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 28:28) - (0 ? 28:28) + 1))))))); ++ ++ /* Determine whether VG 2.0 is present. */ ++ hardware->vg20 = ((((gctUINT32) (hardware->chipMinorFeatures)) >> (0 ? 13:13) & ((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:13) - (0 ? 13:13) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:13) - (0 ? 13:13) + 1))))))); ++ ++ /* Determine whether VG 2.1 is present. */ ++ hardware->vg21 = ((((gctUINT32) (hardware->chipMinorFeatures)) >> (0 ? 18:18) & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 18:18) - (0 ? 18:18) + 1))))))); ++ ++ /* Set default event mask. */ ++ hardware->eventMask = 0xFFFFFFFF; ++ ++ gcmkERR_BREAK(gckOS_AtomConstruct(Os, &hardware->pageTableDirty)); ++ ++ /* Set fast clear to auto. */ ++ gcmkVERIFY_OK(gckVGHARDWARE_SetFastClear(hardware, -1)); ++ ++ gcmkERR_BREAK(gckOS_CreateMutex(Os, &hardware->powerMutex)); ++ ++ /* Enable power management by default. */ ++ hardware->powerManagement = gcvTRUE; ++ ++ /* Return pointer to the gckVGHARDWARE object. */ ++ *Hardware = hardware; ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++#if gcdPOWEROFF_TIMEOUT ++ if (hardware->powerOffTimer != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_StopTimer(Os, hardware->powerOffTimer)); ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Os, hardware->powerOffTimer)); ++ } ++#endif ++ ++ gcmkVERIFY_OK(gckOS_SetGPUPower(Os, gcvCORE_VG, gcvFALSE, gcvFALSE)); ++ ++ if (hardware != gcvNULL && hardware->pageTableDirty != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pageTableDirty)); ++ } ++ ++ if (hardware != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_Free(Os, hardware)); ++ } ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_Destroy ++** ++** Destroy an gckVGHARDWARE object. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to the gckVGHARDWARE object that needs to be destroyed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckVGHARDWARE_Destroy( ++ IN gckVGHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gcmkHEADER_ARG("Hardware=0x%x ", Hardware); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Mark the object as unknown. */ ++ Hardware->object.type = gcvOBJ_UNKNOWN; ++ ++ if (Hardware->powerMutex != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex( ++ Hardware->os, Hardware->powerMutex)); ++ } ++ ++#if gcdPOWEROFF_TIMEOUT ++ gcmkVERIFY_OK(gckOS_StopTimer(Hardware->os, Hardware->powerOffTimer)); ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Hardware->os, Hardware->powerOffTimer)); ++#endif ++ ++ if (Hardware->pageTableDirty != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pageTableDirty)); ++ } ++ ++ /* Free the object. */ ++ status = gckOS_Free(Hardware->os, Hardware); ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_QueryMemory ++** ++** Query the amount of memory available on the hardware. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to the gckVGHARDWARE object. ++** ++** OUTPUT: ++** ++** gctSIZE_T * InternalSize ++** Pointer to a variable that will hold the size of the internal video ++** memory in bytes. If 'InternalSize' is gcvNULL, no information of the ++** internal memory will be returned. ++** ++** gctUINT32 * InternalBaseAddress ++** Pointer to a variable that will hold the hardware's base address for ++** the internal video memory. This pointer cannot be gcvNULL if ++** 'InternalSize' is also non-gcvNULL. ++** ++** gctUINT32 * InternalAlignment ++** Pointer to a variable that will hold the hardware's base address for ++** the internal video memory. This pointer cannot be gcvNULL if ++** 'InternalSize' is also non-gcvNULL. ++** ++** gctSIZE_T * ExternalSize ++** Pointer to a variable that will hold the size of the external video ++** memory in bytes. If 'ExternalSize' is gcvNULL, no information of the ++** external memory will be returned. ++** ++** gctUINT32 * ExternalBaseAddress ++** Pointer to a variable that will hold the hardware's base address for ++** the external video memory. This pointer cannot be gcvNULL if ++** 'ExternalSize' is also non-gcvNULL. ++** ++** gctUINT32 * ExternalAlignment ++** Pointer to a variable that will hold the hardware's base address for ++** the external video memory. This pointer cannot be gcvNULL if ++** 'ExternalSize' is also non-gcvNULL. ++** ++** gctUINT32 * HorizontalTileSize ++** Number of horizontal pixels per tile. If 'HorizontalTileSize' is ++** gcvNULL, no horizontal pixel per tile will be returned. ++** ++** gctUINT32 * VerticalTileSize ++** Number of vertical pixels per tile. If 'VerticalTileSize' is ++** gcvNULL, no vertical pixel per tile will be returned. ++*/ ++gceSTATUS ++gckVGHARDWARE_QueryMemory( ++ IN gckVGHARDWARE Hardware, ++ OUT gctSIZE_T * InternalSize, ++ OUT gctUINT32 * InternalBaseAddress, ++ OUT gctUINT32 * InternalAlignment, ++ OUT gctSIZE_T * ExternalSize, ++ OUT gctUINT32 * ExternalBaseAddress, ++ OUT gctUINT32 * ExternalAlignment, ++ OUT gctUINT32 * HorizontalTileSize, ++ OUT gctUINT32 * VerticalTileSize ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x InternalSize=0x%x InternalBaseAddress=0x%x InternalAlignment=0x%x" ++ "ExternalSize=0x%x ExternalBaseAddress=0x%x ExternalAlignment=0x%x HorizontalTileSize=0x%x VerticalTileSize=0x%x", ++ Hardware, InternalSize, InternalBaseAddress, InternalAlignment, ++ ExternalSize, ExternalBaseAddress, ExternalAlignment, HorizontalTileSize, VerticalTileSize); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (InternalSize != gcvNULL) ++ { ++ /* No internal memory. */ ++ *InternalSize = 0; ++ } ++ ++ if (ExternalSize != gcvNULL) ++ { ++ /* No external memory. */ ++ *ExternalSize = 0; ++ } ++ ++ if (HorizontalTileSize != gcvNULL) ++ { ++ /* 4x4 tiles. */ ++ *HorizontalTileSize = 4; ++ } ++ ++ if (VerticalTileSize != gcvNULL) ++ { ++ /* 4x4 tiles. */ ++ *VerticalTileSize = 4; ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_QueryChipIdentity ++** ++** Query the identity of the hardware. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to the gckVGHARDWARE object. ++** ++** OUTPUT: ++** ++** gceCHIPMODEL * ChipModel ++** If 'ChipModel' is not gcvNULL, the variable it points to will ++** receive the model of the chip. ++** ++** gctUINT32 * ChipRevision ++** If 'ChipRevision' is not gcvNULL, the variable it points to will ++** receive the revision of the chip. ++** ++** gctUINT32 * ChipFeatures ++** If 'ChipFeatures' is not gcvNULL, the variable it points to will ++** receive the feature set of the chip. ++** ++** gctUINT32 * ChipMinorFeatures ++** If 'ChipMinorFeatures' is not gcvNULL, the variable it points to ++** will receive the minor feature set of the chip. ++** ++** gctUINT32 * ChipMinorFeatures2 ++** If 'ChipMinorFeatures2' is not gcvNULL, the variable it points to ++** will receive the minor feature set of the chip. ++** ++*/ ++gceSTATUS ++gckVGHARDWARE_QueryChipIdentity( ++ IN gckVGHARDWARE Hardware, ++ OUT gceCHIPMODEL * ChipModel, ++ OUT gctUINT32 * ChipRevision, ++ OUT gctUINT32* ChipFeatures, ++ OUT gctUINT32* ChipMinorFeatures, ++ OUT gctUINT32* ChipMinorFeatures2 ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x ChipModel=0x%x ChipRevision=0x%x ChipFeatures = 0x%x ChipMinorFeatures = 0x%x ChipMinorFeatures2 = 0x%x", ++ Hardware, ChipModel, ChipRevision, ChipFeatures, ChipMinorFeatures, ChipMinorFeatures2); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Return chip model. */ ++ if (ChipModel != gcvNULL) ++ { ++ *ChipModel = Hardware->chipModel; ++ } ++ ++ /* Return revision number. */ ++ if (ChipRevision != gcvNULL) ++ { ++ *ChipRevision = Hardware->chipRevision; ++ } ++ ++ /* Return feature set. */ ++ if (ChipFeatures != gcvNULL) ++ { ++ gctUINT32 features = Hardware->chipFeatures; ++ ++ if ((((((gctUINT32) (features)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) ++ { ++ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (Hardware->allowFastClear) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); ++ } ++ ++ /* Mark 2D pipe as available for GC500.0 since it did not have this *\ ++ \* bit. */ ++ if ((Hardware->chipModel == gcv500) ++ && (Hardware->chipRevision == 0) ++ ) ++ { ++ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))); ++ } ++ ++ /* Mark 2D pipe as available for GC300 since it did not have this *\ ++ \* bit. */ ++ if (Hardware->chipModel == gcv300) ++ { ++ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))); ++ } ++ ++ *ChipFeatures = features; ++ } ++ ++ /* Return minor feature set. */ ++ if (ChipMinorFeatures != gcvNULL) ++ { ++ *ChipMinorFeatures = Hardware->chipMinorFeatures; ++ } ++ ++ /* Return minor feature set #2. */ ++ if (ChipMinorFeatures2 != gcvNULL) ++ { ++ *ChipMinorFeatures2 = Hardware->chipMinorFeatures2; ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_ConvertFormat ++** ++** Convert an API format to hardware parameters. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to the gckVGHARDWARE object. ++** ++** gceSURF_FORMAT Format ++** API format to convert. ++** ++** OUTPUT: ++** ++** gctUINT32 * BitsPerPixel ++** Pointer to a variable that will hold the number of bits per pixel. ++** ++** gctUINT32 * BytesPerTile ++** Pointer to a variable that will hold the number of bytes per tile. ++*/ ++gceSTATUS ++gckVGHARDWARE_ConvertFormat( ++ IN gckVGHARDWARE Hardware, ++ IN gceSURF_FORMAT Format, ++ OUT gctUINT32 * BitsPerPixel, ++ OUT gctUINT32 * BytesPerTile ++ ) ++{ ++ gctUINT32 bitsPerPixel; ++ gctUINT32 bytesPerTile; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Format=0x%x BitsPerPixel=0x%x BytesPerTile = 0x%x", ++ Hardware, Format, BitsPerPixel, BytesPerTile); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Dispatch on format. */ ++ switch (Format) ++ { ++ case gcvSURF_A1: ++ case gcvSURF_L1: ++ /* 1-bpp format. */ ++ bitsPerPixel = 1; ++ bytesPerTile = (1 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_A4: ++ /* 4-bpp format. */ ++ bitsPerPixel = 4; ++ bytesPerTile = (4 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_INDEX8: ++ case gcvSURF_A8: ++ case gcvSURF_L8: ++ /* 8-bpp format. */ ++ bitsPerPixel = 8; ++ bytesPerTile = (8 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_YV12: ++ /* 12-bpp planar YUV formats. */ ++ bitsPerPixel = 12; ++ bytesPerTile = (12 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_NV12: ++ /* 12-bpp planar YUV formats. */ ++ bitsPerPixel = 12; ++ bytesPerTile = (12 * 4 * 4) / 8; ++ break; ++ ++ /* 4444 variations. */ ++ case gcvSURF_X4R4G4B4: ++ case gcvSURF_A4R4G4B4: ++ case gcvSURF_R4G4B4X4: ++ case gcvSURF_R4G4B4A4: ++ case gcvSURF_B4G4R4X4: ++ case gcvSURF_B4G4R4A4: ++ case gcvSURF_X4B4G4R4: ++ case gcvSURF_A4B4G4R4: ++ ++ /* 1555 variations. */ ++ case gcvSURF_X1R5G5B5: ++ case gcvSURF_A1R5G5B5: ++ case gcvSURF_R5G5B5X1: ++ case gcvSURF_R5G5B5A1: ++ case gcvSURF_X1B5G5R5: ++ case gcvSURF_A1B5G5R5: ++ case gcvSURF_B5G5R5X1: ++ case gcvSURF_B5G5R5A1: ++ ++ /* 565 variations. */ ++ case gcvSURF_R5G6B5: ++ case gcvSURF_B5G6R5: ++ ++ case gcvSURF_A8L8: ++ case gcvSURF_YUY2: ++ case gcvSURF_UYVY: ++ case gcvSURF_D16: ++ /* 16-bpp format. */ ++ bitsPerPixel = 16; ++ bytesPerTile = (16 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_X8R8G8B8: ++ case gcvSURF_A8R8G8B8: ++ case gcvSURF_X8B8G8R8: ++ case gcvSURF_A8B8G8R8: ++ case gcvSURF_R8G8B8X8: ++ case gcvSURF_R8G8B8A8: ++ case gcvSURF_B8G8R8X8: ++ case gcvSURF_B8G8R8A8: ++ case gcvSURF_D32: ++ /* 32-bpp format. */ ++ bitsPerPixel = 32; ++ bytesPerTile = (32 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_D24S8: ++ /* 24-bpp format. */ ++ bitsPerPixel = 32; ++ bytesPerTile = (32 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_DXT1: ++ case gcvSURF_ETC1: ++ bitsPerPixel = 4; ++ bytesPerTile = (4 * 4 * 4) / 8; ++ break; ++ ++ case gcvSURF_DXT2: ++ case gcvSURF_DXT3: ++ case gcvSURF_DXT4: ++ case gcvSURF_DXT5: ++ bitsPerPixel = 8; ++ bytesPerTile = (8 * 4 * 4) / 8; ++ break; ++ ++ default: ++ /* Invalid format. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++ /* Set the result. */ ++ if (BitsPerPixel != gcvNULL) ++ { ++ * BitsPerPixel = bitsPerPixel; ++ } ++ ++ if (BytesPerTile != gcvNULL) ++ { ++ * BytesPerTile = bytesPerTile; ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_SplitMemory ++** ++** Split a hardware specific memory address into a pool and offset. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to the gckVGHARDWARE object. ++** ++** gctUINT32 Address ++** Address in hardware specific format. ++** ++** OUTPUT: ++** ++** gcePOOL * Pool ++** Pointer to a variable that will hold the pool type for the address. ++** ++** gctUINT32 * Offset ++** Pointer to a variable that will hold the offset for the address. ++*/ ++gceSTATUS ++gckVGHARDWARE_SplitMemory( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Address, ++ OUT gcePOOL * Pool, ++ OUT gctUINT32 * Offset ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Pool=0x%x Offset = 0x%x", ++ Hardware, Address, Pool, Offset); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Pool != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Offset != gcvNULL); ++ ++ /* Dispatch on memory type. */ ++ switch ((((((gctUINT32) (Address)) >> (0 ? 1:0)) & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1)))))) )) ++ { ++ case 0x0: ++ /* System memory. */ ++ *Pool = gcvPOOL_SYSTEM; ++ break; ++ ++ case 0x2: ++ /* Virtual memory. */ ++ *Pool = gcvPOOL_VIRTUAL; ++ break; ++ ++ default: ++ /* Invalid memory type. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++ /* Return offset of address. */ ++ *Offset = ((((gctUINT32) (Address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_Execute ++** ++** Kickstart the hardware's command processor with an initialized command ++** buffer. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to the gckVGHARDWARE object. ++** ++** gctUINT32 Address ++** Address of the command buffer. ++** ++** gctSIZE_T Count ++** Number of command-sized data units to be executed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckVGHARDWARE_Execute( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Address, ++ IN gctUINT32 Count ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Count=0x%x", ++ Hardware, Address, Count); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ do ++ { ++ /* Enable all events. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx( ++ Hardware->os, ++ gcvCORE_VG, ++ 0x00014, ++ Hardware->eventMask ++ )); ++ ++ if (Hardware->fe20) ++ { ++ /* Write address register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx( ++ Hardware->os, ++ gcvCORE_VG, ++ 0x00500, ++ gcmkFIXADDRESS(Address) ++ )); ++ ++ /* Write control register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx( ++ Hardware->os, ++ gcvCORE_VG, ++ 0x00504, ++ Count ++ )); ++ } ++ else ++ { ++ /* Write address register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx( ++ Hardware->os, ++ gcvCORE_VG, ++ 0x00654, ++ gcmkFIXADDRESS(Address) ++ )); ++ ++ /* Write control register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx( ++ Hardware->os, ++ gcvCORE_VG, ++ 0x00658, ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | ++ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ )); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_AlignToTile ++** ++** Align the specified width and height to tile boundaries. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to an gckVGHARDWARE object. ++** ++** gceSURF_TYPE Type ++** Type of alignment. ++** ++** gctUINT32 * Width ++** Pointer to the width to be aligned. If 'Width' is gcvNULL, no width ++** will be aligned. ++** ++** gctUINT32 * Height ++** Pointer to the height to be aligned. If 'Height' is gcvNULL, no height ++** will be aligned. ++** ++** OUTPUT: ++** ++** gctUINT32 * Width ++** Pointer to a variable that will receive the aligned width. ++** ++** gctUINT32 * Height ++** Pointer to a variable that will receive the aligned height. ++*/ ++gceSTATUS ++gckVGHARDWARE_AlignToTile( ++ IN gckVGHARDWARE Hardware, ++ IN gceSURF_TYPE Type, ++ IN OUT gctUINT32 * Width, ++ IN OUT gctUINT32 * Height ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x Type=0x%x Width=0x%x Height=0x%x", ++ Hardware, Type, Width, Height); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (Width != gcvNULL) ++ { ++ /* Align the width. */ ++ *Width = gcmALIGN(*Width, (Type == gcvSURF_TEXTURE) ? 4 : 16); ++ } ++ ++ if (Height != gcvNULL) ++ { ++ /* Special case for VG images. */ ++ if ((*Height == 0) && (Type == gcvSURF_IMAGE)) ++ { ++ *Height = 4; ++ } ++ else ++ { ++ /* Align the height. */ ++ *Height = gcmALIGN(*Height, 4); ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_ConvertLogical ++** ++** Convert a logical system address into a hardware specific address. ++** ++** INPUT: ++** ++** gckVGHARDWARE Hardware ++** Pointer to an gckVGHARDWARE object. ++** ++** gctPOINTER Logical ++** Logical address to convert. ++** ++** gctBOOL InUserSpace ++** gcvTRUE if the memory in user space. ++** ++** gctUINT32* Address ++** Return hardware specific address. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckVGHARDWARE_ConvertLogical( ++ IN gckVGHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctBOOL InUserSpace, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gctUINT32 address; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x InUserSpace=%d Address=0x%x", ++ Hardware, Logical, InUserSpace, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ do ++ { ++ /* Convert logical address into a physical address. */ ++ if (InUserSpace) ++ { ++ gcmkERR_BREAK(gckOS_UserLogicalToPhysical( ++ Hardware->os, Logical, &address ++ )); ++ } ++ else ++ { ++ gcmkERR_BREAK(gckOS_GetPhysicalAddress( ++ Hardware->os, Logical, &address ++ )); ++ } ++ ++ /* Return hardware specific address. */ ++ *Address = ((((gctUINT32) (address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))); ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_QuerySystemMemory ++** ++** Query the command buffer alignment and number of reserved bytes. ++** ++** INPUT: ++** ++** gckVGHARDWARE Harwdare ++** Pointer to an gckVGHARDWARE object. ++** ++** OUTPUT: ++** ++** gctSIZE_T * SystemSize ++** Pointer to a variable that receives the maximum size of the system ++** memory. ++** ++** gctUINT32 * SystemBaseAddress ++** Poinetr to a variable that receives the base address for system ++** memory. ++*/ ++gceSTATUS gckVGHARDWARE_QuerySystemMemory( ++ IN gckVGHARDWARE Hardware, ++ OUT gctSIZE_T * SystemSize, ++ OUT gctUINT32 * SystemBaseAddress ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x SystemSize=0x%x SystemBaseAddress=0x%x", ++ Hardware, SystemSize, SystemBaseAddress); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ if (SystemSize != gcvNULL) ++ { ++ /* Maximum system memory can be 2GB. */ ++ *SystemSize = (gctSIZE_T)(1 << 31); ++ } ++ ++ if (SystemBaseAddress != gcvNULL) ++ { ++ /* Set system memory base address. */ ++ *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))); ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_SetMMU ++** ++** Set the page table base address. ++** ++** INPUT: ++** ++** gckVGHARDWARE Harwdare ++** Pointer to an gckVGHARDWARE object. ++** ++** gctPOINTER Logical ++** Logical address of the page table. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS gckVGHARDWARE_SetMMU( ++ IN gckVGHARDWARE Hardware, ++ IN gctPOINTER Logical ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 address = 0; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", ++ Hardware, Logical); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ do ++ { ++ /* Convert the logical address into an hardware address. */ ++ gcmkERR_BREAK(gckVGHARDWARE_ConvertLogical(Hardware, Logical, ++ gcvFALSE, &address)); ++ ++ /* Write the AQMemoryFePageTable register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x00400, ++ gcmkFIXADDRESS(address))); ++ ++ /* Write the AQMemoryTxPageTable register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x00404, ++ gcmkFIXADDRESS(address))); ++ ++ /* Write the AQMemoryPePageTable register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x00408, ++ gcmkFIXADDRESS(address))); ++ ++ /* Write the AQMemoryPezPageTable register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x0040C, ++ gcmkFIXADDRESS(address))); ++ ++ /* Write the AQMemoryRaPageTable register. */ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x00410, ++ gcmkFIXADDRESS(address))); ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_FlushMMU ++** ++** Flush the page table. ++** ++** INPUT: ++** ++** gckVGHARDWARE Harwdare ++** Pointer to an gckVGHARDWARE object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS gckVGHARDWARE_FlushMMU( ++ IN gckVGHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gckVGCOMMAND command; ++ ++ gcmkHEADER_ARG("Hardware=0x%x ", Hardware); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ do ++ { ++ gcsCMDBUFFER_PTR commandBuffer; ++ gctUINT32_PTR buffer; ++ ++ /* Create a shortcut to the command buffer object. */ ++ command = Hardware->kernel->command; ++ ++ /* Allocate command buffer space. */ ++ gcmkERR_BREAK(gckVGCOMMAND_Allocate( ++ command, 8, &commandBuffer, (gctPOINTER *) &buffer ++ )); ++ ++ buffer[0] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); ++ ++ buffer[1] ++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) ++ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); ++ } ++ while(gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_BuildVirtualAddress ++** ++** Build a virtual address. ++** ++** INPUT: ++** ++** gckVGHARDWARE Harwdare ++** Pointer to an gckVGHARDWARE object. ++** ++** gctUINT32 Index ++** Index into page table. ++** ++** gctUINT32 Offset ++** Offset into page. ++** ++** OUTPUT: ++** ++** gctUINT32 * Address ++** Pointer to a variable receiving te hardware address. ++*/ ++gceSTATUS gckVGHARDWARE_BuildVirtualAddress( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Index, ++ IN gctUINT32 Offset, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gctUINT32 address; ++ ++ gcmkHEADER_ARG("Hardware=0x%x Index=0x%x Offset=0x%x Address=0x%x", ++ Hardware, Index, Offset, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ /* Build virtual address. */ ++ address = (Index << 12) | Offset; ++ ++ /* Set virtual type. */ ++ address = ((((gctUINT32) (address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))); ++ ++ /* Set the result. */ ++ *Address = address; ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckVGHARDWARE_GetIdle( ++ IN gckVGHARDWARE Hardware, ++ OUT gctUINT32 * Data ++ ) ++{ ++ gceSTATUS status; ++ gcmkHEADER_ARG("Hardware=0x%x Data=0x%x", Hardware, Data); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Data != gcvNULL); ++ ++ /* Read register and return. */ ++ status = gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, 0x00004, Data); ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckVGHARDWARE_SetFastClear( ++ IN gckVGHARDWARE Hardware, ++ IN gctINT Enable ++ ) ++{ ++ gctUINT32 debug; ++ gceSTATUS status; ++ ++ if (!(((((gctUINT32) (Hardware->chipFeatures)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) ++ { ++ return gcvSTATUS_OK; ++ } ++ ++ do ++ { ++ if (Enable == -1) ++ { ++ Enable = (Hardware->chipModel > gcv500) || ++ ((Hardware->chipModel == gcv500) && (Hardware->chipRevision >= 3)); ++ } ++ ++ gcmkERR_BREAK(gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x00414, ++ &debug)); ++ ++ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))); ++ ++#ifdef AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION ++ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1) == 32) ? ~0 : (~(~0 << ((1 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1))))))) << (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1) == 32) ? ~0 : (~(~0 << ((1 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1))))))) << (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION))); ++#endif ++ ++ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x00414, ++ debug)); ++ ++ Hardware->allowFastClear = Enable; ++ ++ status = gcvFALSE; ++ } ++ while (gcvFALSE); ++ ++ return status; ++} ++ ++gceSTATUS ++gckVGHARDWARE_ReadInterrupt( ++ IN gckVGHARDWARE Hardware, ++ OUT gctUINT32_PTR IDs ++ ) ++{ ++ gceSTATUS status; ++ gcmkHEADER_ARG("Hardware=0x%x IDs=0x%x", Hardware, IDs); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(IDs != gcvNULL); ++ ++ /* Read AQIntrAcknowledge register. */ ++ status = gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, ++ 0x00010, ++ IDs); ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS _CommandStall( ++ gckVGHARDWARE Hardware) ++{ ++ gceSTATUS status; ++ gckVGCOMMAND command; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ do ++ { ++ gctUINT32_PTR buffer; ++ command = Hardware->kernel->command; ++ ++ /* Allocate command buffer space. */ ++ gcmkERR_BREAK(gckVGCOMMAND_Allocate( ++ command, 8, &command->powerStallBuffer, ++ (gctPOINTER *) &buffer ++ )); ++ ++ gcmkERR_BREAK(gckVGCOMMAND_EventCommand( ++ command, buffer, gcvBLOCK_PIXEL, ++ command->powerStallInt, gcvNULL)); ++ ++ gcmkERR_BREAK(gckVGCOMMAND_Execute( ++ command, ++ command->powerStallBuffer ++ )); ++ ++ /* Wait the signal. */ ++ gcmkERR_BREAK(gckOS_WaitSignal( ++ command->os, ++ command->powerStallSignal, ++ command->kernel->kernel->timeOut)); ++ ++ ++ } ++ while(gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_SetPowerManagementState ++** ++** Set GPU to a specified power state. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gceCHIPPOWERSTATE State ++** Power State. ++** ++*/ ++gceSTATUS ++gckVGHARDWARE_SetPowerManagementState( ++ IN gckVGHARDWARE Hardware, ++ IN gceCHIPPOWERSTATE State ++ ) ++{ ++ gceSTATUS status; ++ gckVGCOMMAND command = gcvNULL; ++ gckOS os; ++ gctUINT flag/*, clock*/; ++ ++ gctBOOL acquired = gcvFALSE; ++ gctBOOL stall = gcvTRUE; ++ gctBOOL commitMutex = gcvFALSE; ++ gctBOOL mutexAcquired = gcvFALSE; ++ ++#if gcdPOWEROFF_TIMEOUT ++ gctBOOL timeout = gcvFALSE; ++ gctBOOL isAfter = gcvFALSE; ++ gctUINT32 currentTime; ++#endif ++ ++ gctBOOL broadcast = gcvFALSE; ++ gctUINT32 process, thread; ++ gctBOOL global = gcvFALSE; ++ ++#if gcdENABLE_PROFILING ++ gctUINT64 time, freq, mutexTime, onTime, stallTime, stopTime, delayTime, ++ initTime, offTime, startTime, totalTime; ++#endif ++ ++ /* State transition flags. */ ++ static const gctUINT flags[4][4] = ++ { ++ /* gcvPOWER_ON */ ++ { /* ON */ 0, ++ /* OFF */ gcvPOWER_FLAG_ACQUIRE | ++ gcvPOWER_FLAG_STALL | ++ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_POWER_OFF | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ /* IDLE */ gcvPOWER_FLAG_NOP, ++ /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE | ++ gcvPOWER_FLAG_STALL | ++ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ }, ++ ++ /* gcvPOWER_OFF */ ++ { /* ON */ gcvPOWER_FLAG_INITIALIZE | ++ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_RELEASE | ++ gcvPOWER_FLAG_DELAY, ++ /* OFF */ 0, ++ /* IDLE */ gcvPOWER_FLAG_INITIALIZE | ++ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_RELEASE | ++ gcvPOWER_FLAG_DELAY, ++ /* SUSPEND */ gcvPOWER_FLAG_INITIALIZE | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ }, ++ ++ /* gcvPOWER_IDLE */ ++ { /* ON */ gcvPOWER_FLAG_NOP, ++ /* OFF */ gcvPOWER_FLAG_ACQUIRE | ++ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_POWER_OFF | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ /* IDLE */ 0, ++ /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE | ++ gcvPOWER_FLAG_STOP | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ }, ++ ++ /* gcvPOWER_SUSPEND */ ++ { /* ON */ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_RELEASE | ++ gcvPOWER_FLAG_DELAY | ++ gcvPOWER_FLAG_CLOCK_ON, ++ /* OFF */ gcvPOWER_FLAG_SAVE | ++ gcvPOWER_FLAG_POWER_OFF | ++ gcvPOWER_FLAG_CLOCK_OFF, ++ /* IDLE */ gcvPOWER_FLAG_START | ++ gcvPOWER_FLAG_DELAY | ++ gcvPOWER_FLAG_RELEASE | ++ gcvPOWER_FLAG_CLOCK_ON, ++ /* SUSPEND */ 0, ++ }, ++ }; ++ ++ gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State); ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "Switching to power state %d", ++ State); ++#endif ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ /* Get the gckOS object pointer. */ ++ os = Hardware->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Get the gckCOMMAND object pointer. */ ++ gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL); ++ command = Hardware->kernel->command; ++ gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); ++ ++ if (Hardware->powerManagement == gcvFALSE) ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* Start profiler. */ ++ gcmkPROFILE_INIT(freq, time); ++ ++ /* Convert the broadcast power state. */ ++ switch (State) ++ { ++ case gcvPOWER_SUSPEND_ATPOWERON: ++ /* Convert to SUSPEND and don't wait for STALL. */ ++ State = gcvPOWER_SUSPEND; ++ stall = gcvFALSE; ++ break; ++ ++ case gcvPOWER_OFF_ATPOWERON: ++ /* Convert to OFF and don't wait for STALL. */ ++ State = gcvPOWER_OFF; ++ stall = gcvFALSE; ++ break; ++ ++ case gcvPOWER_IDLE_BROADCAST: ++ /* Convert to IDLE and note we are inside broadcast. */ ++ State = gcvPOWER_IDLE; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_SUSPEND_BROADCAST: ++ /* Convert to SUSPEND and note we are inside broadcast. */ ++ State = gcvPOWER_SUSPEND; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_OFF_BROADCAST: ++ /* Convert to OFF and note we are inside broadcast. */ ++ State = gcvPOWER_OFF; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_OFF_RECOVERY: ++ /* Convert to OFF and note we are inside recovery. */ ++ State = gcvPOWER_OFF; ++ stall = gcvFALSE; ++ broadcast = gcvTRUE; ++ break; ++ ++ case gcvPOWER_ON_AUTO: ++ /* Convert to ON and note we are inside recovery. */ ++ State = gcvPOWER_ON; ++ break; ++ ++ case gcvPOWER_ON: ++ case gcvPOWER_IDLE: ++ case gcvPOWER_SUSPEND: ++ case gcvPOWER_OFF: ++ /* Mark as global power management. */ ++ global = gcvTRUE; ++ break; ++ ++#if gcdPOWEROFF_TIMEOUT ++ case gcvPOWER_OFF_TIMEOUT: ++ /* Convert to OFF and note we are inside broadcast. */ ++ State = gcvPOWER_OFF; ++ broadcast = gcvTRUE; ++ /* Check time out */ ++ timeout = gcvTRUE; ++ break; ++#endif ++ ++ default: ++ break; ++ } ++ ++ /* Get current process and thread IDs. */ ++ gcmkONERROR(gckOS_GetProcessID(&process)); ++ gcmkONERROR(gckOS_GetThreadID(&thread)); ++ ++ /* Acquire the power mutex. */ ++ if (broadcast) ++ { ++ /* Try to acquire the power mutex. */ ++ status = gckOS_AcquireMutex(os, Hardware->powerMutex, 1); ++ ++ if (status == gcvSTATUS_TIMEOUT) ++ { ++ /* Check if we already own this mutex. */ ++ if ((Hardware->powerProcess == process) ++ && (Hardware->powerThread == thread) ++ ) ++ { ++ /* Bail out on recursive power management. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ else if (State == gcvPOWER_IDLE) ++ { ++ /* gcvPOWER_IDLE_BROADCAST is from IST, ++ ** so waiting here will cause deadlock, ++ ** if lock holder call gckCOMMAND_Stall() */ ++ gcmkONERROR(gcvSTATUS_INVALID_REQUEST); ++ } ++ else ++ { ++ /* Acquire the power mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(os, ++ Hardware->powerMutex, ++ gcvINFINITE)); ++ } ++ } ++ } ++ else ++ { ++ /* Acquire the power mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE)); ++ } ++ ++ /* Get time until mtuex acquired. */ ++ gcmkPROFILE_QUERY(time, mutexTime); ++ ++ Hardware->powerProcess = process; ++ Hardware->powerThread = thread; ++ mutexAcquired = gcvTRUE; ++ ++ /* Grab control flags and clock. */ ++ flag = flags[Hardware->chipPowerState][State]; ++ /*clock = clocks[State];*/ ++ ++#if gcdPOWEROFF_TIMEOUT ++ if (timeout) ++ { ++ gcmkONERROR(gckOS_GetTicks(¤tTime)); ++ ++ gcmkONERROR( ++ gckOS_TicksAfter(Hardware->powerOffTime, currentTime, &isAfter)); ++ ++ /* powerOffTime is pushed forward, give up.*/ ++ if (isAfter ++ /* Expect a transition start from IDLE. */ ++ || (Hardware->chipPowerState == gcvPOWER_ON) ++ || (Hardware->chipPowerState == gcvPOWER_OFF) ++ ) ++ { ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ /* No need to do anything. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ } ++#endif ++ ++ if (flag == 0) ++ { ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ /* No need to do anything. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* internal power control */ ++ if (!global) ++ { ++ if (Hardware->chipPowerStateGlobal == gcvPOWER_OFF) ++ { ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ /* No need to do anything. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ } ++ else ++ { ++ if (flag & gcvPOWER_FLAG_ACQUIRE) ++ { ++ /* Acquire the power management semaphore. */ ++ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); ++ acquired = gcvTRUE; ++ ++ /* avoid acquiring again. */ ++ flag &= ~gcvPOWER_FLAG_ACQUIRE; ++ } ++ } ++ ++ if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON)) ++ { ++ /* Turn on the power. */ ++ gcmkONERROR(gckOS_SetGPUPower(os, gcvCORE_VG, gcvTRUE, gcvTRUE)); ++ ++ /* Mark clock and power as enabled. */ ++ Hardware->clockState = gcvTRUE; ++ Hardware->powerState = gcvTRUE; ++ } ++ ++ /* Get time until powered on. */ ++ gcmkPROFILE_QUERY(time, onTime); ++ ++ if ((flag & gcvPOWER_FLAG_STALL) && stall) ++ { ++ /* Acquire the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex( ++ command->os, ++ command->commitMutex, ++ gcvINFINITE ++ )); ++ ++ commitMutex = gcvTRUE; ++ ++ gcmkONERROR(_CommandStall(Hardware)); ++ } ++ ++ /* Get time until stalled. */ ++ gcmkPROFILE_QUERY(time, stallTime); ++ ++ if (flag & gcvPOWER_FLAG_ACQUIRE) ++ { ++ /* Acquire the power management semaphore. */ ++ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); ++ ++ acquired = gcvTRUE; ++ } ++ ++ ++ /* Get time until stopped. */ ++ gcmkPROFILE_QUERY(time, stopTime); ++ ++ ++ if (flag & gcvPOWER_FLAG_DELAY) ++ { ++ /* Wait for the specified amount of time to settle coming back from ++ ** power-off or suspend state. */ ++ gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY)); ++ } ++ ++ /* Get time until delayed. */ ++ gcmkPROFILE_QUERY(time, delayTime); ++ ++ if (flag & gcvPOWER_FLAG_INITIALIZE) ++ { ++ ++ /* Initialize GPU here, replaced by InitializeHardware later */ ++ gcmkONERROR(gckVGHARDWARE_SetMMU(Hardware, Hardware->kernel->mmu->pageTableLogical)); ++ gcmkVERIFY_OK(gckVGHARDWARE_SetFastClear(Hardware, -1)); ++ ++ /* Force the command queue to reload the next context. */ ++ command->currentContext = 0; ++ } ++ ++ /* Get time until initialized. */ ++ gcmkPROFILE_QUERY(time, initTime); ++ ++ if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF)) ++ { ++ /* Turn off the GPU power. */ ++ gcmkONERROR( ++ gckOS_SetGPUPower(os, ++ gcvCORE_VG, ++ (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE ++ : gcvTRUE, ++ (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE ++ : gcvTRUE)); ++ ++ /* Save current hardware power and clock states. */ ++ Hardware->clockState = (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE ++ : gcvTRUE; ++ Hardware->powerState = (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE ++ : gcvTRUE; ++ } ++ ++ /* Get time until off. */ ++ gcmkPROFILE_QUERY(time, offTime); ++ ++ ++ /* Get time until started. */ ++ gcmkPROFILE_QUERY(time, startTime); ++ ++ if (flag & gcvPOWER_FLAG_RELEASE) ++ { ++ /* Release the power management semaphore. */ ++ gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore)); ++ acquired = gcvFALSE; ++ } ++ ++ /* Save the new power state. */ ++ Hardware->chipPowerState = State; ++ ++ if (global) ++ { ++ /* Save the new power state. */ ++ Hardware->chipPowerStateGlobal = State; ++ } ++ ++ if (commitMutex) ++ { ++ /* Acquire the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex( ++ command->os, ++ command->commitMutex ++ )); ++ } ++ ++#if gcdPOWEROFF_TIMEOUT ++ /* Reset power off time */ ++ gcmkONERROR(gckOS_GetTicks(¤tTime)); ++ ++ Hardware->powerOffTime = currentTime + Hardware->powerOffTimeout; ++ ++ if (State == gcvPOWER_IDLE) ++ { ++ /* Start a timer to power off GPU when GPU enters IDLE or SUSPEND. */ ++ gcmkVERIFY_OK(gckOS_StartTimer(os, ++ Hardware->powerOffTimer, ++ Hardware->powerOffTimeout)); ++ } ++ else ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "Cancel powerOfftimer"); ++ ++ /* Cancel running timer when GPU enters ON or OFF. */ ++ gcmkVERIFY_OK(gckOS_StopTimer(os, Hardware->powerOffTimer)); ++ } ++#endif ++ ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); ++ ++ /* Get total time. */ ++ gcmkPROFILE_QUERY(time, totalTime); ++#if gcdENABLE_PROFILING ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ "PROF(%llu): mutex:%llu on:%llu stall:%llu stop:%llu", ++ freq, mutexTime, onTime, stallTime, stopTime); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, ++ " delay:%llu init:%llu off:%llu start:%llu total:%llu", ++ delayTime, initTime, offTime, startTime, totalTime); ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ if (acquired) ++ { ++ /* Release semaphore. */ ++ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os, ++ command->powerSemaphore)); ++ } ++ ++ if (mutexAcquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); ++ } ++ ++ if (commitMutex) ++ { ++ /* Acquire the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex( ++ command->os, ++ command->commitMutex ++ )); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckHARDWARE_QueryPowerManagementState ++** ++** Get GPU power state. ++** ++** INPUT: ++** ++** gckHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gceCHIPPOWERSTATE* State ++** Power State. ++** ++*/ ++gceSTATUS ++gckVGHARDWARE_QueryPowerManagementState( ++ IN gckVGHARDWARE Hardware, ++ OUT gceCHIPPOWERSTATE* State ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(State != gcvNULL); ++ ++ /* Return the statue. */ ++ *State = Hardware->chipPowerState; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*State=%d", *State); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGHARDWARE_SetPowerManagement ++** ++** Configure GPU power management function. ++** Only used in driver initialization stage. ++** ++** INPUT: ++** ++** gckVGHARDWARE Harwdare ++** Pointer to an gckHARDWARE object. ++** ++** gctBOOL PowerManagement ++** Power Mangement State. ++** ++*/ ++gceSTATUS ++gckVGHARDWARE_SetPowerManagement( ++ IN gckVGHARDWARE Hardware, ++ IN gctBOOL PowerManagement ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ Hardware->powerManagement = PowerManagement; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++#if gcdPOWEROFF_TIMEOUT ++gceSTATUS ++gckVGHARDWARE_SetPowerOffTimeout( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Timeout ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x Timeout=%d", Hardware, Timeout); ++ ++ Hardware->powerOffTimeout = Timeout; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++ ++gceSTATUS ++gckVGHARDWARE_QueryPowerOffTimeout( ++ IN gckVGHARDWARE Hardware, ++ OUT gctUINT32* Timeout ++ ) ++{ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ *Timeout = Hardware->powerOffTimeout; ++ ++ gcmkFOOTER_ARG("*Timeout=%d", *Timeout); ++ return gcvSTATUS_OK; ++} ++#endif ++ ++gceSTATUS ++gckVGHARDWARE_QueryIdle( ++ IN gckVGHARDWARE Hardware, ++ OUT gctBOOL_PTR IsIdle ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 idle; ++ ++ gcmkHEADER_ARG("Hardware=0x%x", Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL); ++ ++ /* We are idle when the power is not ON. */ ++ if (Hardware->chipPowerState != gcvPOWER_ON) ++ { ++ *IsIdle = gcvTRUE; ++ } ++ ++ else ++ { ++ /* Read idle register. */ ++ gcmkONERROR( ++ gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, 0x00004, &idle)); ++ ++ /* Pipe must be idle. */ ++ if (((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 8:8)) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 10:10)) & ((gctUINT32) ((((1 ? 10:10) - (0 ? 10:10) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 10:10) - (0 ? 10:10) + 1)))))) ) != 1) ++ || ((((((gctUINT32) (idle)) >> (0 ? 11:11)) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1)))))) ) != 1) ++ ) ++ { ++ /* Something is busy. */ ++ *IsIdle = gcvFALSE; ++ } ++ ++ else ++ { ++ *IsIdle = gcvTRUE; ++ } ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif /* gcdENABLE_VG */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h +--- linux-3.14.72.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h 2016-06-19 22:11:55.133151292 +0200 +@@ -0,0 +1,74 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_hardware_vg_h_ ++#define __gc_hal_kernel_hardware_vg_h_ ++ ++/* gckHARDWARE object. */ ++struct _gckVGHARDWARE ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gckKERNEL object. */ ++ gckVGKERNEL kernel; ++ ++ /* Pointer to gckOS object. */ ++ gckOS os; ++ ++ /* Chip characteristics. */ ++ gceCHIPMODEL chipModel; ++ gctUINT32 chipRevision; ++ gctUINT32 chipFeatures; ++ gctUINT32 chipMinorFeatures; ++ gctUINT32 chipMinorFeatures2; ++ gctBOOL allowFastClear; ++ ++ /* Features. */ ++ gctBOOL fe20; ++ gctBOOL vg20; ++ gctBOOL vg21; ++ ++ /* Event mask. */ ++ gctUINT32 eventMask; ++ ++ gctBOOL clockState; ++ gctBOOL powerState; ++ gctPOINTER powerMutex; ++ gctUINT32 powerProcess; ++ gctUINT32 powerThread; ++ gceCHIPPOWERSTATE chipPowerState; ++ gceCHIPPOWERSTATE chipPowerStateGlobal; ++ gctISRMANAGERFUNC startIsr; ++ gctISRMANAGERFUNC stopIsr; ++ gctPOINTER isrContext; ++ gctPOINTER pageTableDirty; ++#if gcdPOWEROFF_TIMEOUT ++ gctUINT32 powerOffTime; ++ gctUINT32 powerOffTimeout; ++ gctPOINTER powerOffTimer; ++#endif ++ ++ gctBOOL powerManagement; ++}; ++ ++#endif /* __gc_hal_kernel_hardware_h_ */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/config linux-3.14.72/drivers/gpu/galcore/config +--- linux-3.14.72.orig/drivers/gpu/galcore/config 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/config 2016-06-19 22:11:55.133151292 +0200 +@@ -0,0 +1,35 @@ ++############################################################################## ++# ++# Copyright (C) 2005 - 2014 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. ++# ++############################################################################## ++ ++ ++ARCH_TYPE ?= arm ++SDK_DIR ?= $(AQROOT)/build/sdk ++VIVANTE_ENABLE_3D ?= 1 ++VIVANTE_ENABLE_2D ?= 1 ++VIVANTE_ENABLE_VG ?= 1 ++FORCE_ALL_VIDEO_MEMORY_CACHED ?= 0 ++NONPAGED_MEMORY_CACHEABLE ?= 0 ++NONPAGED_MEMORY_BUFFERABLE ?= 1 ++USE_BANK_ALIGNMENT ?= 1 ++BANK_BIT_START ?= 13 ++BANK_BIT_END ?= 15 ++BANK_CHANNEL_BIT ?= 12 ++PLATFORM ?= freescale/gc_hal_kernel_platform_imx6q14 ++DEBUG ?= 0 +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_allocator.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_allocator.c 2016-06-19 22:11:55.133151292 +0200 +@@ -0,0 +1,884 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++#include "gc_hal_kernel_allocator.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "gc_hal_kernel_allocator_array.h" ++#include "gc_hal_kernel_platform.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_OS ++ ++typedef struct _gcsDEFAULT_PRIV * gcsDEFAULT_PRIV_PTR; ++typedef struct _gcsDEFAULT_PRIV { ++ gctUINT32 low; ++ gctUINT32 high; ++} ++gcsDEFAULT_PRIV; ++ ++/******************************************************************************\ ++************************** Default Allocator Debugfs *************************** ++\******************************************************************************/ ++ ++int gc_usage_show(struct seq_file* m, void* data) ++{ ++ gcsINFO_NODE *node = m->private; ++ gckALLOCATOR Allocator = node->device; ++ gcsDEFAULT_PRIV_PTR priv = Allocator->privateData; ++ ++ seq_printf(m, "low: %u bytes\n", priv->low); ++ seq_printf(m, "high: %u bytes\n", priv->high); ++ ++ return 0; ++} ++ ++static gcsINFO InfoList[] = ++{ ++ {"lowHighUsage", gc_usage_show}, ++}; ++ ++static void ++_DefaultAllocatorDebugfsInit( ++ IN gckALLOCATOR Allocator, ++ IN gckDEBUGFS_DIR Root ++ ) ++{ ++ gcmkVERIFY_OK( ++ gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "default")); ++ ++ gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles( ++ &Allocator->debugfsDir, ++ InfoList, ++ gcmCOUNTOF(InfoList), ++ Allocator ++ )); ++} ++ ++static void ++_DefaultAllocatorDebugfsCleanup( ++ IN gckALLOCATOR Allocator ++ ) ++{ ++ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles( ++ &Allocator->debugfsDir, ++ InfoList, ++ gcmCOUNTOF(InfoList) ++ )); ++ ++ gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir); ++} ++ ++ ++static void ++_NonContiguousFree( ++ IN struct page ** Pages, ++ IN gctUINT32 NumPages ++ ) ++{ ++ gctINT i; ++ ++ gcmkHEADER_ARG("Pages=0x%X, NumPages=%d", Pages, NumPages); ++ ++ gcmkASSERT(Pages != gcvNULL); ++ ++ for (i = 0; i < NumPages; i++) ++ { ++ __free_page(Pages[i]); ++ } ++ ++ if (is_vmalloc_addr(Pages)) ++ { ++ vfree(Pages); ++ } ++ else ++ { ++ kfree(Pages); ++ } ++ ++ gcmkFOOTER_NO(); ++} ++ ++static struct page ** ++_NonContiguousAlloc( ++ IN gctUINT32 NumPages ++ ) ++{ ++ struct page ** pages; ++ struct page *p; ++ gctINT i, size; ++ ++ gcmkHEADER_ARG("NumPages=%lu", NumPages); ++ ++ if (NumPages > totalram_pages) ++ { ++ gcmkFOOTER_NO(); ++ return gcvNULL; ++ } ++ ++ size = NumPages * sizeof(struct page *); ++ ++ pages = kmalloc(size, GFP_KERNEL | gcdNOWARN); ++ ++ if (!pages) ++ { ++ pages = vmalloc(size); ++ ++ if (!pages) ++ { ++ gcmkFOOTER_NO(); ++ return gcvNULL; ++ } ++ } ++ ++ for (i = 0; i < NumPages; i++) ++ { ++ p = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN); ++ ++ if (!p) ++ { ++ _NonContiguousFree(pages, i); ++ gcmkFOOTER_NO(); ++ return gcvNULL; ++ } ++ ++ pages[i] = p; ++ } ++ ++ gcmkFOOTER_ARG("pages=0x%X", pages); ++ return pages; ++} ++ ++gctSTRING ++_CreateKernelVirtualMapping( ++ IN PLINUX_MDL Mdl ++ ) ++{ ++ gctSTRING addr = 0; ++ gctINT numPages = Mdl->numPages; ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ if (Mdl->contiguous) ++ { ++ addr = page_address(Mdl->u.contiguousPages); ++ } ++ else ++ { ++ addr = vmap(Mdl->u.nonContiguousPages, ++ numPages, ++ 0, ++ PAGE_KERNEL); ++ ++ /* Trigger a page fault. */ ++ memset(addr, 0, numPages * PAGE_SIZE); ++ } ++#else ++ struct page ** pages; ++ gctBOOL free = gcvFALSE; ++ gctINT i; ++ ++ if (Mdl->contiguous) ++ { ++ pages = kmalloc(sizeof(struct page *) * numPages, GFP_KERNEL | gcdNOWARN); ++ ++ if (!pages) ++ { ++ return gcvNULL; ++ } ++ ++ for (i = 0; i < numPages; i++) ++ { ++ pages[i] = nth_page(Mdl->u.contiguousPages, i); ++ } ++ ++ free = gcvTRUE; ++ } ++ else ++ { ++ pages = Mdl->u.nonContiguousPages; ++ } ++ ++ /* ioremap() can't work on system memory since 2.6.38. */ ++ addr = vmap(pages, numPages, 0, gcmkNONPAGED_MEMROY_PROT(PAGE_KERNEL)); ++ ++ if (free) ++ { ++ kfree(pages); ++ } ++ ++#endif ++ ++ return addr; ++} ++ ++void ++_DestoryKernelVirtualMapping( ++ IN gctSTRING Addr ++ ) ++{ ++#if !gcdNONPAGED_MEMORY_CACHEABLE ++ vunmap(Addr); ++#endif ++} ++ ++void ++_UnmapUserLogical( ++ IN gctPOINTER Logical, ++ IN gctUINT32 Size ++) ++{ ++ if (unlikely(current->mm == gcvNULL)) ++ { ++ /* Do nothing if process is exiting. */ ++ return; ++ } ++ ++ if (vm_munmap((unsigned long)Logical, Size) < 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d): vm_munmap failed", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++} ++ ++/***************************************************************************\ ++************************ Default Allocator ********************************** ++\***************************************************************************/ ++#define C_MAX_PAGENUM (50*1024) ++static gceSTATUS ++_DefaultAlloc( ++ IN gckALLOCATOR Allocator, ++ INOUT PLINUX_MDL Mdl, ++ IN gctSIZE_T NumPages, ++ IN gctUINT32 Flags ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 order; ++ gctSIZE_T bytes; ++ gctPOINTER addr = gcvNULL; ++ gctUINT32 numPages; ++ gctUINT i = 0; ++ gctBOOL contiguous = Flags & gcvALLOC_FLAG_CONTIGUOUS; ++ struct sysinfo temsysinfo; ++ gcsDEFAULT_PRIV_PTR priv = (gcsDEFAULT_PRIV_PTR)Allocator->privateData; ++ ++ gcmkHEADER_ARG("Mdl=%p NumPages=%d", Mdl, NumPages); ++ ++ numPages = NumPages; ++ bytes = NumPages * PAGE_SIZE; ++ order = get_order(bytes); ++ ++ si_meminfo(&temsysinfo); ++ ++ if (Flags & gcvALLOC_FLAG_MEMLIMIT) ++ { ++ if ( (temsysinfo.freeram < NumPages) || ((temsysinfo.freeram-NumPages) < C_MAX_PAGENUM) ) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ } ++ ++ if (contiguous) ++ { ++ if (order >= MAX_ORDER) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ addr = ++ alloc_pages_exact(bytes, GFP_KERNEL | gcdNOWARN | __GFP_NORETRY); ++ ++ Mdl->u.contiguousPages = addr ++ ? virt_to_page(addr) ++ : gcvNULL; ++ ++ Mdl->exact = gcvTRUE; ++ ++ if (Mdl->u.contiguousPages == gcvNULL) ++ { ++ Mdl->u.contiguousPages = ++ alloc_pages(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN, order); ++ ++ Mdl->exact = gcvFALSE; ++ } ++ } ++ else ++ { ++ Mdl->u.nonContiguousPages = _NonContiguousAlloc(numPages); ++ } ++ ++ if (Mdl->u.contiguousPages == gcvNULL && Mdl->u.nonContiguousPages == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ for (i = 0; i < numPages; i++) ++ { ++ struct page *page; ++ ++ if (contiguous) ++ { ++ page = nth_page(Mdl->u.contiguousPages, i); ++ } ++ else ++ { ++ page = _NonContiguousToPage(Mdl->u.nonContiguousPages, i); ++ } ++ ++ SetPageReserved(page); ++ ++ if (!PageHighMem(page) && page_to_phys(page)) ++ { ++ gcmkVERIFY_OK( ++ gckOS_CacheFlush(Allocator->os, _GetProcessID(), gcvNULL, ++ page_to_phys(page), ++ page_address(page), ++ PAGE_SIZE)); ++ ++ priv->low += PAGE_SIZE; ++ } ++ else ++ { ++ flush_dcache_page(page); ++ ++ priv->high += PAGE_SIZE; ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++static void ++_DefaultFree( ++ IN gckALLOCATOR Allocator, ++ IN OUT PLINUX_MDL Mdl ++ ) ++{ ++ gctINT i; ++ struct page * page; ++ gcsDEFAULT_PRIV_PTR priv = (gcsDEFAULT_PRIV_PTR)Allocator->privateData; ++ ++ for (i = 0; i < Mdl->numPages; i++) ++ { ++ if (Mdl->contiguous) ++ { ++ page = nth_page(Mdl->u.contiguousPages, i); ++ } ++ else ++ { ++ page = _NonContiguousToPage(Mdl->u.nonContiguousPages, i); ++ } ++ ++ ClearPageReserved(page); ++ ++ if (PageHighMem(page)) ++ { ++ priv->high -= PAGE_SIZE; ++ } ++ else ++ { ++ priv->low -= PAGE_SIZE; ++ } ++ } ++ ++ if (Mdl->contiguous) ++ { ++ if (Mdl->exact == gcvTRUE) ++ { ++ free_pages_exact(page_address(Mdl->u.contiguousPages), Mdl->numPages * PAGE_SIZE); ++ } ++ else ++ { ++ __free_pages(Mdl->u.contiguousPages, get_order(Mdl->numPages * PAGE_SIZE)); ++ } ++ } ++ else ++ { ++ _NonContiguousFree(Mdl->u.nonContiguousPages, Mdl->numPages); ++ } ++} ++ ++gctINT ++_DefaultMapUser( ++ gckALLOCATOR Allocator, ++ PLINUX_MDL Mdl, ++ PLINUX_MDL_MAP MdlMap, ++ gctBOOL Cacheable ++ ) ++{ ++ ++ gctSTRING addr; ++ unsigned long start; ++ unsigned long pfn; ++ gctINT i; ++ gckOS os = Allocator->os; ++ gcsPLATFORM * platform = os->device->platform; ++ ++ PLINUX_MDL mdl = Mdl; ++ PLINUX_MDL_MAP mdlMap = MdlMap; ++ ++ gcmkHEADER_ARG("Allocator=%p Mdl=%p MdlMap=%p gctBOOL=%d", Allocator, Mdl, MdlMap, Cacheable); ++ ++ mdlMap->vmaAddr = (gctSTRING)vm_mmap(gcvNULL, ++ 0L, ++ mdl->numPages * PAGE_SIZE, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED, ++ 0); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): vmaAddr->0x%X for phys_addr->0x%X", ++ __FUNCTION__, __LINE__, ++ (gctUINT32)(gctUINTPTR_T)mdlMap->vmaAddr, ++ (gctUINT32)(gctUINTPTR_T)mdl ++ ); ++ ++ if (IS_ERR(mdlMap->vmaAddr)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): do_mmap_pgoff error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ down_write(¤t->mm->mmap_sem); ++ ++ mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); ++ ++ if (mdlMap->vma == gcvNULL) ++ { ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): find_vma error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_RESOURCES); ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++ mdlMap->vma->vm_flags |= gcdVM_FLAGS; ++ ++ if (Cacheable == gcvFALSE) ++ { ++ /* Make this mapping non-cached. */ ++ mdlMap->vma->vm_page_prot = gcmkPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot); ++ } ++ ++ if (platform && platform->ops->adjustProt) ++ { ++ platform->ops->adjustProt(mdlMap->vma); ++ } ++ ++ addr = mdl->addr; ++ ++ /* Now map all the vmalloc pages to this user address. */ ++ if (mdl->contiguous) ++ { ++ /* map kernel memory to user space.. */ ++ if (remap_pfn_range(mdlMap->vma, ++ mdlMap->vma->vm_start, ++ page_to_pfn(mdl->u.contiguousPages), ++ mdlMap->vma->vm_end - mdlMap->vma->vm_start, ++ mdlMap->vma->vm_page_prot) < 0) ++ { ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): unable to mmap ret", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ } ++ else ++ { ++ start = mdlMap->vma->vm_start; ++ ++ for (i = 0; i < mdl->numPages; i++) ++ { ++ pfn = _NonContiguousToPfn(mdl->u.nonContiguousPages, i); ++ ++ if (remap_pfn_range(mdlMap->vma, ++ start, ++ pfn, ++ PAGE_SIZE, ++ mdlMap->vma->vm_page_prot) < 0) ++ { ++ up_write(¤t->mm->mmap_sem); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ start += PAGE_SIZE; ++ addr += PAGE_SIZE; ++ } ++ } ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++void ++_DefaultUnmapUser( ++ IN gckALLOCATOR Allocator, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Size ++ ) ++{ ++ _UnmapUserLogical(Logical, Size); ++} ++ ++gceSTATUS ++_DefaultMapKernel( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ OUT gctPOINTER *Logical ++ ) ++{ ++ *Logical = _CreateKernelVirtualMapping(Mdl); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_DefaultUnmapKernel( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical ++ ) ++{ ++ _DestoryKernelVirtualMapping(Logical); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_DefaultLogicalToPhysical( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical, ++ IN gctUINT32 ProcessID, ++ OUT gctUINT32_PTR Physical ++ ) ++{ ++ return _ConvertLogical2Physical( ++ Allocator->os, Logical, ProcessID, Mdl, Physical); ++} ++ ++gceSTATUS ++_DefaultCache( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical, ++ IN gctUINT32 Bytes, ++ IN gceCACHEOPERATION Operation ++ ) ++{ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_DefaultPhysical( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctUINT32 Offset, ++ OUT gctUINT32_PTR Physical ++ ) ++{ ++ gcmkASSERT(Mdl->pagedMem && !Mdl->contiguous); ++ *Physical = _NonContiguousToPhys(Mdl->u.nonContiguousPages, Offset); ++ ++ return gcvSTATUS_OK; ++} ++ ++void ++_DefaultAllocatorDestructor( ++ IN void* PrivateData ++ ) ++{ ++ kfree(PrivateData); ++} ++ ++/* Default allocator operations. */ ++gcsALLOCATOR_OPERATIONS DefaultAllocatorOperations = { ++ .Alloc = _DefaultAlloc, ++ .Free = _DefaultFree, ++ .MapUser = _DefaultMapUser, ++ .UnmapUser = _DefaultUnmapUser, ++ .MapKernel = _DefaultMapKernel, ++ .UnmapKernel = _DefaultUnmapKernel, ++ .LogicalToPhysical = _DefaultLogicalToPhysical, ++ .Cache = _DefaultCache, ++ .Physical = _DefaultPhysical, ++}; ++ ++/* Default allocator entry. */ ++gceSTATUS ++_DefaultAlloctorInit( ++ IN gckOS Os, ++ OUT gckALLOCATOR * Allocator ++ ) ++{ ++ gceSTATUS status; ++ gckALLOCATOR allocator; ++ gcsDEFAULT_PRIV_PTR priv = gcvNULL; ++ ++ gcmkONERROR( ++ gckALLOCATOR_Construct(Os, &DefaultAllocatorOperations, &allocator)); ++ ++ priv = kzalloc(gcmSIZEOF(gcsDEFAULT_PRIV), GFP_KERNEL | gcdNOWARN); ++ ++ if (!priv) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Register private data. */ ++ allocator->privateData = priv; ++ allocator->privateDataDestructor = _DefaultAllocatorDestructor; ++ ++ allocator->debugfsInit = _DefaultAllocatorDebugfsInit; ++ allocator->debugfsCleanup = _DefaultAllocatorDebugfsCleanup; ++ ++ *Allocator = allocator; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++/***************************************************************************\ ++************************ Allocator helper *********************************** ++\***************************************************************************/ ++ ++gceSTATUS ++gckALLOCATOR_Construct( ++ IN gckOS Os, ++ IN gcsALLOCATOR_OPERATIONS * Operations, ++ OUT gckALLOCATOR * Allocator ++ ) ++{ ++ gceSTATUS status; ++ gckALLOCATOR allocator; ++ ++ gcmkHEADER_ARG("Os=%p, Operations=%p, Allocator=%p", ++ Os, Operations, Allocator); ++ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Allocator != gcvNULL); ++ gcmkVERIFY_ARGUMENT ++ ( Operations ++ && Operations->Alloc ++ && Operations->Free ++ && Operations->MapUser ++ && Operations->UnmapUser ++ && Operations->MapKernel ++ && Operations->UnmapKernel ++ && Operations->LogicalToPhysical ++ && Operations->Cache ++ && Operations->Physical ++ ); ++ ++ gcmkONERROR( ++ gckOS_Allocate(Os, gcmSIZEOF(gcsALLOCATOR), (gctPOINTER *)&allocator)); ++ ++ gckOS_ZeroMemory(allocator, gcmSIZEOF(gcsALLOCATOR)); ++ ++ /* Record os. */ ++ allocator->os = Os; ++ ++ /* Set operations. */ ++ allocator->ops = Operations; ++ ++ allocator->capability = gcvALLOC_FLAG_CONTIGUOUS ++ | gcvALLOC_FLAG_NON_CONTIGUOUS ++ | gcvALLOC_FLAG_CACHEABLE ++ | gcvALLOC_FLAG_MEMLIMIT; ++ ; ++ ++ *Allocator = allocator; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************\ ++******************************** Debugfs Support ******************************* ++\******************************************************************************/ ++ ++static gceSTATUS ++_AllocatorDebugfsInit( ++ IN gckOS Os ++ ) ++{ ++ gceSTATUS status; ++ gckGALDEVICE device = Os->device; ++ ++ gckDEBUGFS_DIR dir = &Os->allocatorDebugfsDir; ++ ++ gcmkONERROR(gckDEBUGFS_DIR_Init(dir, device->debugfsDir.root, "allocators")); ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++static void ++_AllocatorDebugfsCleanup( ++ IN gckOS Os ++ ) ++{ ++ gckDEBUGFS_DIR dir = &Os->allocatorDebugfsDir; ++ ++ gckDEBUGFS_DIR_Deinit(dir); ++} ++ ++/***************************************************************************\ ++************************ Allocator management ******************************* ++\***************************************************************************/ ++ ++gceSTATUS ++gckOS_ImportAllocators( ++ gckOS Os ++ ) ++{ ++ gceSTATUS status; ++ gctUINT i; ++ gckALLOCATOR allocator; ++ ++ _AllocatorDebugfsInit(Os); ++ ++ INIT_LIST_HEAD(&Os->allocatorList); ++ ++ for (i = 0; i < gcmCOUNTOF(allocatorArray); i++) ++ { ++ if (allocatorArray[i].construct) ++ { ++ /* Construct allocator. */ ++ status = allocatorArray[i].construct(Os, &allocator); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ gcmkPRINT("["DEVICE_NAME"]: Can't construct allocator(%s)", ++ allocatorArray[i].name); ++ ++ continue; ++ } ++ ++ allocator->name = allocatorArray[i].name; ++ ++ if (allocator->debugfsInit) ++ { ++ /* Init allocator's debugfs. */ ++ allocator->debugfsInit(allocator, &Os->allocatorDebugfsDir); ++ } ++ ++ list_add_tail(&allocator->head, &Os->allocatorList); ++ } ++ } ++ ++#if DEBUG ++ list_for_each_entry(allocator, &Os->allocatorList, head) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d) Allocator: %s", ++ __FUNCTION__, __LINE__, ++ allocator->name ++ ); ++ } ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_FreeAllocators( ++ gckOS Os ++ ) ++{ ++ gckALLOCATOR allocator; ++ gckALLOCATOR temp; ++ ++ list_for_each_entry_safe(allocator, temp, &Os->allocatorList, head) ++ { ++ list_del(&allocator->head); ++ ++ if (allocator->debugfsCleanup) ++ { ++ /* Clean up allocator's debugfs. */ ++ allocator->debugfsCleanup(allocator); ++ } ++ ++ /* Free private data. */ ++ if (allocator->privateDataDestructor && allocator->privateData) ++ { ++ allocator->privateDataDestructor(allocator->privateData); ++ } ++ ++ gckOS_Free(Os, allocator); ++ } ++ ++ _AllocatorDebugfsCleanup(Os); ++ ++ return gcvSTATUS_OK; ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_allocator.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_allocator.h 2016-06-19 22:11:55.133151292 +0200 +@@ -0,0 +1,400 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_allocator_h_ ++#define __gc_hal_kernel_allocator_h_ ++ ++#include "gc_hal_kernel_linux.h" ++ ++typedef struct _gcsALLOCATOR * gckALLOCATOR; ++ ++typedef struct _gcsALLOCATOR_OPERATIONS ++{ ++ /************************************************************************** ++ ** ++ ** Alloc ++ ** ++ ** Allocte memory, request size is page aligned. ++ ** ++ ** INPUT: ++ ** ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_Mdl ++ ** Pointer to Mdl whichs stores information ++ ** about allocated memory. ++ ** ++ ** gctSIZE_T NumPages ++ ** Number of pages need to allocate. ++ ** ++ ** gctUINT32 Flag ++ ** Allocation option. ++ ** ++ ** OUTPUT: ++ ** ++ ** Nothing. ++ ** ++ */ ++ gceSTATUS ++ (*Alloc)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctSIZE_T NumPages, ++ IN gctUINT32 Flag ++ ); ++ ++ /************************************************************************** ++ ** ++ ** Free ++ ** ++ ** Free memory. ++ ** ++ ** INPUT: ++ ** ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_MDL Mdl ++ ** Mdl which stores information. ++ ** ++ ** OUTPUT: ++ ** ++ ** Nothing. ++ ** ++ */ ++ void ++ (*Free)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl ++ ); ++ ++ /************************************************************************** ++ ** ++ ** MapUser ++ ** ++ ** Map memory to user space. ++ ** ++ ** INPUT: ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_MDL Mdl ++ ** Pointer to a Mdl. ++ ** ++ ** PLINUX_MDL_MAP MdlMap ++ ** Pointer to a MdlMap, mapped address is stored ++ ** in MdlMap->vmaAddr ++ ** ++ ** gctBOOL Cacheable ++ ** Whether this mapping is cacheable. ++ ** ++ ** OUTPUT: ++ ** ++ ** Nothing. ++ ** ++ */ ++ gctINT ++ (*MapUser)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN PLINUX_MDL_MAP MdlMap, ++ IN gctBOOL Cacheable ++ ); ++ ++ /************************************************************************** ++ ** ++ ** UnmapUser ++ ** ++ ** Unmap address from user address space. ++ ** ++ ** INPUT: ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** gctPOINTER Logical ++ ** Address to be unmap ++ ** ++ ** gctUINT32 Size ++ ** Size of address space ++ ** ++ ** OUTPUT: ++ ** ++ ** Nothing. ++ ** ++ */ ++ void ++ (*UnmapUser)( ++ IN gckALLOCATOR Allocator, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Size ++ ); ++ ++ /************************************************************************** ++ ** ++ ** MapKernel ++ ** ++ ** Map memory to kernel space. ++ ** ++ ** INPUT: ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_MDL Mdl ++ ** Pointer to a Mdl object. ++ ** ++ ** OUTPUT: ++ ** gctPOINTER * Logical ++ ** Mapped kernel address. ++ */ ++ gceSTATUS ++ (*MapKernel)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ OUT gctPOINTER *Logical ++ ); ++ ++ /************************************************************************** ++ ** ++ ** UnmapKernel ++ ** ++ ** Unmap memory from kernel space. ++ ** ++ ** INPUT: ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_MDL Mdl ++ ** Pointer to a Mdl object. ++ ** ++ ** gctPOINTER Logical ++ ** Mapped kernel address. ++ ** ++ ** OUTPUT: ++ ** ++ ** Nothing. ++ ** ++ */ ++ gceSTATUS ++ (*UnmapKernel)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical ++ ); ++ ++ /************************************************************************** ++ ** ++ ** LogicalToPhysical ++ ** ++ ** Get physical address from logical address, logical ++ ** address could be user virtual address or kernel ++ ** virtual address. ++ ** ++ ** INPUT: ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_MDL Mdl ++ ** Pointer to a Mdl object. ++ ** ++ ** gctPOINTER Logical ++ ** Mapped kernel address. ++ ** ++ ** gctUINT32 ProcessID ++ ** pid of current process. ++ ** OUTPUT: ++ ** ++ ** gctUINT32_PTR Physical ++ ** Physical address. ++ ** ++ */ ++ gceSTATUS ++ (*LogicalToPhysical)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical, ++ IN gctUINT32 ProcessID, ++ OUT gctUINT32_PTR Physical ++ ); ++ ++ /************************************************************************** ++ ** ++ ** Cache ++ ** ++ ** Maintain cache coherency. ++ ** ++ ** INPUT: ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_MDL Mdl ++ ** Pointer to a Mdl object. ++ ** ++ ** gctPOINTER Logical ++ ** Logical address, could be user address or kernel address ++ ** ++ ** gctUINT32_PTR Physical ++ ** Physical address. ++ ** ++ ** gctUINT32 Bytes ++ ** Size of memory region. ++ ** ++ ** gceCACHEOPERATION Opertaion ++ ** Cache operation. ++ ** ++ ** OUTPUT: ++ ** ++ ** Nothing. ++ ** ++ */ ++ gceSTATUS (*Cache)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical, ++ IN gctUINT32 Bytes, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++ /************************************************************************** ++ ** ++ ** Physical ++ ** ++ ** Get physical address from a offset in memory region. ++ ** ++ ** INPUT: ++ ** gckALLOCATOR Allocator ++ ** Pointer to an gckALLOCATOER object. ++ ** ++ ** PLINUX_MDL Mdl ++ ** Pointer to a Mdl object. ++ ** ++ ** gctUINT32 Offset ++ ** Offset in this memory region. ++ ** ++ ** OUTPUT: ++ ** gctUINT32_PTR Physical ++ ** Physical address. ++ ** ++ */ ++ gceSTATUS (*Physical)( ++ IN gckALLOCATOR Allocator, ++ IN PLINUX_MDL Mdl, ++ IN gctUINT32 Offset, ++ OUT gctUINT32_PTR Physical ++ ); ++} ++gcsALLOCATOR_OPERATIONS; ++ ++typedef struct _gcsALLOCATOR ++{ ++ /* Pointer to gckOS Object. */ ++ gckOS os; ++ ++ /* Name. */ ++ gctSTRING name; ++ ++ /* Operations. */ ++ gcsALLOCATOR_OPERATIONS* ops; ++ ++ /* Capability of this allocator. */ ++ gctUINT32 capability; ++ ++ struct list_head head; ++ ++ /* Debugfs entry of this allocator. */ ++ gcsDEBUGFS_DIR debugfsDir; ++ ++ /* Init allocator debugfs. */ ++ void (*debugfsInit)(gckALLOCATOR, gckDEBUGFS_DIR); ++ ++ /* Cleanup allocator debugfs. */ ++ void (*debugfsCleanup)(gckALLOCATOR); ++ ++ /* Private data used by customer allocator. */ ++ void * privateData; ++ ++ /* Private data destructor. */ ++ void (*privateDataDestructor)(void *); ++} ++gcsALLOCATOR; ++ ++typedef struct _gcsALLOCATOR_DESC ++{ ++ /* Name of a allocator. */ ++ char * name; ++ ++ /* Entry function to construct a allocator. */ ++ gceSTATUS (*construct)(gckOS, gckALLOCATOR *); ++} ++gcsALLOCATOR_DESC; ++ ++/* ++* Helpers ++*/ ++ ++/* Fill a gcsALLOCATOR_DESC structure. */ ++#define gcmkDEFINE_ALLOCATOR_DESC(Name, Construct) \ ++ { \ ++ .name = Name, \ ++ .construct = Construct, \ ++ } ++ ++/* Construct a allocator. */ ++gceSTATUS ++gckALLOCATOR_Construct( ++ IN gckOS Os, ++ IN gcsALLOCATOR_OPERATIONS * Operations, ++ OUT gckALLOCATOR * Allocator ++ ); ++ ++/* ++ How to implement customer allocator ++ ++ Build in customer alloctor ++ ++ It is recommanded that customer allocator is implmented in independent ++ source file(s) which is specified by CUSOMTER_ALLOCATOR_OBJS in Kbuld. ++ ++ Register gcsALLOCATOR ++ ++ For each customer specified allocator, a desciption entry must be added ++ to allocatorArray defined in gc_hal_kernel_allocator_array.h. ++ ++ An entry in allocatorArray is a gcsALLOCATOR_DESC structure which describes ++ name and constructor of a gckALLOCATOR object. ++ ++ ++ Implement gcsALLOCATOR_DESC.init() ++ ++ In gcsALLOCATOR_DESC.init(), gckALLOCATOR_Construct should be called ++ to create a gckALLOCATOR object, customer specified private data can ++ be put in gcsALLOCATOR.privateData. ++ ++ ++ Implement gcsALLOCATOR_OPERATIONS ++ ++ When call gckALLOCATOR_Construct to create a gckALLOCATOR object, a ++ gcsALLOCATOR_OPERATIONS structure must be provided whose all members ++ implemented. ++ ++*/ ++#endif +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel.c 2016-06-19 22:11:55.133151292 +0200 +@@ -0,0 +1,4244 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include ++#include "gc_hal_kernel_precomp.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_KERNEL ++ ++/******************************************************************************* ++***** Version Signature *******************************************************/ ++ ++#define _gcmTXT2STR(t) #t ++#define gcmTXT2STR(t) _gcmTXT2STR(t) ++const char * _VERSION = "\n\0$VERSION$" ++ gcmTXT2STR(gcvVERSION_MAJOR) "." ++ gcmTXT2STR(gcvVERSION_MINOR) "." ++ gcmTXT2STR(gcvVERSION_PATCH) ":" ++ gcmTXT2STR(gcvVERSION_BUILD) "$\n"; ++ ++/******************************************************************************\ ++******************************* gckKERNEL API Code ****************************** ++\******************************************************************************/ ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++#define gcmDEFINE2TEXT(d) #d ++gctCONST_STRING _DispatchText[] = ++{ ++ gcmDEFINE2TEXT(gcvHAL_QUERY_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_IDENTITY), ++ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_NON_PAGED_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_FREE_NON_PAGED_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_FREE_CONTIGUOUS_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_RELEASE_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_MAP_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_UNMAP_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_MAP_USER_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_UNMAP_USER_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_LOCK_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_UNLOCK_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_EVENT_COMMIT), ++ gcmDEFINE2TEXT(gcvHAL_USER_SIGNAL), ++ gcmDEFINE2TEXT(gcvHAL_SIGNAL), ++ gcmDEFINE2TEXT(gcvHAL_WRITE_DATA), ++ gcmDEFINE2TEXT(gcvHAL_COMMIT), ++ gcmDEFINE2TEXT(gcvHAL_STALL), ++ gcmDEFINE2TEXT(gcvHAL_READ_REGISTER), ++ gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER), ++ gcmDEFINE2TEXT(gcvHAL_GET_PROFILE_SETTING), ++ gcmDEFINE2TEXT(gcvHAL_SET_PROFILE_SETTING), ++ gcmDEFINE2TEXT(gcvHAL_READ_ALL_PROFILE_REGISTERS), ++ gcmDEFINE2TEXT(gcvHAL_PROFILE_REGISTERS_2D), ++#if VIVANTE_PROFILER_PERDRAW ++ gcvHAL_READ_PROFILER_REGISTER_SETTING, ++#endif ++ gcmDEFINE2TEXT(gcvHAL_SET_POWER_MANAGEMENT_STATE), ++ gcmDEFINE2TEXT(gcvHAL_QUERY_POWER_MANAGEMENT_STATE), ++ gcmDEFINE2TEXT(gcvHAL_GET_BASE_ADDRESS), ++ gcmDEFINE2TEXT(gcvHAL_SET_IDLE), ++ gcmDEFINE2TEXT(gcvHAL_QUERY_KERNEL_SETTINGS), ++ gcmDEFINE2TEXT(gcvHAL_RESET), ++ gcmDEFINE2TEXT(gcvHAL_MAP_PHYSICAL), ++ gcmDEFINE2TEXT(gcvHAL_DEBUG), ++ gcmDEFINE2TEXT(gcvHAL_CACHE), ++ gcmDEFINE2TEXT(gcvHAL_TIMESTAMP), ++ gcmDEFINE2TEXT(gcvHAL_DATABASE), ++ gcmDEFINE2TEXT(gcvHAL_VERSION), ++ gcmDEFINE2TEXT(gcvHAL_CHIP_INFO), ++ gcmDEFINE2TEXT(gcvHAL_ATTACH), ++ gcmDEFINE2TEXT(gcvHAL_DETACH), ++ gcmDEFINE2TEXT(gcvHAL_COMPOSE), ++ gcmDEFINE2TEXT(gcvHAL_SET_TIMEOUT), ++ gcmDEFINE2TEXT(gcvHAL_GET_FRAME_INFO), ++ gcmDEFINE2TEXT(gcvHAL_QUERY_COMMAND_BUFFER), ++ gcmDEFINE2TEXT(gcvHAL_COMMIT_DONE), ++ gcmDEFINE2TEXT(gcvHAL_DUMP_GPU_STATE), ++ gcmDEFINE2TEXT(gcvHAL_DUMP_EVENT), ++ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER), ++ gcmDEFINE2TEXT(gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER), ++ gcmDEFINE2TEXT(gcvHAL_SET_FSCALE_VALUE), ++ gcmDEFINE2TEXT(gcvHAL_GET_FSCALE_VALUE), ++ gcmDEFINE2TEXT(gcvHAL_NAME_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_IMPORT_VIDEO_MEMORY), ++ gcmDEFINE2TEXT(gcvHAL_QUERY_RESET_TIME_STAMP), ++ gcmDEFINE2TEXT(gcvHAL_READ_REGISTER_EX), ++ gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER_EX), ++ gcmDEFINE2TEXT(gcvHAL_SYNC_POINT), ++ gcmDEFINE2TEXT(gcvHAL_CREATE_NATIVE_FENCE), ++ gcmDEFINE2TEXT(gcvHAL_DESTROY_MMU), ++ gcmDEFINE2TEXT(gcvHAL_SHBUF), ++}; ++#endif ++ ++#if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC ++void ++_MonitorTimerFunction( ++ gctPOINTER Data ++ ) ++{ ++ gckKERNEL kernel = (gckKERNEL)Data; ++ gctUINT32 pendingInterrupt; ++ gctBOOL reset = gcvFALSE; ++ gctUINT32 mask; ++ gctUINT32 advance = kernel->timeOut/2; ++ ++#if gcdENABLE_VG ++ if (kernel->core == gcvCORE_VG) ++ { ++ return; ++ } ++#endif ++ ++ if (kernel->monitorTimerStop) ++ { ++ /* Stop. */ ++ return; ++ } ++ ++ gckOS_AtomGet(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt); ++ ++ if (kernel->monitoring == gcvFALSE) ++ { ++ if (pendingInterrupt) ++ { ++ /* Begin to mointor GPU state. */ ++ kernel->monitoring = gcvTRUE; ++ ++ /* Record current state. */ ++ kernel->lastCommitStamp = kernel->eventObj->lastCommitStamp; ++ kernel->restoreAddress = kernel->hardware->lastWaitLink; ++ gcmkVERIFY_OK(gckOS_AtomGet( ++ kernel->os, ++ kernel->hardware->pendingEvent, ++ &kernel->restoreMask ++ )); ++ ++ /* Clear timeout. */ ++ kernel->timer = 0; ++ } ++ } ++ else ++ { ++ if (pendingInterrupt) ++ { ++ gcmkVERIFY_OK(gckOS_AtomGet( ++ kernel->os, ++ kernel->hardware->pendingEvent, ++ &mask ++ )); ++ ++ if (kernel->eventObj->lastCommitStamp == kernel->lastCommitStamp ++ && kernel->hardware->lastWaitLink == kernel->restoreAddress ++ && mask == kernel->restoreMask ++ ) ++ { ++ /* GPU state is not changed, accumlate timeout. */ ++ kernel->timer += advance; ++ ++ if (kernel->timer >= kernel->timeOut) ++ { ++ /* GPU stuck, trigger reset. */ ++ reset = gcvTRUE; ++ } ++ } ++ else ++ { ++ /* GPU state changed, cancel current timeout.*/ ++ kernel->monitoring = gcvFALSE; ++ } ++ } ++ else ++ { ++ /* GPU finish all jobs, cancel current timeout*/ ++ kernel->monitoring = gcvFALSE; ++ } ++ } ++ ++ if (reset) ++ { ++ gckKERNEL_Recovery(kernel); ++ ++ /* Work in this timeout is done. */ ++ kernel->monitoring = gcvFALSE; ++ } ++ ++ gcmkVERIFY_OK(gckOS_StartTimer(kernel->os, kernel->monitorTimer, advance)); ++} ++#endif ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gceSTATUS ++_MapCommandBuffer( ++ IN gckKERNEL Kernel ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 i; ++ gctUINT32 physical; ++ gckMMU mmu; ++ ++ gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu)); ++ ++ for (i = 0; i < gcdCOMMAND_QUEUES; i++) ++ { ++ gcmkONERROR(gckOS_GetPhysicalAddress( ++ Kernel->os, ++ Kernel->command->queues[i].logical, ++ &physical ++ )); ++ ++ gcmkONERROR(gckMMU_FlatMapping(mmu, physical)); ++ } ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++#endif ++ ++void ++_DumpDriverConfigure( ++ IN gckKERNEL Kernel ++ ) ++{ ++ gcmkPRINT_N(0, "**************************\n"); ++ gcmkPRINT_N(0, "*** GPU DRV CONFIG ***\n"); ++ gcmkPRINT_N(0, "**************************\n"); ++ ++ gcmkPRINT("Galcore version %d.%d.%d.%d\n", ++ gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD); ++ ++ gckOS_DumpParam(); ++} ++ ++void ++_DumpState( ++ IN gckKERNEL Kernel ++ ) ++{ ++ /* Dump GPU Debug registers. */ ++ gcmkVERIFY_OK(gckHARDWARE_DumpGPUState(Kernel->hardware)); ++ ++ if (Kernel->virtualCommandBuffer) ++ { ++ gcmkVERIFY_OK(gckCOMMAND_DumpExecutingBuffer(Kernel->command)); ++ } ++ ++ /* Dump Pending event. */ ++ gcmkVERIFY_OK(gckEVENT_Dump(Kernel->eventObj)); ++ ++ /* Dump Process DB. */ ++ gcmkVERIFY_OK(gckKERNEL_DumpProcessDB(Kernel)); ++ ++#if gcdRECORD_COMMAND ++ /* Dump record. */ ++ gckRECORDER_Dump(Kernel->command->recorder); ++#endif ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_Construct ++** ++** Construct a new gckKERNEL object. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gceCORE Core ++** Specified core. ++** ++** IN gctPOINTER Context ++** Pointer to a driver defined context. ++** ++** IN gckDB SharedDB, ++** Pointer to a shared DB. ++** ++** OUTPUT: ++** ++** gckKERNEL * Kernel ++** Pointer to a variable that will hold the pointer to the gckKERNEL ++** object. ++*/ ++ ++gceSTATUS ++gckKERNEL_Construct( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPOINTER Context, ++ IN gckDB SharedDB, ++ OUT gckKERNEL * Kernel ++ ) ++{ ++ gckKERNEL kernel = gcvNULL; ++ gceSTATUS status; ++ gctSIZE_T i; ++ gctPOINTER pointer = gcvNULL; ++ ++ gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); ++ ++ /* Allocate the gckKERNEL object. */ ++ gcmkONERROR(gckOS_Allocate(Os, ++ gcmSIZEOF(struct _gckKERNEL), ++ &pointer)); ++ ++ kernel = pointer; ++ ++ /* Zero the object pointers. */ ++ kernel->hardware = gcvNULL; ++ kernel->command = gcvNULL; ++ kernel->eventObj = gcvNULL; ++ kernel->mmu = gcvNULL; ++#if gcdDVFS ++ kernel->dvfs = gcvNULL; ++#endif ++ kernel->monitorTimer = gcvNULL; ++ ++ /* Initialize the gckKERNEL object. */ ++ kernel->object.type = gcvOBJ_KERNEL; ++ kernel->os = Os; ++ kernel->core = Core; ++ ++ if (SharedDB == gcvNULL) ++ { ++ gcmkONERROR(gckOS_Allocate(Os, ++ gcmSIZEOF(struct _gckDB), ++ &pointer)); ++ ++ kernel->db = pointer; ++ kernel->dbCreated = gcvTRUE; ++ kernel->db->freeDatabase = gcvNULL; ++ kernel->db->freeRecord = gcvNULL; ++ kernel->db->dbMutex = gcvNULL; ++ kernel->db->lastDatabase = gcvNULL; ++ kernel->db->idleTime = 0; ++ kernel->db->lastIdle = 0; ++ kernel->db->lastSlowdown = 0; ++ ++ for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i) ++ { ++ kernel->db->db[i] = gcvNULL; ++ } ++ ++ /* Construct a database mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->dbMutex)); ++ ++ /* Construct a video memory name database. */ ++ gcmkONERROR(gckKERNEL_CreateIntegerDatabase(kernel, &kernel->db->nameDatabase)); ++ ++ /* Construct a video memory name database mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->nameDatabaseMutex)); ++ ++ /* Construct a pointer name database. */ ++ gcmkONERROR(gckKERNEL_CreateIntegerDatabase(kernel, &kernel->db->pointerDatabase)); ++ ++ /* Construct a pointer name database mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->pointerDatabaseMutex)); ++ } ++ else ++ { ++ kernel->db = SharedDB; ++ kernel->dbCreated = gcvFALSE; ++ } ++ ++ for (i = 0; i < gcmCOUNTOF(kernel->timers); ++i) ++ { ++ kernel->timers[i].startTime = 0; ++ kernel->timers[i].stopTime = 0; ++ } ++ ++ /* Save context. */ ++ kernel->context = Context; ++ ++ /* Construct atom holding number of clients. */ ++ kernel->atomClients = gcvNULL; ++ gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients)); ++ ++#if gcdENABLE_VG ++ kernel->vg = gcvNULL; ++ ++ if (Core == gcvCORE_VG) ++ { ++ /* Construct the gckMMU object. */ ++ gcmkONERROR( ++ gckVGKERNEL_Construct(Os, Context, kernel, &kernel->vg)); ++ ++ kernel->timeOut = gcdGPU_TIMEOUT; ++ } ++ else ++#endif ++ { ++ /* Construct the gckHARDWARE object. */ ++ gcmkONERROR( ++ gckHARDWARE_Construct(Os, kernel->core, &kernel->hardware)); ++ ++ /* Set pointer to gckKERNEL object in gckHARDWARE object. */ ++ kernel->hardware->kernel = kernel; ++ ++ kernel->timeOut = kernel->hardware->type == gcvHARDWARE_2D ++ ? gcdGPU_2D_TIMEOUT ++ : gcdGPU_TIMEOUT ++ ; ++ ++ /* Initialize virtual command buffer. */ ++ kernel->virtualCommandBuffer = gcvTRUE; ++ ++ /* Construct the gckCOMMAND object. */ ++ gcmkONERROR( ++ gckCOMMAND_Construct(kernel, &kernel->command)); ++ ++ /* Construct the gckEVENT object. */ ++ gcmkONERROR( ++ gckEVENT_Construct(kernel, &kernel->eventObj)); ++ ++ /* Construct the gckMMU object. */ ++ gcmkONERROR( ++ gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu)); ++ ++ gcmkVERIFY_OK(gckOS_GetTime(&kernel->resetTimeStamp)); ++ ++ gcmkONERROR(gckHARDWARE_PrepareFunctions(kernel->hardware)); ++ ++ /* Initialize the hardware. */ ++ gcmkONERROR( ++ gckHARDWARE_InitializeHardware(kernel->hardware)); ++ ++#if gcdDVFS ++ if (gckHARDWARE_IsFeatureAvailable(kernel->hardware, ++ gcvFEATURE_DYNAMIC_FREQUENCY_SCALING)) ++ { ++ gcmkONERROR(gckDVFS_Construct(kernel->hardware, &kernel->dvfs)); ++ gcmkONERROR(gckDVFS_Start(kernel->dvfs)); ++ } ++#endif ++ } ++ ++ spin_lock_init(&kernel->irq_lock); ++ ++#if VIVANTE_PROFILER ++ /* Initialize profile setting */ ++ kernel->profileEnable = gcvFALSE; ++ kernel->profileCleanRegister = gcvTRUE; ++#endif ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ gcmkONERROR(gckOS_CreateSyncTimeline(Os, &kernel->timeline)); ++#endif ++ ++ kernel->recovery = gcvTRUE; ++ kernel->stuckDump = 1; ++ ++ kernel->virtualBufferHead = ++ kernel->virtualBufferTail = gcvNULL; ++ ++ gcmkONERROR( ++ gckOS_CreateMutex(Os, (gctPOINTER)&kernel->virtualBufferLock)); ++ ++#if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC ++ if (kernel->timeOut) ++ { ++ gcmkVERIFY_OK(gckOS_CreateTimer( ++ Os, ++ (gctTIMERFUNCTION)_MonitorTimerFunction, ++ (gctPOINTER)kernel, ++ &kernel->monitorTimer ++ )); ++ ++ kernel->monitoring = gcvFALSE; ++ ++ kernel->monitorTimerStop = gcvFALSE; ++ ++ gcmkVERIFY_OK(gckOS_StartTimer( ++ Os, ++ kernel->monitorTimer, ++ 100 ++ )); ++ } ++#endif ++ ++ /* Return pointer to the gckKERNEL object. */ ++ *Kernel = kernel; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (kernel != gcvNULL) ++ { ++#if gcdENABLE_VG ++ if (Core != gcvCORE_VG) ++#endif ++ { ++ if (kernel->eventObj != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckEVENT_Destroy(kernel->eventObj)); ++ } ++ ++ if (kernel->command != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckCOMMAND_Destroy(kernel->command)); ++ } ++ ++ if (kernel->hardware != gcvNULL) ++ { ++ /* Turn off the power. */ ++ gcmkVERIFY_OK(gckOS_SetGPUPower(kernel->hardware->os, ++ kernel->hardware->core, ++ gcvFALSE, ++ gcvFALSE)); ++ gcmkVERIFY_OK(gckHARDWARE_Destroy(kernel->hardware)); ++ } ++ } ++ ++ if (kernel->atomClients != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Os, kernel->atomClients)); ++ } ++ ++ if (kernel->dbCreated && kernel->db != gcvNULL) ++ { ++ if (kernel->db->dbMutex != gcvNULL) ++ { ++ /* Destroy the database mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, kernel->db->dbMutex)); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, kernel->db)); ++ } ++ ++ if (kernel->virtualBufferLock != gcvNULL) ++ { ++ /* Destroy the virtual command buffer mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, kernel->virtualBufferLock)); ++ } ++ ++#if gcdDVFS ++ if (kernel->dvfs) ++ { ++ gcmkVERIFY_OK(gckDVFS_Stop(kernel->dvfs)); ++ gcmkVERIFY_OK(gckDVFS_Destroy(kernel->dvfs)); ++ } ++#endif ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ if (kernel->timeline) ++ { ++ gcmkVERIFY_OK(gckOS_DestroySyncTimeline(Os, kernel->timeline)); ++ } ++#endif ++ ++ if (kernel->monitorTimer) ++ { ++ gcmkVERIFY_OK(gckOS_StopTimer(Os, kernel->monitorTimer)); ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Os, kernel->monitorTimer)); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, kernel)); ++ } ++ ++ /* Return the error. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_Destroy ++** ++** Destroy an gckKERNEL object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object to destroy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_Destroy( ++ IN gckKERNEL Kernel ++ ) ++{ ++ gctSIZE_T i; ++ gcsDATABASE_PTR database, databaseNext; ++ gcsDATABASE_RECORD_PTR record, recordNext; ++ ++ gcmkHEADER_ARG("Kernel=0x%x", Kernel); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Destroy the database. */ ++ if (Kernel->dbCreated) ++ { ++ for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i) ++ { ++ if (Kernel->db->db[i] != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckKERNEL_DestroyProcessDB(Kernel, Kernel->db->db[i]->processID)); ++ } ++ } ++ ++ /* Free all databases. */ ++ for (database = Kernel->db->freeDatabase; ++ database != gcvNULL; ++ database = databaseNext) ++ { ++ databaseNext = database->next; ++ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->counterMutex)); ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, database)); ++ } ++ ++ if (Kernel->db->lastDatabase != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->lastDatabase->counterMutex)); ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db->lastDatabase)); ++ } ++ ++ /* Free all database records. */ ++ for (record = Kernel->db->freeRecord; record != gcvNULL; record = recordNext) ++ { ++ recordNext = record->next; ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record)); ++ } ++ ++ /* Destroy the database mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Destroy video memory name database. */ ++ gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->nameDatabase)); ++ ++ /* Destroy video memory name database mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->nameDatabaseMutex)); ++ ++ ++ /* Destroy id-pointer database. */ ++ gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->pointerDatabase)); ++ ++ /* Destroy id-pointer database mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ ++ /* Destroy the database. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db)); ++ ++ /* Notify stuck timer to quit. */ ++ Kernel->monitorTimerStop = gcvTRUE; ++ } ++ ++#if gcdENABLE_VG ++ if (Kernel->vg) ++ { ++ gcmkVERIFY_OK(gckVGKERNEL_Destroy(Kernel->vg)); ++ } ++ else ++#endif ++ { ++ /* Destroy the gckMMU object. */ ++ gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu)); ++ ++ /* Destroy the gckCOMMNAND object. */ ++ gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command)); ++ ++ /* Destroy the gckEVENT object. */ ++ gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->eventObj)); ++ ++ /* Destroy the gckHARDWARE object. */ ++ gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware)); ++ } ++ ++ /* Detsroy the client atom. */ ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients)); ++ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->virtualBufferLock)); ++ ++#if gcdDVFS ++ if (Kernel->dvfs) ++ { ++ gcmkVERIFY_OK(gckDVFS_Stop(Kernel->dvfs)); ++ gcmkVERIFY_OK(gckDVFS_Destroy(Kernel->dvfs)); ++ } ++#endif ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ gcmkVERIFY_OK(gckOS_DestroySyncTimeline(Kernel->os, Kernel->timeline)); ++#endif ++ ++ if (Kernel->monitorTimer) ++ { ++ gcmkVERIFY_OK(gckOS_StopTimer(Kernel->os, Kernel->monitorTimer)); ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Kernel->os, Kernel->monitorTimer)); ++ } ++ ++ /* Mark the gckKERNEL object as unknown. */ ++ Kernel->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckKERNEL object. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** _AllocateMemory ++** ++** Private function to walk all required memory pools to allocate the requested ++** amount of video memory. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that defines the command to ++** be dispatched. ++** ++** OUTPUT: ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that receives any data to be ++** returned. ++*/ ++gceSTATUS ++gckKERNEL_AllocateLinearMemory( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN OUT gcePOOL * Pool, ++ IN gctSIZE_T Bytes, ++ IN gctUINT32 Alignment, ++ IN gceSURF_TYPE Type, ++ IN gctUINT32 Flag, ++ OUT gctUINT32 * Node ++ ) ++{ ++ gcePOOL pool; ++ gceSTATUS status; ++ gckVIDMEM videoMemory; ++ gctINT loopCount; ++ gcuVIDMEM_NODE_PTR node = gcvNULL; ++ gctBOOL tileStatusInVirtual; ++ gctBOOL contiguous = gcvFALSE; ++ gctBOOL cacheable = gcvFALSE; ++ gctSIZE_T bytes = Bytes; ++ gctUINT32 handle = 0; ++ gceDATABASE_TYPE type; ++ ++ gcmkHEADER_ARG("Kernel=0x%x *Pool=%d Bytes=%lu Alignment=%lu Type=%d", ++ Kernel, *Pool, Bytes, Alignment, Type); ++ ++ gcmkVERIFY_ARGUMENT(Pool != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes != 0); ++ ++ /* Get basic type. */ ++ Type &= 0xFF; ++ ++ /* Check flags. */ ++ contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS; ++ cacheable = Flag & gcvALLOC_FLAG_CACHEABLE; ++ ++AllocateMemory: ++ ++ /* Get initial pool. */ ++ switch (pool = *Pool) ++ { ++ case gcvPOOL_DEFAULT: ++ case gcvPOOL_LOCAL: ++ pool = gcvPOOL_LOCAL_INTERNAL; ++ loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS; ++ break; ++ ++ case gcvPOOL_UNIFIED: ++ pool = gcvPOOL_SYSTEM; ++ loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS; ++ break; ++ ++ case gcvPOOL_CONTIGUOUS: ++ loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS; ++ break; ++ ++ default: ++ loopCount = 1; ++ break; ++ } ++ ++ while (loopCount-- > 0) ++ { ++ if (pool == gcvPOOL_VIRTUAL) ++ { ++ /* Create a gcuVIDMEM_NODE for virtual memory. */ ++ gcmkONERROR( ++ gckVIDMEM_ConstructVirtual(Kernel, Flag | gcvALLOC_FLAG_NON_CONTIGUOUS, Bytes, &node)); ++ ++ bytes = node->Virtual.bytes; ++ node->Virtual.type = Type; ++ ++ /* Success. */ ++ break; ++ } ++ ++ else ++ if (pool == gcvPOOL_CONTIGUOUS) ++ { ++#if gcdCONTIGUOUS_SIZE_LIMIT ++ if (Bytes > gcdCONTIGUOUS_SIZE_LIMIT && contiguous == gcvFALSE) ++ { ++ status = gcvSTATUS_OUT_OF_MEMORY; ++ } ++ else ++#endif ++ { ++ /* Create a gcuVIDMEM_NODE from contiguous memory. */ ++ status = gckVIDMEM_ConstructVirtual( ++ Kernel, ++ Flag | gcvALLOC_FLAG_CONTIGUOUS, ++ Bytes, ++ &node); ++ } ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ bytes = node->Virtual.bytes; ++ node->Virtual.type = Type; ++ ++ /* Memory allocated. */ ++ break; ++ } ++ } ++ ++ else ++ /* gcvPOOL_SYSTEM can't be cacheable. */ ++ if (cacheable == gcvFALSE) ++ { ++ /* Get pointer to gckVIDMEM object for pool. */ ++ status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ /* Allocate memory. */ ++#if defined(gcdLINEAR_SIZE_LIMIT) ++ /* 512 KB */ ++ if (Bytes > gcdLINEAR_SIZE_LIMIT) ++ { ++ status = gcvSTATUS_OUT_OF_MEMORY; ++ } ++ else ++#endif ++ { ++ status = gckVIDMEM_AllocateLinear(Kernel, ++ videoMemory, ++ Bytes, ++ Alignment, ++ Type, ++ (*Pool == gcvPOOL_SYSTEM), ++ &node); ++ } ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ /* Memory allocated. */ ++ node->VidMem.pool = pool; ++ bytes = node->VidMem.bytes; ++ break; ++ } ++ } ++ } ++ ++ if (pool == gcvPOOL_LOCAL_INTERNAL) ++ { ++ /* Advance to external memory. */ ++ pool = gcvPOOL_LOCAL_EXTERNAL; ++ } ++ ++ else ++ if (pool == gcvPOOL_LOCAL_EXTERNAL) ++ { ++ /* Advance to contiguous system memory. */ ++ pool = gcvPOOL_SYSTEM; ++ } ++ ++ else ++ if (pool == gcvPOOL_SYSTEM) ++ { ++ /* Advance to contiguous memory. */ ++ pool = gcvPOOL_CONTIGUOUS; ++ } ++ ++ else ++ if (pool == gcvPOOL_CONTIGUOUS) ++ { ++#if gcdENABLE_VG ++ if (Kernel->vg) ++ { ++ tileStatusInVirtual = gcvFALSE; ++ } ++ else ++#endif ++ { ++ tileStatusInVirtual = ++ gckHARDWARE_IsFeatureAvailable(Kernel->hardware, ++ gcvFEATURE_MC20); ++ } ++ ++ if (Type == gcvSURF_TILE_STATUS && tileStatusInVirtual != gcvTRUE) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ if (contiguous) ++ { ++ break; ++ } ++ ++ /* Advance to virtual memory. */ ++ pool = gcvPOOL_VIRTUAL; ++ } ++ ++ else ++ { ++ /* Out of pools. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ } ++ ++ if (node == gcvNULL) ++ { ++ if (contiguous) ++ { ++ /* Broadcast OOM message. */ ++ status = gckOS_Broadcast(Kernel->os, Kernel->hardware, gcvBROADCAST_OUT_OF_MEMORY); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ /* Get some memory. */ ++ gckOS_Delay(gcvNULL, 1); ++ goto AllocateMemory; ++ } ++ } ++ ++ /* Nothing allocated. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Allocate handle for this video memory. */ ++ gcmkONERROR( ++ gckVIDMEM_NODE_Allocate(Kernel, node, Type, pool, &handle)); ++ ++ /* Return node and pool used for allocation. */ ++ *Node = handle; ++ *Pool = pool; ++ ++ /* Encode surface type and pool to database type. */ ++ type = gcvDB_VIDEO_MEMORY ++ | (Type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT) ++ | (pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT); ++ ++ /* Record in process db. */ ++ gcmkONERROR( ++ gckKERNEL_AddProcessDB(Kernel, ++ ProcessID, ++ type, ++ gcmINT2PTR(handle), ++ gcvNULL, ++ bytes)); ++ ++ /* Return status. */ ++ gcmkFOOTER_ARG("*Pool=%d *Node=0x%x", *Pool, *Node); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (handle) ++ { ++ /* Destroy handle allocated. */ ++ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, handle)); ++ } ++ ++ if (node) ++ { ++ /* Free video memory allocated. */ ++ gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, node)); ++ } ++ ++ /* For some case like chrome with webgl test, it needs too much memory so that it invokes oom_killer ++ * And the case is killed by oom_killer, the user wants not to see the crash and hope the case iteself handles the condition ++ * So the patch reports the out_of_memory to the case */ ++ if ( status == gcvSTATUS_OUT_OF_MEMORY && (Flag & gcvALLOC_FLAG_MEMLIMIT) ) ++ gcmkPRINT("The running case is out_of_memory"); ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_ReleaseVideoMemory ++** ++** Release handle of a video memory. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** ProcessID of current process. ++** ++** gctUINT32 Handle ++** Handle of video memory. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_ReleaseVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE nodeObject; ++ gceDATABASE_TYPE type; ++ ++ gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d Handle=%d", ++ Kernel, ProcessID, Handle); ++ ++ gcmkONERROR( ++ gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, Handle, &nodeObject)); ++ ++ type = gcvDB_VIDEO_MEMORY ++ | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT) ++ | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT); ++ ++ gcmkONERROR( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ ProcessID, ++ type, ++ gcmINT2PTR(Handle))); ++ ++ gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, Handle); ++ ++ gckVIDMEM_NODE_Dereference(Kernel, nodeObject); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_LockVideoMemory ++** ++** Lock a video memory node. It will generate a cpu virtual address used ++** by software and a GPU address used by GPU. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gceCORE Core ++** GPU to which video memory is locked. ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that defines the command to ++** be dispatched. ++** ++** OUTPUT: ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that receives any data to be ++** returned. ++*/ ++gceSTATUS ++gckKERNEL_LockVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gceCORE Core, ++ IN gctUINT32 ProcessID, ++ IN gctBOOL FromUser, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE nodeObject = gcvNULL; ++ gcuVIDMEM_NODE_PTR node = gcvNULL; ++ gctBOOL locked = gcvFALSE; ++ gctBOOL asynchronous = gcvFALSE; ++ gctPOINTER pointer = gcvNULL; ++ ++ gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d", ++ Kernel, ProcessID); ++ ++ gcmkONERROR( ++ gckVIDMEM_HANDLE_LookupAndReference(Kernel, ++ Interface->u.LockVideoMemory.node, ++ &nodeObject)); ++ ++ node = nodeObject->node; ++ ++ Interface->u.LockVideoMemory.gid = 0; ++ ++ /* Lock video memory. */ ++ gcmkONERROR( ++ gckVIDMEM_Lock(Kernel, ++ nodeObject, ++ Interface->u.LockVideoMemory.cacheable, ++ &Interface->u.LockVideoMemory.address, ++ &Interface->u.LockVideoMemory.gid, ++ &Interface->u.LockVideoMemory.physicalAddress)); ++ ++ locked = gcvTRUE; ++ ++ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ++ { ++ /* Map video memory address into user space. */ ++ gcmkONERROR( ++ gckKERNEL_MapVideoMemoryEx(Kernel, ++ Core, ++ FromUser, ++ Interface->u.LockVideoMemory.address, ++ &pointer)); ++ ++ Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(pointer); ++ } ++ else ++ { ++ Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(node->Virtual.logical); ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ } ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkONERROR(gckVIDMEM_Node_Lock( ++ Kernel, ++ nodeObject, ++ &Interface->u.LockVideoMemory.address ++ )); ++#endif ++ ++ ++ gcmkONERROR( ++ gckKERNEL_AddProcessDB(Kernel, ++ ProcessID, gcvDB_VIDEO_MEMORY_LOCKED, ++ gcmINT2PTR(Interface->u.LockVideoMemory.node), ++ gcvNULL, ++ 0)); ++ ++ gckVIDMEM_HANDLE_Reference( ++ Kernel, ProcessID, (gctUINT32)Interface->u.LockVideoMemory.node); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (locked) ++ { ++ /* Roll back the lock. */ ++ gcmkVERIFY_OK(gckVIDMEM_Unlock(Kernel, ++ nodeObject, ++ gcvSURF_TYPE_UNKNOWN, ++ &asynchronous)); ++ ++ if (gcvTRUE == asynchronous) ++ { ++ /* Bottom Half */ ++ gcmkVERIFY_OK(gckVIDMEM_Unlock(Kernel, ++ nodeObject, ++ gcvSURF_TYPE_UNKNOWN, ++ gcvNULL)); ++ } ++ } ++ ++ if (nodeObject != gcvNULL) ++ { ++ gckVIDMEM_NODE_Dereference(Kernel, nodeObject); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_UnlockVideoMemory ++** ++** Unlock a video memory node. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** ProcessID of current process. ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that defines the command to ++** be dispatched. ++** ++** OUTPUT: ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that receives any data to be ++** returned. ++*/ ++gceSTATUS ++gckKERNEL_UnlockVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE nodeObject; ++ gcuVIDMEM_NODE_PTR node; ++ ++ gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d", ++ Kernel, ProcessID); ++ ++ gcmkONERROR(gckVIDMEM_HANDLE_Lookup( ++ Kernel, ++ ProcessID, ++ (gctUINT32)Interface->u.UnlockVideoMemory.node, ++ &nodeObject)); ++ ++ node = nodeObject->node; ++ ++ /* Unlock video memory. */ ++ gcmkONERROR(gckVIDMEM_Unlock( ++ Kernel, ++ nodeObject, ++ Interface->u.UnlockVideoMemory.type, ++ &Interface->u.UnlockVideoMemory.asynchroneous)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_QueryDatabase( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ) ++{ ++ gceSTATUS status; ++ gctINT i; ++ gcuDATABASE_INFO tmp; ++ ++ gceDATABASE_TYPE type[3] = { ++ gcvDB_VIDEO_MEMORY | (gcvPOOL_SYSTEM << gcdDB_VIDEO_MEMORY_POOL_SHIFT), ++ gcvDB_VIDEO_MEMORY | (gcvPOOL_CONTIGUOUS << gcdDB_VIDEO_MEMORY_POOL_SHIFT), ++ gcvDB_VIDEO_MEMORY | (gcvPOOL_VIRTUAL << gcdDB_VIDEO_MEMORY_POOL_SHIFT), ++ }; ++ ++ gcmkHEADER(); ++ ++ /* Query video memory. */ ++ gcmkONERROR( ++ gckKERNEL_QueryProcessDB(Kernel, ++ Interface->u.Database.processID, ++ !Interface->u.Database.validProcessID, ++ gcvDB_VIDEO_MEMORY, ++ &Interface->u.Database.vidMem)); ++ ++ /* Query non-paged memory. */ ++ gcmkONERROR( ++ gckKERNEL_QueryProcessDB(Kernel, ++ Interface->u.Database.processID, ++ !Interface->u.Database.validProcessID, ++ gcvDB_NON_PAGED, ++ &Interface->u.Database.nonPaged)); ++ ++ /* Query contiguous memory. */ ++ gcmkONERROR( ++ gckKERNEL_QueryProcessDB(Kernel, ++ Interface->u.Database.processID, ++ !Interface->u.Database.validProcessID, ++ gcvDB_CONTIGUOUS, ++ &Interface->u.Database.contiguous)); ++ ++ /* Query GPU idle time. */ ++ gcmkONERROR( ++ gckKERNEL_QueryProcessDB(Kernel, ++ Interface->u.Database.processID, ++ !Interface->u.Database.validProcessID, ++ gcvDB_IDLE, ++ &Interface->u.Database.gpuIdle)); ++ for (i = 0; i < 3; i++) ++ { ++ /* Query each video memory pool. */ ++ gcmkONERROR( ++ gckKERNEL_QueryProcessDB(Kernel, ++ Interface->u.Database.processID, ++ !Interface->u.Database.validProcessID, ++ type[i], ++ &Interface->u.Database.vidMemPool[i])); ++ } ++ ++ /* Query virtual command buffer pool. */ ++ gcmkONERROR( ++ gckKERNEL_QueryProcessDB(Kernel, ++ Interface->u.Database.processID, ++ !Interface->u.Database.validProcessID, ++ gcvDB_COMMAND_BUFFER, ++ &tmp)); ++ ++ Interface->u.Database.vidMemPool[2].counters.bytes += tmp.counters.bytes; ++ Interface->u.Database.vidMemPool[2].counters.maxBytes += tmp.counters.maxBytes; ++ Interface->u.Database.vidMemPool[2].counters.totalBytes += tmp.counters.totalBytes; ++ ++ Interface->u.Database.vidMem.counters.bytes += tmp.counters.bytes; ++ Interface->u.Database.vidMem.counters.maxBytes += tmp.counters.maxBytes; ++ Interface->u.Database.vidMem.counters.totalBytes += tmp.counters.totalBytes; ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gckKERNEL_DumpVidMemUsage(Kernel, Interface->u.Database.processID); ++#endif ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_ConfigPowerManagement( ++ IN gckKERNEL Kernel, ++ IN OUT gcsHAL_INTERFACE * Interface ++) ++{ ++ gceSTATUS status; ++ gctBOOL enable = Interface->u.ConfigPowerManagement.enable; ++ ++ gcmkHEADER(); ++ ++ gcmkONERROR(gckHARDWARE_SetPowerManagement(Kernel->hardware, enable)); ++ ++ if (enable == gcvTRUE) ++ { ++ gcmkONERROR( ++ gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_ON)); ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_Dispatch ++** ++** Dispatch a command received from the user HAL layer. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctBOOL FromUser ++** whether the call is from the user space. ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that defines the command to ++** be dispatched. ++** ++** OUTPUT: ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that receives any data to be ++** returned. ++*/ ++gceSTATUS ++gckKERNEL_Dispatch( ++ IN gckKERNEL Kernel, ++ IN gctBOOL FromUser, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gctPHYS_ADDR physical = gcvNULL; ++ gctSIZE_T bytes; ++ gctPOINTER logical = gcvNULL; ++ gctPOINTER info = gcvNULL; ++#if (gcdENABLE_3D || gcdENABLE_2D) ++ gckCONTEXT context = gcvNULL; ++#endif ++ gckKERNEL kernel = Kernel; ++ gctUINT32 address; ++ gctUINT32 processID; ++ gctUINT32 paddr = gcvINVALID_ADDRESS; ++ gctSIGNAL signal; ++ gckVIRTUAL_COMMAND_BUFFER_PTR buffer; ++ ++ gckVIDMEM_NODE nodeObject; ++ gctBOOL powerMutexAcquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%x FromUser=%d Interface=0x%x", ++ Kernel, FromUser, Interface); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Interface != gcvNULL); ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, ++ "Dispatching command %d (%s)", ++ Interface->command, _DispatchText[Interface->command]); ++#endif ++ ++ /* Get the current process ID. */ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ /* Dispatch on command. */ ++ switch (Interface->command) ++ { ++ case gcvHAL_GET_BASE_ADDRESS: ++ /* Get base address. */ ++ gcmkONERROR( ++ gckOS_GetBaseAddress(Kernel->os, ++ &Interface->u.GetBaseAddress.baseAddress)); ++ break; ++ ++ case gcvHAL_QUERY_VIDEO_MEMORY: ++ /* Query video memory size. */ ++ gcmkONERROR(gckKERNEL_QueryVideoMemory(Kernel, Interface)); ++ break; ++ ++ case gcvHAL_QUERY_CHIP_IDENTITY: ++ /* Query chip identity. */ ++ gcmkONERROR( ++ gckHARDWARE_QueryChipIdentity( ++ Kernel->hardware, ++ &Interface->u.QueryChipIdentity)); ++ break; ++ ++ case gcvHAL_MAP_MEMORY: ++ physical = gcmINT2PTR(Interface->u.MapMemory.physical); ++ ++ /* Map memory. */ ++ gcmkONERROR( ++ gckKERNEL_MapMemory(Kernel, ++ physical, ++ (gctSIZE_T) Interface->u.MapMemory.bytes, ++ &logical)); ++ ++ Interface->u.MapMemory.logical = gcmPTR_TO_UINT64(logical); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_MAP_MEMORY, ++ logical, ++ physical, ++ (gctSIZE_T) Interface->u.MapMemory.bytes)); ++ break; ++ ++ case gcvHAL_UNMAP_MEMORY: ++ physical = gcmINT2PTR(Interface->u.UnmapMemory.physical); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, gcvDB_MAP_MEMORY, ++ gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical))); ++ ++ /* Unmap memory. */ ++ gcmkONERROR( ++ gckKERNEL_UnmapMemory(Kernel, ++ physical, ++ (gctSIZE_T) Interface->u.UnmapMemory.bytes, ++ gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical))); ++ break; ++ ++ case gcvHAL_ALLOCATE_NON_PAGED_MEMORY: ++ bytes = (gctSIZE_T) Interface->u.AllocateNonPagedMemory.bytes; ++ ++ /* Allocate non-paged memory. */ ++ gcmkONERROR( ++ gckOS_AllocateNonPagedMemory( ++ Kernel->os, ++ FromUser, ++ &bytes, ++ &physical, ++ &logical)); ++ ++ Interface->u.AllocateNonPagedMemory.bytes = bytes; ++ Interface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical); ++ Interface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_NON_PAGED, ++ logical, ++ gcmINT2PTR(Interface->u.AllocateNonPagedMemory.physical), ++ bytes)); ++ break; ++ ++ case gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER: ++ bytes = (gctSIZE_T) Interface->u.AllocateVirtualCommandBuffer.bytes; ++ ++ gcmkONERROR( ++ gckKERNEL_AllocateVirtualCommandBuffer( ++ Kernel, ++ FromUser, ++ &bytes, ++ &physical, ++ &logical)); ++ ++ Interface->u.AllocateVirtualCommandBuffer.bytes = bytes; ++ Interface->u.AllocateVirtualCommandBuffer.logical = gcmPTR_TO_UINT64(logical); ++ Interface->u.AllocateVirtualCommandBuffer.physical = gcmPTR_TO_NAME(physical); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_COMMAND_BUFFER, ++ logical, ++ gcmINT2PTR(Interface->u.AllocateVirtualCommandBuffer.physical), ++ bytes)); ++ break; ++ ++ case gcvHAL_FREE_NON_PAGED_MEMORY: ++ physical = gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, gcvDB_NON_PAGED, ++ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical))); ++ ++ /* Unmap user logical out of physical memory first. */ ++ gcmkONERROR(gckOS_UnmapUserLogical(Kernel->os, ++ physical, ++ (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes, ++ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical))); ++ ++ /* Free non-paged memory. */ ++ gcmkONERROR( ++ gckOS_FreeNonPagedMemory(Kernel->os, ++ (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes, ++ physical, ++ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical))); ++ ++ gcmRELEASE_NAME(Interface->u.FreeNonPagedMemory.physical); ++ break; ++ ++ case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY: ++ bytes = (gctSIZE_T) Interface->u.AllocateContiguousMemory.bytes; ++ ++ /* Allocate contiguous memory. */ ++ gcmkONERROR(gckOS_AllocateContiguous( ++ Kernel->os, ++ FromUser, ++ &bytes, ++ &physical, ++ &logical)); ++ ++ Interface->u.AllocateContiguousMemory.bytes = bytes; ++ Interface->u.AllocateContiguousMemory.logical = gcmPTR_TO_UINT64(logical); ++ Interface->u.AllocateContiguousMemory.physical = gcmPTR_TO_NAME(physical); ++ ++ gcmkONERROR(gckHARDWARE_ConvertLogical( ++ Kernel->hardware, ++ logical, ++ gcvTRUE, ++ &Interface->u.AllocateContiguousMemory.address)); ++ ++ gcmkVERIFY_OK(gckKERNEL_AddProcessDB( ++ Kernel, ++ processID, gcvDB_CONTIGUOUS, ++ logical, ++ gcmINT2PTR(Interface->u.AllocateContiguousMemory.physical), ++ bytes)); ++ break; ++ ++ case gcvHAL_FREE_CONTIGUOUS_MEMORY: ++ physical = gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, gcvDB_CONTIGUOUS, ++ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical))); ++ ++ /* Unmap user logical out of physical memory first. */ ++ gcmkONERROR(gckOS_UnmapUserLogical(Kernel->os, ++ physical, ++ (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes, ++ gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical))); ++ ++ /* Free contiguous memory. */ ++ gcmkONERROR( ++ gckOS_FreeContiguous(Kernel->os, ++ physical, ++ gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical), ++ (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes)); ++ ++ gcmRELEASE_NAME(Interface->u.FreeContiguousMemory.physical); ++ break; ++ ++ case gcvHAL_ALLOCATE_VIDEO_MEMORY: ++ ++ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); ++ ++ break; ++ ++ case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY: ++ /* Allocate memory. */ ++ gcmkONERROR( ++ gckKERNEL_AllocateLinearMemory(Kernel, processID, ++ &Interface->u.AllocateLinearVideoMemory.pool, ++ Interface->u.AllocateLinearVideoMemory.bytes, ++ Interface->u.AllocateLinearVideoMemory.alignment, ++ Interface->u.AllocateLinearVideoMemory.type, ++ Interface->u.AllocateLinearVideoMemory.flag, ++ &Interface->u.AllocateLinearVideoMemory.node)); ++ break; ++ ++ case gcvHAL_RELEASE_VIDEO_MEMORY: ++ /* Release video memory. */ ++ gcmkONERROR(gckKERNEL_ReleaseVideoMemory( ++ Kernel, processID, ++ (gctUINT32)Interface->u.ReleaseVideoMemory.node ++ )); ++ break; ++ ++ case gcvHAL_LOCK_VIDEO_MEMORY: ++ /* Lock video memory. */ ++ gcmkONERROR(gckKERNEL_LockVideoMemory(Kernel, Kernel->core, processID, FromUser, Interface)); ++ break; ++ ++ case gcvHAL_UNLOCK_VIDEO_MEMORY: ++ /* Unlock video memory. */ ++ gcmkONERROR(gckKERNEL_UnlockVideoMemory(Kernel, processID, Interface)); ++ break; ++ ++ case gcvHAL_EVENT_COMMIT: ++ /* Commit an event queue. */ ++ gcmkONERROR( ++ gckEVENT_Commit(Kernel->eventObj, ++ gcmUINT64_TO_PTR(Interface->u.Event.queue))); ++ break; ++ ++ case gcvHAL_COMMIT: ++ /* Commit a command and context buffer. */ ++ gcmkONERROR( ++ gckCOMMAND_Commit(Kernel->command, ++ Interface->u.Commit.context ? ++ gcmNAME_TO_PTR(Interface->u.Commit.context) : gcvNULL, ++ gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffer), ++ gcmUINT64_TO_PTR(Interface->u.Commit.delta), ++ gcmUINT64_TO_PTR(Interface->u.Commit.queue), ++ processID)); ++ ++ break; ++ ++ case gcvHAL_STALL: ++ /* Stall the command queue. */ ++ gcmkONERROR(gckCOMMAND_Stall(Kernel->command, gcvFALSE)); ++ break; ++ ++ case gcvHAL_MAP_USER_MEMORY: ++ /* Map user memory to DMA. */ ++ gcmkONERROR( ++ gckOS_MapUserMemory(Kernel->os, ++ Kernel->core, ++ gcmUINT64_TO_PTR(Interface->u.MapUserMemory.memory), ++ Interface->u.MapUserMemory.physical, ++ (gctSIZE_T) Interface->u.MapUserMemory.size, ++ &info, ++ &Interface->u.MapUserMemory.address)); ++ ++ Interface->u.MapUserMemory.info = gcmPTR_TO_NAME(info); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_MAP_USER_MEMORY, ++ gcmINT2PTR(Interface->u.MapUserMemory.info), ++ gcmUINT64_TO_PTR(Interface->u.MapUserMemory.memory), ++ (gctSIZE_T) Interface->u.MapUserMemory.size)); ++ break; ++ ++ case gcvHAL_UNMAP_USER_MEMORY: ++ address = Interface->u.UnmapUserMemory.address; ++ info = gcmNAME_TO_PTR(Interface->u.UnmapUserMemory.info); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, gcvDB_MAP_USER_MEMORY, ++ gcmINT2PTR(Interface->u.UnmapUserMemory.info))); ++ /* Unmap user memory. */ ++ gcmkONERROR( ++ gckOS_UnmapUserMemory(Kernel->os, ++ Kernel->core, ++ gcmUINT64_TO_PTR(Interface->u.UnmapUserMemory.memory), ++ (gctSIZE_T) Interface->u.UnmapUserMemory.size, ++ info, ++ address)); ++ ++ gcmRELEASE_NAME(Interface->u.UnmapUserMemory.info); ++ break; ++ ++ case gcvHAL_USER_SIGNAL: ++ /* Dispatch depends on the user signal subcommands. */ ++ switch(Interface->u.UserSignal.command) ++ { ++ case gcvUSER_SIGNAL_CREATE: ++ /* Create a signal used in the user space. */ ++ gcmkONERROR( ++ gckOS_CreateUserSignal(Kernel->os, ++ Interface->u.UserSignal.manualReset, ++ &Interface->u.UserSignal.id)); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_SIGNAL, ++ gcmINT2PTR(Interface->u.UserSignal.id), ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvUSER_SIGNAL_DESTROY: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Kernel, ++ processID, gcvDB_SIGNAL, ++ gcmINT2PTR(Interface->u.UserSignal.id))); ++ ++ /* Destroy the signal. */ ++ gcmkONERROR( ++ gckOS_DestroyUserSignal(Kernel->os, ++ Interface->u.UserSignal.id)); ++ break; ++ ++ case gcvUSER_SIGNAL_SIGNAL: ++ /* Signal the signal. */ ++ gcmkONERROR( ++ gckOS_SignalUserSignal(Kernel->os, ++ Interface->u.UserSignal.id, ++ Interface->u.UserSignal.state)); ++ break; ++ ++ case gcvUSER_SIGNAL_WAIT: ++ /* Wait on the signal. */ ++ status = gckOS_WaitUserSignal(Kernel->os, ++ Interface->u.UserSignal.id, ++ Interface->u.UserSignal.wait); ++ ++ break; ++ ++ case gcvUSER_SIGNAL_MAP: ++ gcmkONERROR( ++ gckOS_MapSignal(Kernel->os, ++ (gctSIGNAL)(gctUINTPTR_T)Interface->u.UserSignal.id, ++ (gctHANDLE)(gctUINTPTR_T)processID, ++ &signal)); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_SIGNAL, ++ gcmINT2PTR(Interface->u.UserSignal.id), ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvUSER_SIGNAL_UNMAP: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Kernel, ++ processID, gcvDB_SIGNAL, ++ gcmINT2PTR(Interface->u.UserSignal.id))); ++ ++ /* Destroy the signal. */ ++ gcmkONERROR( ++ gckOS_DestroyUserSignal(Kernel->os, ++ Interface->u.UserSignal.id)); ++ break; ++ ++ default: ++ /* Invalid user signal command. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ break; ++ ++ case gcvHAL_SET_POWER_MANAGEMENT_STATE: ++ /* Set the power management state. */ ++ gcmkONERROR( ++ gckHARDWARE_SetPowerManagementState( ++ Kernel->hardware, ++ Interface->u.SetPowerManagement.state)); ++ break; ++ ++ case gcvHAL_QUERY_POWER_MANAGEMENT_STATE: ++ /* Chip is not idle. */ ++ Interface->u.QueryPowerManagement.isIdle = gcvFALSE; ++ ++ /* Query the power management state. */ ++ gcmkONERROR(gckHARDWARE_QueryPowerManagementState( ++ Kernel->hardware, ++ &Interface->u.QueryPowerManagement.state)); ++ ++ /* Query the idle state. */ ++ gcmkONERROR( ++ gckHARDWARE_QueryIdle(Kernel->hardware, ++ &Interface->u.QueryPowerManagement.isIdle)); ++ break; ++ ++ case gcvHAL_READ_REGISTER: ++#if gcdREGISTER_ACCESS_FROM_USER ++ { ++ gceCHIPPOWERSTATE power; ++ ++ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE)); ++ powerMutexAcquired = gcvTRUE; ++ gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware, ++ &power)); ++ if (power == gcvPOWER_ON) ++ { ++ /* Read a register. */ ++ gcmkONERROR(gckOS_ReadRegisterEx( ++ Kernel->os, ++ Kernel->core, ++ Interface->u.ReadRegisterData.address, ++ &Interface->u.ReadRegisterData.data)); ++ } ++ else ++ { ++ /* Chip is in power-state. */ ++ Interface->u.ReadRegisterData.data = 0; ++ status = gcvSTATUS_CHIP_NOT_READY; ++ } ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex)); ++ powerMutexAcquired = gcvFALSE; ++ } ++#else ++ /* No access from user land to read registers. */ ++ Interface->u.ReadRegisterData.data = 0; ++ status = gcvSTATUS_NOT_SUPPORTED; ++#endif ++ break; ++ ++ case gcvHAL_WRITE_REGISTER: ++#if gcdREGISTER_ACCESS_FROM_USER ++ { ++ gceCHIPPOWERSTATE power; ++ ++ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE)); ++ powerMutexAcquired = gcvTRUE; ++ gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware, ++ &power)); ++ if (power == gcvPOWER_ON) ++ { ++ /* Write a register. */ ++ gcmkONERROR( ++ gckOS_WriteRegisterEx(Kernel->os, ++ Kernel->core, ++ Interface->u.WriteRegisterData.address, ++ Interface->u.WriteRegisterData.data)); ++ } ++ else ++ { ++ /* Chip is in power-state. */ ++ Interface->u.WriteRegisterData.data = 0; ++ status = gcvSTATUS_CHIP_NOT_READY; ++ } ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex)); ++ powerMutexAcquired = gcvFALSE; ++ } ++#else ++ /* No access from user land to write registers. */ ++ status = gcvSTATUS_NOT_SUPPORTED; ++#endif ++ break; ++ ++ case gcvHAL_READ_ALL_PROFILE_REGISTERS: ++#if VIVANTE_PROFILER && VIVANTE_PROFILER_CONTEXT ++ /* Read profile data according to the context. */ ++ gcmkONERROR( ++ gckHARDWARE_QueryContextProfile( ++ Kernel->hardware, ++ Kernel->profileCleanRegister, ++ gcmNAME_TO_PTR(Interface->u.RegisterProfileData.context), ++ &Interface->u.RegisterProfileData.counters)); ++#elif VIVANTE_PROFILER ++ /* Read all 3D profile registers. */ ++ gcmkONERROR( ++ gckHARDWARE_QueryProfileRegisters( ++ Kernel->hardware, ++ Kernel->profileCleanRegister, ++ &Interface->u.RegisterProfileData.counters)); ++#else ++ status = gcvSTATUS_OK; ++#endif ++ break; ++ ++ case gcvHAL_PROFILE_REGISTERS_2D: ++#if VIVANTE_PROFILER ++ /* Read all 2D profile registers. */ ++ gcmkONERROR( ++ gckHARDWARE_ProfileEngine2D( ++ Kernel->hardware, ++ gcmUINT64_TO_PTR(Interface->u.RegisterProfileData2D.hwProfile2D))); ++#else ++ status = gcvSTATUS_OK; ++#endif ++ break; ++ ++ case gcvHAL_GET_PROFILE_SETTING: ++#if VIVANTE_PROFILER ++ /* Get profile setting */ ++ Interface->u.GetProfileSetting.enable = Kernel->profileEnable; ++#endif ++ ++ status = gcvSTATUS_OK; ++ break; ++ ++ case gcvHAL_SET_PROFILE_SETTING: ++#if VIVANTE_PROFILER ++ /* Set profile setting */ ++ if(Kernel->hardware->gpuProfiler) ++ { ++ Kernel->profileEnable = Interface->u.SetProfileSetting.enable; ++#if VIVANTE_PROFILER_NEW ++ if (Kernel->profileEnable) ++ gckHARDWARE_InitProfiler(Kernel->hardware); ++#endif ++ } ++ else ++ { ++ status = gcvSTATUS_NOT_SUPPORTED; ++ break; ++ } ++#endif ++ ++ status = gcvSTATUS_OK; ++ break; ++ ++#if VIVANTE_PROFILER_PERDRAW ++ case gcvHAL_READ_PROFILER_REGISTER_SETTING: ++ #if VIVANTE_PROFILER ++ Kernel->profileCleanRegister = Interface->u.SetProfilerRegisterClear.bclear; ++ #endif ++ status = gcvSTATUS_OK; ++ break; ++#endif ++ ++ case gcvHAL_QUERY_KERNEL_SETTINGS: ++ /* Get kernel settings. */ ++ gcmkONERROR( ++ gckKERNEL_QuerySettings(Kernel, ++ &Interface->u.QueryKernelSettings.settings)); ++ break; ++ ++ case gcvHAL_RESET: ++ /* Reset the hardware. */ ++ gcmkONERROR( ++ gckHARDWARE_Reset(Kernel->hardware)); ++ break; ++ ++ case gcvHAL_DEBUG: ++ /* Set debug level and zones. */ ++ if (Interface->u.Debug.set) ++ { ++ gckOS_SetDebugLevel(Interface->u.Debug.level); ++ gckOS_SetDebugZones(Interface->u.Debug.zones, ++ Interface->u.Debug.enable); ++ } ++ ++ if (Interface->u.Debug.message[0] != '\0') ++ { ++ /* Print a message to the debugger. */ ++ if (Interface->u.Debug.type == gcvMESSAGE_TEXT) ++ { ++ gckOS_CopyPrint(Interface->u.Debug.message); ++ } ++ else ++ { ++ gckOS_DumpBuffer(Kernel->os, ++ Interface->u.Debug.message, ++ Interface->u.Debug.messageSize, ++ gceDUMP_BUFFER_FROM_USER, ++ gcvTRUE); ++ } ++ } ++ status = gcvSTATUS_OK; ++ break; ++ ++ case gcvHAL_DUMP_GPU_STATE: ++ { ++ gceCHIPPOWERSTATE power; ++ ++ _DumpDriverConfigure(Kernel); ++ ++ gcmkONERROR(gckHARDWARE_QueryPowerManagementState( ++ Kernel->hardware, ++ &power ++ )); ++ ++ if (power == gcvPOWER_ON) ++ { ++ Interface->u.ReadRegisterData.data = 1; ++ ++ _DumpState(Kernel); ++ } ++ else ++ { ++ Interface->u.ReadRegisterData.data = 0; ++ status = gcvSTATUS_CHIP_NOT_READY; ++ ++ gcmkPRINT("[galcore]: Can't dump state if GPU isn't POWER ON."); ++ } ++ } ++ break; ++ ++ case gcvHAL_DUMP_EVENT: ++ break; ++ ++ case gcvHAL_CACHE: ++ ++ logical = gcmUINT64_TO_PTR(Interface->u.Cache.logical); ++ ++ if (Interface->u.Cache.node) ++ { ++ gcmkONERROR(gckVIDMEM_HANDLE_Lookup( ++ Kernel, ++ processID, ++ Interface->u.Cache.node, ++ &nodeObject)); ++ ++ if (nodeObject->node->VidMem.memory->object.type == gcvOBJ_VIDMEM ++ || nodeObject->node->Virtual.contiguous ++ ) ++ { ++ /* If memory is contiguous, get physical address. */ ++ gcmkONERROR(gckOS_GetPhysicalAddress( ++ Kernel->os, logical, (gctUINT32*)&paddr)); ++ } ++ } ++ ++ bytes = (gctSIZE_T) Interface->u.Cache.bytes; ++ switch(Interface->u.Cache.operation) ++ { ++ case gcvCACHE_FLUSH: ++ /* Clean and invalidate the cache. */ ++ status = gckOS_CacheFlush(Kernel->os, ++ processID, ++ physical, ++ paddr, ++ logical, ++ bytes); ++ break; ++ case gcvCACHE_CLEAN: ++ /* Clean the cache. */ ++ status = gckOS_CacheClean(Kernel->os, ++ processID, ++ physical, ++ paddr, ++ logical, ++ bytes); ++ break; ++ case gcvCACHE_INVALIDATE: ++ /* Invalidate the cache. */ ++ status = gckOS_CacheInvalidate(Kernel->os, ++ processID, ++ physical, ++ paddr, ++ logical, ++ bytes); ++ break; ++ ++ case gcvCACHE_MEMORY_BARRIER: ++ status = gckOS_MemoryBarrier(Kernel->os, ++ logical); ++ break; ++ default: ++ status = gcvSTATUS_INVALID_ARGUMENT; ++ break; ++ } ++ break; ++ ++ case gcvHAL_TIMESTAMP: ++ /* Check for invalid timer. */ ++ if ((Interface->u.TimeStamp.timer >= gcmCOUNTOF(Kernel->timers)) ++ || (Interface->u.TimeStamp.request != 2)) ++ { ++ Interface->u.TimeStamp.timeDelta = 0; ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Return timer results and reset timer. */ ++ { ++ gcsTIMER_PTR timer = &(Kernel->timers[Interface->u.TimeStamp.timer]); ++ gctUINT64 timeDelta = 0; ++ ++ if (timer->stopTime < timer->startTime ) ++ { ++ Interface->u.TimeStamp.timeDelta = 0; ++ gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW); ++ } ++ ++ timeDelta = timer->stopTime - timer->startTime; ++ ++ /* Check truncation overflow. */ ++ Interface->u.TimeStamp.timeDelta = (gctINT32) timeDelta; ++ /*bit0~bit30 is available*/ ++ if (timeDelta>>31) ++ { ++ Interface->u.TimeStamp.timeDelta = 0; ++ gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW); ++ } ++ ++ status = gcvSTATUS_OK; ++ } ++ break; ++ ++ case gcvHAL_DATABASE: ++ gcmkONERROR(gckKERNEL_QueryDatabase(Kernel, processID, Interface)); ++ break; ++ ++ case gcvHAL_VERSION: ++ Interface->u.Version.major = gcvVERSION_MAJOR; ++ Interface->u.Version.minor = gcvVERSION_MINOR; ++ Interface->u.Version.patch = gcvVERSION_PATCH; ++ Interface->u.Version.build = gcvVERSION_BUILD; ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, ++ "KERNEL version %d.%d.%d build %u %s", ++ gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, ++ gcvVERSION_BUILD, utsname()->version); ++#endif ++ break; ++ ++ case gcvHAL_CHIP_INFO: ++ /* Only if not support multi-core */ ++ Interface->u.ChipInfo.count = 1; ++ Interface->u.ChipInfo.types[0] = Kernel->hardware->type; ++ break; ++ ++#if (gcdENABLE_3D || gcdENABLE_2D) ++ case gcvHAL_ATTACH: ++ /* Attach user process. */ ++ gcmkONERROR( ++ gckCOMMAND_Attach(Kernel->command, ++ &context, ++ &bytes, ++ processID)); ++ ++ Interface->u.Attach.stateCount = bytes; ++ Interface->u.Attach.context = gcmPTR_TO_NAME(context); ++ ++ if (Interface->u.Attach.map == gcvTRUE) ++ { ++ gcmkVERIFY_OK( ++ gckCONTEXT_MapBuffer(context, ++ Interface->u.Attach.physicals, ++ Interface->u.Attach.logicals, ++ &Interface->u.Attach.bytes)); ++ } ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_CONTEXT, ++ gcmINT2PTR(Interface->u.Attach.context), ++ gcvNULL, ++ 0)); ++ break; ++#endif ++ ++ case gcvHAL_DETACH: ++ gcmkVERIFY_OK( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, gcvDB_CONTEXT, ++ gcmINT2PTR(Interface->u.Detach.context))); ++ ++ /* Detach user process. */ ++ gcmkONERROR( ++ gckCOMMAND_Detach(Kernel->command, ++ gcmNAME_TO_PTR(Interface->u.Detach.context))); ++ ++ gcmRELEASE_NAME(Interface->u.Detach.context); ++ break; ++ ++ case gcvHAL_COMPOSE: ++ Interface->u.Compose.physical = gcmPTR_TO_UINT64(gcmNAME_TO_PTR(Interface->u.Compose.physical)); ++ /* Start composition. */ ++ gcmkONERROR( ++ gckEVENT_Compose(Kernel->eventObj, ++ &Interface->u.Compose)); ++ break; ++ ++ case gcvHAL_SET_TIMEOUT: ++ /* set timeOut value from user */ ++ gckKERNEL_SetTimeOut(Kernel, Interface->u.SetTimeOut.timeOut); ++ break; ++ ++ case gcvHAL_GET_FRAME_INFO: ++ gcmkONERROR(gckHARDWARE_GetFrameInfo( ++ Kernel->hardware, ++ gcmUINT64_TO_PTR(Interface->u.GetFrameInfo.frameInfo))); ++ break; ++ ++ case gcvHAL_SET_FSCALE_VALUE: ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ status = gckHARDWARE_SetFscaleValue(Kernel->hardware, ++ Interface->u.SetFscaleValue.value); ++#else ++ status = gcvSTATUS_NOT_SUPPORTED; ++#endif ++ break; ++ case gcvHAL_GET_FSCALE_VALUE: ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ status = gckHARDWARE_GetFscaleValue(Kernel->hardware, ++ &Interface->u.GetFscaleValue.value, ++ &Interface->u.GetFscaleValue.minValue, ++ &Interface->u.GetFscaleValue.maxValue); ++#else ++ status = gcvSTATUS_NOT_SUPPORTED; ++#endif ++ break; ++ ++ case gcvHAL_NAME_VIDEO_MEMORY: ++ gcmkONERROR(gckVIDMEM_NODE_Name(Kernel, ++ Interface->u.NameVideoMemory.handle, ++ &Interface->u.NameVideoMemory.name)); ++ break; ++ ++ case gcvHAL_IMPORT_VIDEO_MEMORY: ++ gcmkONERROR(gckVIDMEM_NODE_Import(Kernel, ++ Interface->u.ImportVideoMemory.name, ++ &Interface->u.ImportVideoMemory.handle)); ++ ++ gcmkONERROR( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_VIDEO_MEMORY, ++ gcmINT2PTR(Interface->u.ImportVideoMemory.handle), ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvHAL_GET_VIDEO_MEMORY_FD: ++ gcmkONERROR(gckVIDMEM_NODE_GetFd( ++ Kernel, ++ Interface->u.GetVideoMemoryFd.handle, ++ &Interface->u.GetVideoMemoryFd.fd ++ )); ++ ++ /* No need to add it to processDB because OS will release all fds when ++ ** process quits. ++ */ ++ break; ++ ++ case gcvHAL_QUERY_RESET_TIME_STAMP: ++ Interface->u.QueryResetTimeStamp.timeStamp = Kernel->resetTimeStamp; ++ break; ++ ++ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER: ++ buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)gcmNAME_TO_PTR(Interface->u.FreeVirtualCommandBuffer.physical); ++ ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Kernel, ++ processID, ++ gcvDB_COMMAND_BUFFER, ++ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical))); ++ ++ gcmkONERROR(gckOS_DestroyUserVirtualMapping( ++ Kernel->os, ++ buffer->physical, ++ (gctSIZE_T)Interface->u.FreeVirtualCommandBuffer.bytes, ++ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical))); ++ ++ gcmkONERROR(gckKERNEL_DestroyVirtualCommandBuffer( ++ Kernel, ++ (gctSIZE_T)Interface->u.FreeVirtualCommandBuffer.bytes, ++ (gctPHYS_ADDR)buffer, ++ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical))); ++ ++ gcmRELEASE_NAME(Interface->u.FreeVirtualCommandBuffer.physical); ++ break; ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ case gcvHAL_SYNC_POINT: ++ { ++ gctSYNC_POINT syncPoint; ++ ++ switch (Interface->u.SyncPoint.command) ++ { ++ case gcvSYNC_POINT_CREATE: ++ gcmkONERROR(gckOS_CreateSyncPoint(Kernel->os, &syncPoint)); ++ ++ Interface->u.SyncPoint.syncPoint = gcmPTR_TO_UINT64(syncPoint); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_SYNC_POINT, ++ syncPoint, ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvSYNC_POINT_DESTROY: ++ syncPoint = gcmUINT64_TO_PTR(Interface->u.SyncPoint.syncPoint); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, gcvDB_SYNC_POINT, ++ syncPoint)); ++ ++ gcmkONERROR(gckOS_DestroySyncPoint(Kernel->os, syncPoint)); ++ break; ++ ++ default: ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ break; ++ } ++ } ++ break; ++ ++ case gcvHAL_CREATE_NATIVE_FENCE: ++ { ++ gctINT fenceFD; ++ gctSYNC_POINT syncPoint = ++ gcmUINT64_TO_PTR(Interface->u.CreateNativeFence.syncPoint); ++ ++ gcmkONERROR( ++ gckOS_CreateNativeFence(Kernel->os, ++ Kernel->timeline, ++ syncPoint, ++ &fenceFD)); ++ ++ Interface->u.CreateNativeFence.fenceFD = fenceFD; ++ } ++ break; ++#endif ++ ++ case gcvHAL_SHBUF: ++ { ++ gctSHBUF shBuf; ++ gctPOINTER uData; ++ gctUINT32 bytes; ++ ++ switch (Interface->u.ShBuf.command) ++ { ++ case gcvSHBUF_CREATE: ++ bytes = Interface->u.ShBuf.bytes; ++ ++ /* Create. */ ++ gcmkONERROR(gckKERNEL_CreateShBuffer(Kernel, bytes, &shBuf)); ++ ++ Interface->u.ShBuf.id = gcmPTR_TO_UINT64(shBuf); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, ++ gcvDB_SHBUF, ++ shBuf, ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvSHBUF_DESTROY: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ ++ /* Check db first to avoid illegal destroy in the process. */ ++ gcmkONERROR( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, ++ gcvDB_SHBUF, ++ shBuf)); ++ ++ gcmkONERROR(gckKERNEL_DestroyShBuffer(Kernel, shBuf)); ++ break; ++ ++ case gcvSHBUF_MAP: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ ++ /* Map for current process access. */ ++ gcmkONERROR(gckKERNEL_MapShBuffer(Kernel, shBuf)); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, ++ gcvDB_SHBUF, ++ shBuf, ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvSHBUF_WRITE: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data); ++ bytes = Interface->u.ShBuf.bytes; ++ ++ /* Write. */ ++ gcmkONERROR( ++ gckKERNEL_WriteShBuffer(Kernel, shBuf, uData, bytes)); ++ break; ++ ++ case gcvSHBUF_READ: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data); ++ bytes = Interface->u.ShBuf.bytes; ++ ++ /* Read. */ ++ gcmkONERROR( ++ gckKERNEL_ReadShBuffer(Kernel, ++ shBuf, ++ uData, ++ bytes, ++ &bytes)); ++ ++ /* Return copied size. */ ++ Interface->u.ShBuf.bytes = bytes; ++ break; ++ ++ default: ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ break; ++ } ++ } ++ break; ++ ++ case gcvHAL_CONFIG_POWER_MANAGEMENT: ++ gcmkONERROR(gckKERNEL_ConfigPowerManagement(Kernel, Interface)); ++ break; ++ ++ default: ++ /* Invalid command. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++OnError: ++ /* Save status. */ ++ Interface->status = status; ++ ++ if (powerMutexAcquired == gcvTRUE) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_AttachProcess ++** ++** Attach or detach a process. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctBOOL Attach ++** gcvTRUE if a new process gets attached or gcFALSE when a process ++** gets detatched. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_AttachProcess( ++ IN gckKERNEL Kernel, ++ IN gctBOOL Attach ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 processID; ++ ++ gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Get current process ID. */ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ gcmkONERROR(gckKERNEL_AttachProcessEx(Kernel, Attach, processID)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_AttachProcessEx ++** ++** Attach or detach a process with the given PID. Can be paired with gckKERNEL_AttachProcess ++** provided the programmer is aware of the consequences. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctBOOL Attach ++** gcvTRUE if a new process gets attached or gcFALSE when a process ++** gets detatched. ++** ++** gctUINT32 PID ++** PID of the process to attach or detach. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_AttachProcessEx( ++ IN gckKERNEL Kernel, ++ IN gctBOOL Attach, ++ IN gctUINT32 PID ++ ) ++{ ++ gceSTATUS status; ++ gctINT32 old; ++ ++ gcmkHEADER_ARG("Kernel=0x%x Attach=%d PID=%d", Kernel, Attach, PID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ if (Attach) ++ { ++ /* Increment the number of clients attached. */ ++ gcmkONERROR( ++ gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old)); ++ ++ if (old == 0) ++ { ++#if gcdENABLE_VG ++ if (Kernel->vg == gcvNULL) ++#endif ++ { ++ gcmkONERROR(gckOS_Broadcast(Kernel->os, ++ Kernel->hardware, ++ gcvBROADCAST_FIRST_PROCESS)); ++ } ++ } ++ ++ if (Kernel->dbCreated) ++ { ++ /* Create the process database. */ ++ gcmkONERROR(gckKERNEL_CreateProcessDB(Kernel, PID)); ++ } ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ /* Map kernel command buffer in the process's own MMU. */ ++ gcmkONERROR(_MapCommandBuffer(Kernel)); ++#endif ++ } ++ else ++ { ++ if (Kernel->dbCreated) ++ { ++ /* Clean up the process database. */ ++ gcmkONERROR(gckKERNEL_DestroyProcessDB(Kernel, PID)); ++ ++ /* Save the last know process ID. */ ++ Kernel->db->lastProcessID = PID; ++ } ++ ++#if gcdENABLE_VG ++ if (Kernel->vg == gcvNULL) ++#endif ++ { ++ status = gckEVENT_Submit(Kernel->eventObj, gcvTRUE, gcvFALSE, gcvFALSE); ++ ++ if (status == gcvSTATUS_INTERRUPTED && Kernel->eventObj->submitTimer) ++ { ++ gcmkONERROR(gckOS_StartTimer(Kernel->os, ++ Kernel->eventObj->submitTimer, ++ 1)); ++ } ++ else ++ { ++ gcmkONERROR(status); ++ } ++ } ++ ++ /* Decrement the number of clients attached. */ ++ gcmkONERROR( ++ gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old)); ++ ++ if (old == 1) ++ { ++#if gcdENABLE_VG ++ if (Kernel->vg == gcvNULL) ++#endif ++ { ++ /* Last client detached, switch to SUSPEND power state. */ ++ gcmkONERROR(gckOS_Broadcast(Kernel->os, ++ Kernel->hardware, ++ gcvBROADCAST_LAST_PROCESS)); ++ } ++ ++ /* Flush the debug cache. */ ++ gcmkDEBUGFLUSH(~0U); ++ } ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_Recovery ++** ++** Try to recover the GPU from a fatal error. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_Recovery( ++ IN gckKERNEL Kernel ++ ) ++{ ++ gceSTATUS status; ++ gckEVENT eventObj; ++ gckHARDWARE hardware; ++ gctUINT32 mask = 0; ++ gckCOMMAND command; ++ gckENTRYDATA data; ++ gctUINT32 i = 0, count = 0; ++#if gcdINTERRUPT_STATISTIC ++ gctINT32 oldValue; ++#endif ++ ++ gcmkHEADER_ARG("Kernel=0x%x", Kernel); ++ ++ /* Validate the arguemnts. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Grab gckEVENT object. */ ++ eventObj = Kernel->eventObj; ++ gcmkVERIFY_OBJECT(eventObj, gcvOBJ_EVENT); ++ ++ /* Grab gckHARDWARE object. */ ++ hardware = Kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ /* Grab gckCOMMAND object. */ ++ command = Kernel->command; ++ gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); ++ ++ if (Kernel->stuckDump == gcdSTUCK_DUMP_MINIMAL) ++ { ++ gcmkPRINT("[galcore]: GPU[%d] hang, automatic recovery.", Kernel->core); ++ } ++ else ++ { ++ _DumpDriverConfigure(Kernel); ++ _DumpState(Kernel); ++ } ++ ++ if (Kernel->recovery == gcvFALSE) ++ { ++ gcmkPRINT("[galcore]: Stop driver to keep scene."); ++ ++ for (;;) ++ { ++ gckOS_Delay(Kernel->os, 10000); ++ } ++ } ++ ++ /* Clear queue. */ ++ do ++ { ++ status = gckENTRYQUEUE_Dequeue(&command->queue, &data); ++ } ++ while (status == gcvSTATUS_OK); ++ ++ /* Issuing a soft reset for the GPU. */ ++ gcmkONERROR(gckHARDWARE_Reset(hardware)); ++ ++ mask = Kernel->restoreMask; ++ ++ for (i = 0; i < 32; i++) ++ { ++ if (mask & (1 << i)) ++ { ++ count++; ++ } ++ } ++ ++ /* Handle all outstanding events now. */ ++#if gcdSMP ++ gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending, mask)); ++#else ++ eventObj->pending = mask; ++#endif ++ ++#if gcdINTERRUPT_STATISTIC ++ while (count--) ++ { ++ gcmkONERROR(gckOS_AtomDecrement( ++ Kernel->os, ++ eventObj->interruptCount, ++ &oldValue ++ )); ++ } ++ ++ gckOS_AtomClearMask(Kernel->hardware->pendingEvent, mask); ++#endif ++ ++ gcmkONERROR(gckEVENT_Notify(eventObj, 1)); ++ ++ gcmkVERIFY_OK(gckOS_GetTime(&Kernel->resetTimeStamp)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_OpenUserData ++** ++** Get access to the user data. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctBOOL NeedCopy ++** The flag indicating whether or not the data should be copied. ++** ++** gctPOINTER StaticStorage ++** Pointer to the kernel storage where the data is to be copied if ++** NeedCopy is gcvTRUE. ++** ++** gctPOINTER UserPointer ++** User pointer to the data. ++** ++** gctSIZE_T Size ++** Size of the data. ++** ++** OUTPUT: ++** ++** gctPOINTER * KernelPointer ++** Pointer to the kernel pointer that will be pointing to the data. ++*/ ++gceSTATUS ++gckKERNEL_OpenUserData( ++ IN gckKERNEL Kernel, ++ IN gctBOOL NeedCopy, ++ IN gctPOINTER StaticStorage, ++ IN gctPOINTER UserPointer, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * KernelPointer ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG( ++ "Kernel=0x%08X NeedCopy=%d StaticStorage=0x%08X " ++ "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X", ++ Kernel, NeedCopy, StaticStorage, UserPointer, Size, KernelPointer ++ ); ++ ++ /* Validate the arguemnts. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(!NeedCopy || (StaticStorage != gcvNULL)); ++ gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ ++ if (NeedCopy) ++ { ++ /* Copy the user data to the static storage. */ ++ gcmkONERROR(gckOS_CopyFromUserData( ++ Kernel->os, StaticStorage, UserPointer, Size ++ )); ++ ++ /* Set the kernel pointer. */ ++ * KernelPointer = StaticStorage; ++ } ++ else ++ { ++ gctPOINTER pointer = gcvNULL; ++ ++ /* Map the user pointer. */ ++ gcmkONERROR(gckOS_MapUserPointer( ++ Kernel->os, UserPointer, Size, &pointer ++ )); ++ ++ /* Set the kernel pointer. */ ++ * KernelPointer = pointer; ++ } ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_CloseUserData ++** ++** Release resources associated with the user data connection opened by ++** gckKERNEL_OpenUserData. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctBOOL NeedCopy ++** The flag indicating whether or not the data should be copied. ++** ++** gctBOOL FlushData ++** If gcvTRUE, the data is written back to the user. ++** ++** gctPOINTER UserPointer ++** User pointer to the data. ++** ++** gctSIZE_T Size ++** Size of the data. ++** ++** OUTPUT: ++** ++** gctPOINTER * KernelPointer ++** Kernel pointer to the data. ++*/ ++gceSTATUS ++gckKERNEL_CloseUserData( ++ IN gckKERNEL Kernel, ++ IN gctBOOL NeedCopy, ++ IN gctBOOL FlushData, ++ IN gctPOINTER UserPointer, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * KernelPointer ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gctPOINTER pointer; ++ ++ gcmkHEADER_ARG( ++ "Kernel=0x%08X NeedCopy=%d FlushData=%d " ++ "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X", ++ Kernel, NeedCopy, FlushData, UserPointer, Size, KernelPointer ++ ); ++ ++ /* Validate the arguemnts. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ ++ /* Get a shortcut to the kernel pointer. */ ++ pointer = * KernelPointer; ++ ++ if (pointer != gcvNULL) ++ { ++ if (NeedCopy) ++ { ++ if (FlushData) ++ { ++ gcmkONERROR(gckOS_CopyToUserData( ++ Kernel->os, * KernelPointer, UserPointer, Size ++ )); ++ } ++ } ++ else ++ { ++ /* Unmap record from kernel memory. */ ++ gcmkONERROR(gckOS_UnmapUserPointer( ++ Kernel->os, ++ UserPointer, ++ Size, ++ * KernelPointer ++ )); ++ } ++ ++ /* Reset the kernel pointer. */ ++ * KernelPointer = gcvNULL; ++ } ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++void ++gckKERNEL_SetTimeOut( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 timeOut ++ ) ++{ ++ gcmkHEADER_ARG("Kernel=0x%x timeOut=%d", Kernel, timeOut); ++#if gcdGPU_TIMEOUT ++ Kernel->timeOut = timeOut; ++#endif ++ gcmkFOOTER_NO(); ++} ++ ++gceSTATUS ++gckKERNEL_AllocateVirtualCommandBuffer( ++ IN gckKERNEL Kernel, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ gckOS os = Kernel->os; ++ gceSTATUS status; ++ gctPOINTER logical = gcvNULL; ++ gctSIZE_T pageCount; ++ gctSIZE_T bytes = *Bytes; ++ gckVIRTUAL_COMMAND_BUFFER_PTR buffer = gcvNULL; ++ gckMMU mmu; ++ gctUINT32 flag = gcvALLOC_FLAG_NON_CONTIGUOUS; ++ ++ gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu", ++ os, InUserSpace, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes != gcvNULL); ++ gcmkVERIFY_ARGUMENT(*Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ gcmkONERROR(gckOS_Allocate(os, ++ sizeof(gckVIRTUAL_COMMAND_BUFFER), ++ (gctPOINTER)&buffer)); ++ ++ gcmkONERROR(gckOS_ZeroMemory(buffer, sizeof(gckVIRTUAL_COMMAND_BUFFER))); ++ ++ buffer->bytes = bytes; ++ ++ gcmkONERROR(gckOS_AllocatePagedMemoryEx(os, ++ flag, ++ bytes, ++ gcvNULL, ++ &buffer->physical)); ++ ++ if (InUserSpace) ++ { ++ gcmkONERROR(gckOS_CreateUserVirtualMapping(os, ++ buffer->physical, ++ bytes, ++ &logical, ++ &pageCount)); ++ ++ *Logical = ++ buffer->userLogical = logical; ++ } ++ else ++ { ++ gcmkONERROR(gckOS_CreateKernelVirtualMapping(os, ++ buffer->physical, ++ bytes, ++ &logical, ++ &pageCount)); ++ ++ *Logical = ++ buffer->kernelLogical = logical; ++ } ++ ++ buffer->pageCount = pageCount; ++ buffer->kernel = Kernel; ++ ++ gcmkONERROR(gckOS_GetProcessID(&buffer->pid)); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu)); ++ buffer->mmu = mmu; ++#else ++ mmu = Kernel->mmu; ++#endif ++ ++ gcmkONERROR(gckMMU_AllocatePages(mmu, ++ pageCount, ++ &buffer->pageTable, ++ &buffer->gpuAddress)); ++ ++ ++ gcmkONERROR(gckOS_MapPagesEx(os, ++ Kernel->core, ++ buffer->physical, ++ pageCount, ++ buffer->gpuAddress, ++ buffer->pageTable)); ++ ++ gcmkONERROR(gckMMU_Flush(mmu, gcvSURF_INDEX)); ++ ++ *Physical = buffer; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, ++ "gpuAddress = %x pageCount = %d kernelLogical = %x userLogical=%x", ++ buffer->gpuAddress, buffer->pageCount, ++ buffer->kernelLogical, buffer->userLogical); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(os, Kernel->virtualBufferLock, gcvINFINITE)); ++ ++ if (Kernel->virtualBufferHead == gcvNULL) ++ { ++ Kernel->virtualBufferHead = ++ Kernel->virtualBufferTail = buffer; ++ } ++ else ++ { ++ buffer->prev = Kernel->virtualBufferTail; ++ Kernel->virtualBufferTail->next = buffer; ++ Kernel->virtualBufferTail = buffer; ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Kernel->virtualBufferLock)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (buffer->gpuAddress) ++ { ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkVERIFY_OK( ++ gckMMU_FreePages(mmu, buffer->pageTable, buffer->pageCount)); ++#else ++ gcmkVERIFY_OK( ++ gckMMU_FreePages(Kernel->mmu, buffer->pageTable, buffer->pageCount)); ++#endif ++ } ++ ++ if (buffer->userLogical) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DestroyUserVirtualMapping(os, ++ buffer->physical, ++ bytes, ++ buffer->userLogical)); ++ } ++ ++ if (buffer->kernelLogical) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DestroyKernelVirtualMapping(os, ++ buffer->physical, ++ bytes, ++ buffer->kernelLogical)); ++ } ++ ++ if (buffer->physical) ++ { ++ gcmkVERIFY_OK(gckOS_FreePagedMemory(os, buffer->physical, bytes)); ++ } ++ ++ gcmkVERIFY_OK(gckOS_Free(os, buffer)); ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_DestroyVirtualCommandBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical ++ ) ++{ ++ gckOS os; ++ gckKERNEL kernel; ++ gckVIRTUAL_COMMAND_BUFFER_PTR buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)Physical; ++ ++ gcmkHEADER(); ++ gcmkVERIFY_ARGUMENT(buffer != gcvNULL); ++ ++ kernel = buffer->kernel; ++ os = kernel->os; ++ ++ if (!buffer->userLogical) ++ { ++ gcmkVERIFY_OK(gckOS_DestroyKernelVirtualMapping(os, ++ buffer->physical, ++ Bytes, ++ Logical)); ++ } ++ ++#if !gcdPROCESS_ADDRESS_SPACE ++ gcmkVERIFY_OK( ++ gckMMU_FreePages(kernel->mmu, buffer->pageTable, buffer->pageCount)); ++#endif ++ ++ gcmkVERIFY_OK(gckOS_UnmapPages(os, buffer->pageCount, buffer->gpuAddress)); ++ ++ gcmkVERIFY_OK(gckOS_FreePagedMemory(os, buffer->physical, Bytes)); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(os, kernel->virtualBufferLock, gcvINFINITE)); ++ ++ if (buffer == kernel->virtualBufferHead) ++ { ++ if ((kernel->virtualBufferHead = buffer->next) == gcvNULL) ++ { ++ kernel->virtualBufferTail = gcvNULL; ++ } ++ } ++ else ++ { ++ buffer->prev->next = buffer->next; ++ ++ if (buffer == kernel->virtualBufferTail) ++ { ++ kernel->virtualBufferTail = buffer->prev; ++ } ++ else ++ { ++ buffer->next->prev = buffer->prev; ++ } ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, kernel->virtualBufferLock)); ++ ++ gcmkVERIFY_OK(gckOS_Free(os, buffer)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckKERNEL_GetGPUAddress( ++ IN gckKERNEL Kernel, ++ IN gctPOINTER Logical, ++ IN gctBOOL InUserSpace, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gceSTATUS status; ++ gckVIRTUAL_COMMAND_BUFFER_PTR buffer; ++ gctPOINTER start; ++ gctUINT32 pid; ++ ++ gcmkHEADER_ARG("Logical = %x InUserSpace=%d.", Logical, InUserSpace); ++ ++ gcmkVERIFY_OK(gckOS_GetProcessID(&pid)); ++ ++ status = gcvSTATUS_INVALID_ADDRESS; ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->virtualBufferLock, gcvINFINITE)); ++ ++ /* Walk all command buffer. */ ++ for (buffer = Kernel->virtualBufferHead; buffer != gcvNULL; buffer = buffer->next) ++ { ++ if (InUserSpace) ++ { ++ start = buffer->userLogical; ++ } ++ else ++ { ++ start = buffer->kernelLogical; ++ } ++ ++ if (start == gcvNULL) ++ { ++ continue; ++ } ++ ++ if (Logical >= start ++ && (Logical < (gctPOINTER)((gctUINT8_PTR)start + buffer->pageCount * 4096)) ++ && pid == buffer->pid ++ ) ++ { ++ * Address = buffer->gpuAddress + (gctUINT32)((gctUINT8_PTR)Logical - (gctUINT8_PTR)start); ++ status = gcvSTATUS_OK; ++ break; ++ } ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->virtualBufferLock)); ++ ++ gcmkFOOTER_NO(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_QueryGPUAddress( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 GpuAddress, ++ OUT gckVIRTUAL_COMMAND_BUFFER_PTR * Buffer ++ ) ++{ ++ gckVIRTUAL_COMMAND_BUFFER_PTR buffer; ++ gctUINT32 start; ++ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED; ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->virtualBufferLock, gcvINFINITE)); ++ ++ /* Walk all command buffers. */ ++ for (buffer = Kernel->virtualBufferHead; buffer != gcvNULL; buffer = buffer->next) ++ { ++ start = (gctUINT32)buffer->gpuAddress; ++ ++ if (GpuAddress >= start && GpuAddress < (start + buffer->pageCount * 4096)) ++ { ++ /* Find a range matched. */ ++ *Buffer = buffer; ++ status = gcvSTATUS_OK; ++ break; ++ } ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->virtualBufferLock)); ++ ++ return status; ++} ++ ++#if gcdLINK_QUEUE_SIZE ++static void ++gckLINKQUEUE_Dequeue( ++ IN gckLINKQUEUE LinkQueue ++ ) ++{ ++ gcmkASSERT(LinkQueue->count == gcdLINK_QUEUE_SIZE); ++ ++ LinkQueue->count--; ++ LinkQueue->front = (LinkQueue->front + 1) % gcdLINK_QUEUE_SIZE; ++} ++ ++void ++gckLINKQUEUE_Enqueue( ++ IN gckLINKQUEUE LinkQueue, ++ IN gctUINT32 start, ++ IN gctUINT32 end ++ ) ++{ ++ if (LinkQueue->count == gcdLINK_QUEUE_SIZE) ++ { ++ gckLINKQUEUE_Dequeue(LinkQueue); ++ } ++ ++ gcmkASSERT(LinkQueue->count < gcdLINK_QUEUE_SIZE); ++ ++ LinkQueue->count++; ++ ++ LinkQueue->data[LinkQueue->rear].start = start; ++ LinkQueue->data[LinkQueue->rear].end = end; ++ ++ gcmkVERIFY_OK( ++ gckOS_GetProcessID(&LinkQueue->data[LinkQueue->rear].pid)); ++ ++ LinkQueue->rear = (LinkQueue->rear + 1) % gcdLINK_QUEUE_SIZE; ++} ++ ++void ++gckLINKQUEUE_GetData( ++ IN gckLINKQUEUE LinkQueue, ++ IN gctUINT32 Index, ++ OUT gckLINKDATA * Data ++ ) ++{ ++ gcmkASSERT(Index >= 0 && Index < gcdLINK_QUEUE_SIZE); ++ ++ *Data = &LinkQueue->data[(Index + LinkQueue->front) % gcdLINK_QUEUE_SIZE]; ++} ++#endif ++ ++/* ++* gckENTRYQUEUE_Enqueue is called with Command->mutexQueue acquired. ++*/ ++gceSTATUS ++gckENTRYQUEUE_Enqueue( ++ IN gckKERNEL Kernel, ++ IN gckENTRYQUEUE Queue, ++ IN gctUINT32 physical, ++ IN gctUINT32 bytes ++ ) ++{ ++ gctUINT32 next = (Queue->rear + 1) % gcdENTRY_QUEUE_SIZE; ++ ++ if (next == Queue->front) ++ { ++ /* Queue is full. */ ++ return gcvSTATUS_INVALID_REQUEST; ++ } ++ ++ /* Copy data. */ ++ Queue->data[Queue->rear].physical = physical; ++ Queue->data[Queue->rear].bytes = bytes; ++ ++ gcmkVERIFY_OK(gckOS_MemoryBarrier(Kernel->os, &Queue->rear)); ++ ++ /* Update rear. */ ++ Queue->rear = next; ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckENTRYQUEUE_Dequeue( ++ IN gckENTRYQUEUE Queue, ++ OUT gckENTRYDATA * Data ++ ) ++{ ++ if (Queue->front == Queue->rear) ++ { ++ /* Queue is empty. */ ++ return gcvSTATUS_INVALID_REQUEST; ++ } ++ ++ /* Copy data. */ ++ *Data = &Queue->data[Queue->front]; ++ ++ /* Update front. */ ++ Queue->front = (Queue->front + 1) % gcdENTRY_QUEUE_SIZE; ++ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************\ ++*************************** Pointer - ID translation *************************** ++\******************************************************************************/ ++#define gcdID_TABLE_LENGTH 1024 ++typedef struct _gcsINTEGERDB * gckINTEGERDB; ++typedef struct _gcsINTEGERDB ++{ ++ gckOS os; ++ gctPOINTER* table; ++ gctPOINTER mutex; ++ gctUINT32 tableLen; ++ gctUINT32 currentID; ++ gctUINT32 unused; ++} ++gcsINTEGERDB; ++ ++gceSTATUS ++gckKERNEL_CreateIntegerDatabase( ++ IN gckKERNEL Kernel, ++ OUT gctPOINTER * Database ++ ) ++{ ++ gceSTATUS status; ++ gckINTEGERDB database = gcvNULL; ++ ++ gcmkHEADER_ARG("Kernel=0x%08X Datbase=0x%08X", Kernel, Database); ++ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Database != gcvNULL); ++ ++ /* Allocate a database. */ ++ gcmkONERROR(gckOS_Allocate( ++ Kernel->os, gcmSIZEOF(gcsINTEGERDB), (gctPOINTER *)&database)); ++ ++ gcmkONERROR(gckOS_ZeroMemory(database, gcmSIZEOF(gcsINTEGERDB))); ++ ++ /* Allocate a pointer table. */ ++ gcmkONERROR(gckOS_Allocate( ++ Kernel->os, gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH, (gctPOINTER *)&database->table)); ++ ++ gcmkONERROR(gckOS_ZeroMemory(database->table, gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH)); ++ ++ /* Allocate a database mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->mutex)); ++ ++ /* Initialize. */ ++ database->currentID = 0; ++ database->unused = gcdID_TABLE_LENGTH; ++ database->os = Kernel->os; ++ database->tableLen = gcdID_TABLE_LENGTH; ++ ++ *Database = database; ++ ++ gcmkFOOTER_ARG("*Database=0x%08X", *Database); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Rollback. */ ++ if (database) ++ { ++ if (database->table) ++ { ++ gcmkOS_SAFE_FREE(Kernel->os, database->table); ++ } ++ ++ gcmkOS_SAFE_FREE(Kernel->os, database); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_DestroyIntegerDatabase( ++ IN gckKERNEL Kernel, ++ IN gctPOINTER Database ++ ) ++{ ++ gckINTEGERDB database = Database; ++ ++ gcmkHEADER_ARG("Kernel=0x%08X Datbase=0x%08X", Kernel, Database); ++ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Database != gcvNULL); ++ ++ /* Destroy pointer table. */ ++ gcmkOS_SAFE_FREE(Kernel->os, database->table); ++ ++ /* Destroy database mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->mutex)); ++ ++ /* Destroy database. */ ++ gcmkOS_SAFE_FREE(Kernel->os, database); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckKERNEL_AllocateIntegerId( ++ IN gctPOINTER Database, ++ IN gctPOINTER Pointer, ++ OUT gctUINT32 * Id ++ ) ++{ ++ gceSTATUS status; ++ gckINTEGERDB database = Database; ++ gctUINT32 i, unused, currentID, tableLen; ++ gctPOINTER * table; ++ gckOS os = database->os; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Database=0x%08X Pointer=0x%08X", Database, Pointer); ++ ++ gcmkVERIFY_ARGUMENT(Id != gcvNULL); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ if (database->unused < 1) ++ { ++ /* Extend table. */ ++ gcmkONERROR( ++ gckOS_Allocate(os, ++ gcmSIZEOF(gctPOINTER) * (database->tableLen + gcdID_TABLE_LENGTH), ++ (gctPOINTER *)&table)); ++ ++ gcmkONERROR(gckOS_ZeroMemory(table + database->tableLen, ++ gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH)); ++ ++ /* Copy data from old table. */ ++ gckOS_MemCopy(table, ++ database->table, ++ database->tableLen * gcmSIZEOF(gctPOINTER)); ++ ++ gcmkOS_SAFE_FREE(os, database->table); ++ ++ /* Update databse with new allocated table. */ ++ database->table = table; ++ database->currentID = database->tableLen; ++ database->tableLen += gcdID_TABLE_LENGTH; ++ database->unused += gcdID_TABLE_LENGTH; ++ } ++ ++ table = database->table; ++ currentID = database->currentID; ++ tableLen = database->tableLen; ++ unused = database->unused; ++ ++ /* Connect id with pointer. */ ++ table[currentID] = Pointer; ++ ++ *Id = currentID + 1; ++ ++ /* Update the currentID. */ ++ if (--unused > 0) ++ { ++ for (i = 0; i < tableLen; i++) ++ { ++ if (++currentID >= tableLen) ++ { ++ /* Wrap to the begin. */ ++ currentID = 0; ++ } ++ ++ if (table[currentID] == gcvNULL) ++ { ++ break; ++ } ++ } ++ } ++ ++ database->table = table; ++ database->currentID = currentID; ++ database->tableLen = tableLen; ++ database->unused = unused; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_ARG("*Id=%d", *Id); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_FreeIntegerId( ++ IN gctPOINTER Database, ++ IN gctUINT32 Id ++ ) ++{ ++ gceSTATUS status; ++ gckINTEGERDB database = Database; ++ gckOS os = database->os; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Database=0x%08X Id=%d", Database, Id); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ if (!(Id > 0 && Id <= database->tableLen)) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_FOUND); ++ } ++ ++ Id -= 1; ++ ++ database->table[Id] = gcvNULL; ++ ++ if (database->unused++ == 0) ++ { ++ database->currentID = Id; ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_QueryIntegerId( ++ IN gctPOINTER Database, ++ IN gctUINT32 Id, ++ OUT gctPOINTER * Pointer ++ ) ++{ ++ gceSTATUS status; ++ gckINTEGERDB database = Database; ++ gctPOINTER pointer; ++ gckOS os = database->os; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Database=0x%08X Id=%d", Database, Id); ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ if (!(Id > 0 && Id <= database->tableLen)) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_FOUND); ++ } ++ ++ Id -= 1; ++ ++ pointer = database->table[Id]; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex)); ++ acquired = gcvFALSE; ++ ++ if (pointer) ++ { ++ *Pointer = pointer; ++ } ++ else ++ { ++ gcmkONERROR(gcvSTATUS_NOT_FOUND); ++ } ++ ++ gcmkFOOTER_ARG("*Pointer=0x%08X", *Pointer); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++ ++gctUINT32 ++gckKERNEL_AllocateNameFromPointer( ++ IN gckKERNEL Kernel, ++ IN gctPOINTER Pointer ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 name; ++ gctPOINTER database = Kernel->db->pointerDatabase; ++ ++ gcmkHEADER_ARG("Kernel=0x%X Pointer=0x%X", Kernel, Pointer); ++ ++ gcmkONERROR( ++ gckKERNEL_AllocateIntegerId(database, Pointer, &name)); ++ ++ gcmkFOOTER_ARG("name=%d", name); ++ return name; ++ ++OnError: ++ gcmkFOOTER(); ++ return 0; ++} ++ ++gctPOINTER ++gckKERNEL_QueryPointerFromName( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Name ++ ) ++{ ++ gceSTATUS status; ++ gctPOINTER pointer = gcvNULL; ++ gctPOINTER database = Kernel->db->pointerDatabase; ++ ++ gcmkHEADER_ARG("Kernel=0x%X Name=%d", Kernel, Name); ++ ++ /* Lookup in database to get pointer. */ ++ gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, &pointer)); ++ ++ gcmkFOOTER_ARG("pointer=0x%X", pointer); ++ return pointer; ++ ++OnError: ++ gcmkFOOTER(); ++ return gcvNULL; ++} ++ ++gceSTATUS ++gckKERNEL_DeleteName( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Name ++ ) ++{ ++ gctPOINTER database = Kernel->db->pointerDatabase; ++ ++ gcmkHEADER_ARG("Kernel=0x%X Name=0x%X", Kernel, Name); ++ ++ /* Free name if exists. */ ++ gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, Name)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckKERNEL_SetRecovery( ++ IN gckKERNEL Kernel, ++ IN gctBOOL Recovery, ++ IN gctUINT32 StuckDump ++ ) ++{ ++ Kernel->recovery = Recovery; ++ ++ if (Recovery == gcvFALSE) ++ { ++ /* Dump stuck information if Recovery is disabled. */ ++ Kernel->stuckDump = gcmMAX(StuckDump, gcdSTUCK_DUMP_MIDDLE); ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++ ++/******************************************************************************* ++***** Shared Buffer ************************************************************ ++*******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckKERNEL_CreateShBuffer ++** ++** Create shared buffer. ++** The shared buffer can be used across processes. Other process needs call ++** gckKERNEL_MapShBuffer before use it. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctUINT32 Size ++** Specify the shared buffer size. ++** ++** OUTPUT: ++** ++** gctSHBUF * ShBuf ++** Pointer to hold return shared buffer handle. ++*/ ++gceSTATUS ++gckKERNEL_CreateShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Size, ++ OUT gctSHBUF * ShBuf ++ ) ++{ ++ gceSTATUS status; ++ gcsSHBUF_PTR shBuf = gcvNULL; ++ ++ gcmkHEADER_ARG("Kernel=0x%X, Size=%u", Kernel, Size); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ if (Size == 0) ++ { ++ /* Invalid size. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ else if (Size > 1024) ++ { ++ /* Limite shared buffer size. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ /* Create a shared buffer structure. */ ++ gcmkONERROR( ++ gckOS_Allocate(Kernel->os, ++ sizeof (gcsSHBUF), ++ (gctPOINTER *)&shBuf)); ++ ++ /* Initialize shared buffer. */ ++ shBuf->id = 0; ++ shBuf->reference = gcvNULL; ++ shBuf->size = Size; ++ shBuf->data = gcvNULL; ++ ++ /* Allocate integer id for this shared buffer. */ ++ gcmkONERROR( ++ gckKERNEL_AllocateIntegerId(Kernel->db->pointerDatabase, ++ shBuf, ++ &shBuf->id)); ++ ++ /* Allocate atom. */ ++ gcmkONERROR(gckOS_AtomConstruct(Kernel->os, &shBuf->reference)); ++ ++ /* Set default reference count to 1. */ ++ gcmkVERIFY_OK(gckOS_AtomSet(Kernel->os, shBuf->reference, 1)); ++ ++ /* Return integer id. */ ++ *ShBuf = (gctSHBUF)(gctUINTPTR_T)shBuf->id; ++ ++ gcmkFOOTER_ARG("*ShBuf=%u", shBuf->id); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Error roll back. */ ++ if (shBuf != gcvNULL) ++ { ++ if (shBuf->id != 0) ++ { ++ gcmkVERIFY_OK( ++ gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase, ++ shBuf->id)); ++ } ++ ++ gcmkOS_SAFE_FREE(Kernel->os, shBuf); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_DestroyShBuffer ++** ++** Destroy shared buffer. ++** This will decrease reference of specified shared buffer and do actual ++** destroy when no reference on it. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctSHBUF ShBuf ++** Specify the shared buffer to be destroyed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_DestroyShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf ++ ) ++{ ++ gceSTATUS status; ++ gcsSHBUF_PTR shBuf; ++ gctINT32 oldValue = 0; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u", ++ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL); ++ ++ /* Acquire mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, ++ Kernel->db->pointerDatabaseMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Find shared buffer structure. */ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase, ++ (gctUINT32)(gctUINTPTR_T)ShBuf, ++ (gctPOINTER)&shBuf)); ++ ++ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf); ++ ++ /* Decrease the reference count. */ ++ gckOS_AtomDecrement(Kernel->os, shBuf->reference, &oldValue); ++ ++ if (oldValue == 1) ++ { ++ /* Free integer id. */ ++ gcmkVERIFY_OK( ++ gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase, ++ shBuf->id)); ++ ++ /* Free atom. */ ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, shBuf->reference)); ++ ++ if (shBuf->data) ++ { ++ gcmkOS_SAFE_FREE(Kernel->os, shBuf->data); ++ shBuf->data = gcvNULL; ++ } ++ ++ /* Free the shared buffer. */ ++ gcmkOS_SAFE_FREE(Kernel->os, shBuf); ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_MapShBuffer ++** ++** Map shared buffer into this process so that it can be used in this process. ++** This will increase reference count on the specified shared buffer. ++** Call gckKERNEL_DestroyShBuffer to dereference. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctSHBUF ShBuf ++** Specify the shared buffer to be mapped. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_MapShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf ++ ) ++{ ++ gceSTATUS status; ++ gcsSHBUF_PTR shBuf; ++ gctINT32 oldValue = 0; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u", ++ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL); ++ ++ /* Acquire mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, ++ Kernel->db->pointerDatabaseMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Find shared buffer structure. */ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase, ++ (gctUINT32)(gctUINTPTR_T)ShBuf, ++ (gctPOINTER)&shBuf)); ++ ++ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf); ++ ++ /* Increase the reference count. */ ++ gckOS_AtomIncrement(Kernel->os, shBuf->reference, &oldValue); ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_WriteShBuffer ++** ++** Write user data into shared buffer. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctSHBUF ShBuf ++** Specify the shared buffer to be written to. ++** ++** gctPOINTER UserData ++** User mode pointer to hold the source data. ++** ++** gctUINT32 ByteCount ++** Specify number of bytes to write. If this is larger than ++** shared buffer size, gcvSTATUS_INVALID_ARGUMENT is returned. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_WriteShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf, ++ IN gctPOINTER UserData, ++ IN gctUINT32 ByteCount ++ ) ++{ ++ gceSTATUS status; ++ gcsSHBUF_PTR shBuf; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u UserData=0x%X ByteCount=%u", ++ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL); ++ ++ /* Acquire mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, ++ Kernel->db->pointerDatabaseMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Find shared buffer structure. */ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase, ++ (gctUINT32)(gctUINTPTR_T)ShBuf, ++ (gctPOINTER)&shBuf)); ++ ++ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf); ++ ++ if ((ByteCount > shBuf->size) || ++ (ByteCount == 0) || ++ (UserData == gcvNULL)) ++ { ++ /* Exceeds buffer max size or invalid. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ if (shBuf->data == gcvNULL) ++ { ++ /* Allocate buffer data when first time write. */ ++ gcmkONERROR(gckOS_Allocate(Kernel->os, ByteCount, &shBuf->data)); ++ } ++ ++ /* Copy data from user. */ ++ gcmkONERROR( ++ gckOS_CopyFromUserData(Kernel->os, ++ shBuf->data, ++ UserData, ++ ByteCount)); ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_ReadShBuffer ++** ++** Read data from shared buffer and copy to user pointer. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctSHBUF ShBuf ++** Specify the shared buffer to be read from. ++** ++** gctPOINTER UserData ++** User mode pointer to save output data. ++** ++** gctUINT32 ByteCount ++** Specify number of bytes to read. ++** If this is larger than shared buffer size, only avaiable bytes are ++** copied. If smaller, copy requested size. ++** ++** OUTPUT: ++** ++** gctUINT32 * BytesRead ++** Pointer to hold how many bytes actually read from shared buffer. ++*/ ++gceSTATUS ++gckKERNEL_ReadShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf, ++ IN gctPOINTER UserData, ++ IN gctUINT32 ByteCount, ++ OUT gctUINT32 * BytesRead ++ ) ++{ ++ gceSTATUS status; ++ gcsSHBUF_PTR shBuf; ++ gctUINT32 bytes; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u UserData=0x%X ByteCount=%u", ++ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL); ++ ++ /* Acquire mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, ++ Kernel->db->pointerDatabaseMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Find shared buffer structure. */ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase, ++ (gctUINT32)(gctUINTPTR_T)ShBuf, ++ (gctPOINTER)&shBuf)); ++ ++ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf); ++ ++ if (shBuf->data == gcvNULL) ++ { ++ *BytesRead = 0; ++ ++ /* No data in shared buffer, skip copy. */ ++ status = gcvSTATUS_SKIP; ++ goto OnError; ++ } ++ else if (ByteCount == 0) ++ { ++ /* Invalid size to read. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Determine bytes to copy. */ ++ bytes = (ByteCount < shBuf->size) ? ByteCount : shBuf->size; ++ ++ /* Copy data to user. */ ++ gcmkONERROR( ++ gckOS_CopyToUserData(Kernel->os, ++ shBuf->data, ++ UserData, ++ bytes)); ++ ++ /* Return copied size. */ ++ *BytesRead = bytes; ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_ARG("*BytesRead=%u", bytes); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++ ++/******************************************************************************* ++***** Test Code **************************************************************** ++*******************************************************************************/ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_command.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_command.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_command.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_command.c 2016-06-19 22:11:55.137151030 +0200 +@@ -0,0 +1,3075 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++#include "gc_hal_kernel_context.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_COMMAND ++ ++/******************************************************************************\ ++********************************* Support Code ********************************* ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** _NewQueue ++** ++** Allocate a new command queue. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object. ++** ++** OUTPUT: ++** ++** gckCOMMAND Command ++** gckCOMMAND object has been updated with a new command queue. ++*/ ++static gceSTATUS ++_NewQueue( ++ IN OUT gckCOMMAND Command ++ ) ++{ ++ gceSTATUS status; ++ gctINT currentIndex, newIndex; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Switch to the next command buffer. */ ++ currentIndex = Command->index; ++ newIndex = (currentIndex + 1) % gcdCOMMAND_QUEUES; ++ ++ /* Wait for availability. */ ++#if gcdDUMP_COMMAND ++ gcmkPRINT("@[kernel.waitsignal]"); ++#endif ++ ++ gcmkONERROR(gckOS_WaitSignal( ++ Command->os, ++ Command->queues[newIndex].signal, ++ gcvINFINITE ++ )); ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ if (newIndex < currentIndex) ++ { ++ Command->wrapCount += 1; ++ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_INFO, gcvZONE_COMMAND, ++ 2 * 4, ++ "%s(%d): queue array wrapped around.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_INFO, gcvZONE_COMMAND, ++ 3 * 4, ++ "%s(%d): total queue wrap arounds %d.\n", ++ __FUNCTION__, __LINE__, Command->wrapCount ++ ); ++ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_INFO, gcvZONE_COMMAND, ++ 3 * 4, ++ "%s(%d): switched to queue %d.\n", ++ __FUNCTION__, __LINE__, newIndex ++ ); ++#endif ++ ++ /* Update gckCOMMAND object with new command queue. */ ++ Command->index = newIndex; ++ Command->newQueue = gcvTRUE; ++ Command->logical = Command->queues[newIndex].logical; ++ Command->address = Command->queues[newIndex].address; ++ Command->offset = 0; ++ ++ gcmkONERROR(gckOS_GetPhysicalAddress( ++ Command->os, ++ Command->logical, ++ (gctUINT32 *) &Command->physical ++ )); ++ ++ if (currentIndex != -1) ++ { ++ /* Mark the command queue as available. */ ++ gcmkONERROR(gckEVENT_Signal( ++ Command->kernel->eventObj, ++ Command->queues[currentIndex].signal, ++ gcvKERNEL_COMMAND ++ )); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("Command->index=%d", Command->index); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++_IncrementCommitAtom( ++ IN gckCOMMAND Command, ++ IN gctBOOL Increment ++ ) ++{ ++ gceSTATUS status; ++ gckHARDWARE hardware; ++ gctINT32 atomValue; ++ gctBOOL powerAcquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Extract the gckHARDWARE and gckEVENT objects. */ ++ hardware = Command->kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ /* Increment the commit atom. */ ++ if (Increment) ++ { ++ /* Grab the power mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex( ++ Command->os, hardware->powerMutex, gcvINFINITE ++ )); ++ powerAcquired = gcvTRUE; ++ ++ gcmkONERROR(gckOS_AtomIncrement( ++ Command->os, Command->atomCommit, &atomValue ++ )); ++ ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex( ++ Command->os, hardware->powerMutex ++ )); ++ powerAcquired = gcvFALSE; ++ } ++ else ++ { ++ gcmkONERROR(gckOS_AtomDecrement( ++ Command->os, Command->atomCommit, &atomValue ++ )); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (powerAcquired) ++ { ++ /* Release the power mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex( ++ Command->os, hardware->powerMutex ++ )); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++_FlushMMU( ++ IN gckCOMMAND Command ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 oldValue; ++ gckHARDWARE hardware = Command->kernel->hardware; ++ gctBOOL pause = gcvFALSE; ++ ++ gctUINT8_PTR pointer; ++ gctUINT32 eventBytes; ++ gctUINT32 endBytes; ++ gctUINT32 bufferSize; ++ gctUINT32 executeBytes; ++ gctUINT32 waitLinkBytes; ++ ++ gcmkONERROR(gckOS_AtomicExchange(Command->os, ++ hardware->pageTableDirty, ++ 0, ++ &oldValue)); ++ ++ if (oldValue) ++ { ++ /* Page Table is upated, flush mmu before commit. */ ++ gcmkONERROR(gckHARDWARE_FlushMMU(hardware)); ++ ++ if ((oldValue & gcvPAGE_TABLE_DIRTY_BIT_FE) ++ && (hardware->endAfterFlushMmuCache) ++ ) ++ { ++ pause = gcvTRUE; ++ } ++ } ++ ++ if (pause) ++ { ++ /* Query size. */ ++ gcmkONERROR(gckHARDWARE_Event(hardware, gcvNULL, 0, gcvKERNEL_PIXEL, &eventBytes)); ++ gcmkONERROR(gckHARDWARE_End(hardware, gcvNULL, &endBytes)); ++ ++ executeBytes = eventBytes + endBytes; ++ ++ gcmkONERROR(gckHARDWARE_WaitLink( ++ hardware, ++ gcvNULL, ++ Command->offset + executeBytes, ++ &waitLinkBytes, ++ gcvNULL, ++ gcvNULL ++ )); ++ ++ /* Reserve space. */ ++ gcmkONERROR(gckCOMMAND_Reserve( ++ Command, ++ executeBytes, ++ (gctPOINTER *)&pointer, ++ &bufferSize ++ )); ++ ++ /* Append EVENT(29). */ ++ gcmkONERROR(gckHARDWARE_Event( ++ hardware, ++ pointer, ++ 29, ++ gcvKERNEL_PIXEL, ++ &eventBytes ++ )); ++ ++ /* Append END. */ ++ pointer += eventBytes; ++ gcmkONERROR(gckHARDWARE_End(hardware, pointer, &endBytes)); ++ ++ /* Store address to queue. */ ++ gcmkONERROR(gckENTRYQUEUE_Enqueue( ++ Command->kernel, ++ &Command->queue, ++ Command->address + Command->offset + executeBytes, ++ waitLinkBytes ++ )); ++ ++ gcmkONERROR(gckCOMMAND_Execute(Command, executeBytes)); ++ } ++ ++ return gcvSTATUS_OK; ++OnError: ++ return status; ++} ++ ++static void ++_DumpBuffer( ++ IN gctPOINTER Buffer, ++ IN gctUINT32 GpuAddress, ++ IN gctSIZE_T Size ++ ) ++{ ++ gctSIZE_T i, line, left; ++ gctUINT32_PTR data = Buffer; ++ ++ line = Size / 32; ++ left = Size % 32; ++ ++ for (i = 0; i < line; i++) ++ { ++ gcmkPRINT("%X : %08X %08X %08X %08X %08X %08X %08X %08X ", ++ GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); ++ data += 8; ++ GpuAddress += 8 * 4; ++ } ++ ++ switch(left) ++ { ++ case 28: ++ gcmkPRINT("%X : %08X %08X %08X %08X %08X %08X %08X ", ++ GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5], data[6]); ++ break; ++ case 24: ++ gcmkPRINT("%X : %08X %08X %08X %08X %08X %08X ", ++ GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5]); ++ break; ++ case 20: ++ gcmkPRINT("%X : %08X %08X %08X %08X %08X ", ++ GpuAddress, data[0], data[1], data[2], data[3], data[4]); ++ break; ++ case 16: ++ gcmkPRINT("%X : %08X %08X %08X %08X ", ++ GpuAddress, data[0], data[1], data[2], data[3]); ++ break; ++ case 12: ++ gcmkPRINT("%X : %08X %08X %08X ", ++ GpuAddress, data[0], data[1], data[2]); ++ break; ++ case 8: ++ gcmkPRINT("%X : %08X %08X ", ++ GpuAddress, data[0], data[1]); ++ break; ++ case 4: ++ gcmkPRINT("%X : %08X ", ++ GpuAddress, data[0]); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ++_DumpKernelCommandBuffer( ++ IN gckCOMMAND Command ++ ) ++{ ++ gctINT i; ++ gctUINT32 physical = 0; ++ gctPOINTER entry = gcvNULL; ++ ++ for (i = 0; i < gcdCOMMAND_QUEUES; i++) ++ { ++ entry = Command->queues[i].logical; ++ ++ gckOS_GetPhysicalAddress(Command->os, entry, &physical); ++ ++ gcmkPRINT("Kernel command buffer %d\n", i); ++ ++ _DumpBuffer(entry, physical, Command->pageSize); ++ } ++} ++ ++/******************************************************************************\ ++****************************** gckCOMMAND API Code ****************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Construct ++** ++** Construct a new gckCOMMAND object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** OUTPUT: ++** ++** gckCOMMAND * Command ++** Pointer to a variable that will hold the pointer to the gckCOMMAND ++** object. ++*/ ++gceSTATUS ++gckCOMMAND_Construct( ++ IN gckKERNEL Kernel, ++ OUT gckCOMMAND * Command ++ ) ++{ ++ gckOS os; ++ gckCOMMAND command = gcvNULL; ++ gceSTATUS status; ++ gctINT i; ++ gctPOINTER pointer = gcvNULL; ++ gctSIZE_T pageSize; ++ ++ gcmkHEADER_ARG("Kernel=0x%x", Kernel); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Command != gcvNULL); ++ ++ /* Extract the gckOS object. */ ++ os = Kernel->os; ++ ++ /* Allocate the gckCOMMAND structure. */ ++ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckCOMMAND), &pointer)); ++ command = pointer; ++ ++ /* Reset the entire object. */ ++ gcmkONERROR(gckOS_ZeroMemory(command, gcmSIZEOF(struct _gckCOMMAND))); ++ ++ /* Initialize the gckCOMMAND object.*/ ++ command->object.type = gcvOBJ_COMMAND; ++ command->kernel = Kernel; ++ command->os = os; ++ ++ /* Get the command buffer requirements. */ ++ gcmkONERROR(gckHARDWARE_QueryCommandBuffer( ++ Kernel->hardware, ++ &command->alignment, ++ &command->reservedHead, ++ &command->reservedTail ++ )); ++ ++ /* Create the command queue mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(os, &command->mutexQueue)); ++ ++ /* Create the context switching mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(os, &command->mutexContext)); ++ ++#if VIVANTE_PROFILER_CONTEXT ++ /* Create the context switching mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(os, &command->mutexContextSeq)); ++#endif ++ ++ /* Create the power management semaphore. */ ++ gcmkONERROR(gckOS_CreateSemaphore(os, &command->powerSemaphore)); ++ ++ /* Create the commit atom. */ ++ gcmkONERROR(gckOS_AtomConstruct(os, &command->atomCommit)); ++ ++ /* Get the page size from teh OS. */ ++ gcmkONERROR(gckOS_GetPageSize(os, &pageSize)); ++ ++ gcmkSAFECASTSIZET(command->pageSize, pageSize); ++ ++ /* Get process ID. */ ++ gcmkONERROR(gckOS_GetProcessID(&command->kernelProcessID)); ++ ++ /* Set hardware to pipe 0. */ ++ command->pipeSelect = gcvPIPE_INVALID; ++ ++ /* Pre-allocate the command queues. */ ++ for (i = 0; i < gcdCOMMAND_QUEUES; ++i) ++ { ++ gcmkONERROR(gckOS_AllocateNonPagedMemory( ++ os, ++ gcvFALSE, ++ &pageSize, ++ &command->queues[i].physical, ++ &command->queues[i].logical ++ )); ++ ++ gcmkONERROR(gckHARDWARE_ConvertLogical( ++ Kernel->hardware, ++ command->queues[i].logical, ++ gcvFALSE, ++ &command->queues[i].address ++ )); ++ ++ gcmkONERROR(gckOS_CreateSignal( ++ os, gcvFALSE, &command->queues[i].signal ++ )); ++ ++ gcmkONERROR(gckOS_Signal( ++ os, command->queues[i].signal, gcvTRUE ++ )); ++ } ++ ++#if gcdRECORD_COMMAND ++ gcmkONERROR(gckRECORDER_Construct(os, Kernel->hardware, &command->recorder)); ++#endif ++ ++ /* No command queue in use yet. */ ++ command->index = -1; ++ command->logical = gcvNULL; ++ command->newQueue = gcvFALSE; ++ ++ /* Command is not yet running. */ ++ command->running = gcvFALSE; ++ ++ /* Command queue is idle. */ ++ command->idle = gcvTRUE; ++ ++ /* Commit stamp is zero. */ ++ command->commitStamp = 0; ++ ++ /* END event signal not created. */ ++ command->endEventSignal = gcvNULL; ++ ++ command->queue.front = 0; ++ command->queue.rear = 0; ++ command->queue.count = 0; ++ ++ /* Return pointer to the gckCOMMAND object. */ ++ *Command = command; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Command=0x%x", *Command); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (command != gcvNULL) ++ { ++ if (command->atomCommit != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(os, command->atomCommit)); ++ } ++ ++ if (command->powerSemaphore != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DestroySemaphore(os, command->powerSemaphore)); ++ } ++ ++ if (command->mutexContext != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexContext)); ++ } ++ ++#if VIVANTE_PROFILER_CONTEXT ++ if (command->mutexContextSeq != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexContextSeq)); ++ } ++#endif ++ ++ if (command->mutexQueue != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexQueue)); ++ } ++ ++ for (i = 0; i < gcdCOMMAND_QUEUES; ++i) ++ { ++ if (command->queues[i].signal != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DestroySignal( ++ os, command->queues[i].signal ++ )); ++ } ++ ++ if (command->queues[i].logical != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory( ++ os, ++ command->pageSize, ++ command->queues[i].physical, ++ command->queues[i].logical ++ )); ++ } ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, command)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Destroy ++** ++** Destroy an gckCOMMAND object. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object to destroy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_Destroy( ++ IN gckCOMMAND Command ++ ) ++{ ++ gctINT i; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ /* Stop the command queue. */ ++ gcmkVERIFY_OK(gckCOMMAND_Stop(Command, gcvFALSE)); ++ ++ for (i = 0; i < gcdCOMMAND_QUEUES; ++i) ++ { ++ gcmkASSERT(Command->queues[i].signal != gcvNULL); ++ gcmkVERIFY_OK(gckOS_DestroySignal( ++ Command->os, Command->queues[i].signal ++ )); ++ ++ gcmkASSERT(Command->queues[i].logical != gcvNULL); ++ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory( ++ Command->os, ++ Command->pageSize, ++ Command->queues[i].physical, ++ Command->queues[i].logical ++ )); ++ } ++ ++ /* END event signal. */ ++ if (Command->endEventSignal != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DestroySignal( ++ Command->os, Command->endEventSignal ++ )); ++ } ++ ++ /* Delete the context switching mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext)); ++ ++#if VIVANTE_PROFILER_CONTEXT ++ if (Command->mutexContextSeq != gcvNULL) ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContextSeq)); ++#endif ++ ++ /* Delete the command queue mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue)); ++ ++ /* Destroy the power management semaphore. */ ++ gcmkVERIFY_OK(gckOS_DestroySemaphore(Command->os, Command->powerSemaphore)); ++ ++ /* Destroy the commit atom. */ ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Command->os, Command->atomCommit)); ++ ++#if gcdRECORD_COMMAND ++ gckRECORDER_Destory(Command->os, Command->recorder); ++#endif ++ ++ /* Mark object as unknown. */ ++ Command->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckCOMMAND object. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command->os, Command)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_EnterCommit ++** ++** Acquire command queue synchronization objects. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object to destroy. ++** ++** gctBOOL FromPower ++** Determines whether the call originates from inside the power ++** management or not. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_EnterCommit( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromPower ++ ) ++{ ++ gceSTATUS status; ++ gckHARDWARE hardware; ++ gctBOOL atomIncremented = gcvFALSE; ++ gctBOOL semaAcquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Extract the gckHARDWARE and gckEVENT objects. */ ++ hardware = Command->kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ if (!FromPower) ++ { ++ /* Increment COMMIT atom to let power management know that a commit is ++ ** in progress. */ ++ gcmkONERROR(_IncrementCommitAtom(Command, gcvTRUE)); ++ atomIncremented = gcvTRUE; ++ ++ /* Notify the system the GPU has a commit. */ ++ gcmkONERROR(gckOS_Broadcast(Command->os, ++ hardware, ++ gcvBROADCAST_GPU_COMMIT)); ++ ++ /* Acquire the power management semaphore. */ ++ gcmkONERROR(gckOS_AcquireSemaphore(Command->os, ++ Command->powerSemaphore)); ++ semaAcquired = gcvTRUE; ++ } ++ ++ /* Grab the conmmand queue mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Command->os, ++ Command->mutexQueue, ++ gcvINFINITE)); ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (semaAcquired) ++ { ++ /* Release the power management semaphore. */ ++ gcmkVERIFY_OK(gckOS_ReleaseSemaphore( ++ Command->os, Command->powerSemaphore ++ )); ++ } ++ ++ if (atomIncremented) ++ { ++ /* Decrement the commit atom. */ ++ gcmkVERIFY_OK(_IncrementCommitAtom( ++ Command, gcvFALSE ++ )); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_ExitCommit ++** ++** Release command queue synchronization objects. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object to destroy. ++** ++** gctBOOL FromPower ++** Determines whether the call originates from inside the power ++** management or not. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_ExitCommit( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromPower ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Release the power mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); ++ ++ if (!FromPower) ++ { ++ /* Release the power management semaphore. */ ++ gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, ++ Command->powerSemaphore)); ++ ++ /* Decrement the commit atom. */ ++ gcmkONERROR(_IncrementCommitAtom(Command, gcvFALSE)); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Start ++** ++** Start up the command queue. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object to start. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_Start( ++ IN gckCOMMAND Command ++ ) ++{ ++ gceSTATUS status; ++ gckHARDWARE hardware; ++ gctUINT32 waitOffset = 0; ++ gctUINT32 waitLinkBytes; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->running) ++ { ++ /* Command queue already running. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* Extract the gckHARDWARE object. */ ++ hardware = Command->kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ if (Command->logical == gcvNULL) ++ { ++ /* Start at beginning of a new queue. */ ++ gcmkONERROR(_NewQueue(Command)); ++ } ++ ++ /* Start at beginning of page. */ ++ Command->offset = 0; ++ ++ /* Set abvailable number of bytes for WAIT/LINK command sequence. */ ++ waitLinkBytes = Command->pageSize; ++ ++ /* Append WAIT/LINK. */ ++ gcmkONERROR(gckHARDWARE_WaitLink( ++ hardware, ++ Command->logical, ++ 0, ++ &waitLinkBytes, ++ &waitOffset, ++ &Command->waitSize ++ )); ++ ++ Command->waitLogical = (gctUINT8_PTR) Command->logical + waitOffset; ++ Command->waitPhysical = (gctUINT8_PTR) Command->physical + waitOffset; ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the cache for the wait/link. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ Command->kernelProcessID, ++ gcvNULL, ++ (gctUINT32)Command->physical, ++ Command->logical, ++ waitLinkBytes ++ )); ++#endif ++ ++ /* Adjust offset. */ ++ Command->offset = waitLinkBytes; ++ Command->newQueue = gcvFALSE; ++ ++ /* Enable command processor. */ ++ gcmkONERROR(gckHARDWARE_Execute( ++ hardware, ++ Command->address, ++ waitLinkBytes ++ )); ++ ++ /* Command queue is running. */ ++ Command->running = gcvTRUE; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Stop ++** ++** Stop the command queue. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object to stop. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_Stop( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromRecovery ++ ) ++{ ++ gckHARDWARE hardware; ++ gceSTATUS status; ++ gctUINT32 idle; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (!Command->running) ++ { ++ /* Command queue is not running. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* Extract the gckHARDWARE object. */ ++ hardware = Command->kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ if (gckHARDWARE_IsFeatureAvailable(hardware, ++ gcvFEATURE_END_EVENT) == gcvSTATUS_TRUE) ++ { ++ /* Allocate the signal. */ ++ if (Command->endEventSignal == gcvNULL) ++ { ++ gcmkONERROR(gckOS_CreateSignal(Command->os, ++ gcvTRUE, ++ &Command->endEventSignal)); ++ } ++ ++ /* Append the END EVENT command to trigger the signal. */ ++ gcmkONERROR(gckEVENT_Stop(Command->kernel->eventObj, ++ Command->kernelProcessID, ++ Command->waitPhysical, ++ Command->waitLogical, ++ Command->endEventSignal, ++ &Command->waitSize)); ++ } ++ else ++ { ++ /* Replace last WAIT with END. */ ++ gcmkONERROR(gckHARDWARE_End( ++ hardware, Command->waitLogical, &Command->waitSize ++ )); ++ ++ /* Update queue tail pointer. */ ++ gcmkONERROR(gckHARDWARE_UpdateQueueTail(Command->kernel->hardware, ++ Command->logical, ++ Command->offset)); ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the cache for the END. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ Command->kernelProcessID, ++ gcvNULL, ++ (gctUINT32)Command->waitPhysical, ++ Command->waitLogical, ++ Command->waitSize ++ )); ++#endif ++ ++ /* Wait for idle. */ ++ gcmkONERROR(gckHARDWARE_GetIdle(hardware, !FromRecovery, &idle)); ++ } ++ ++ /* Command queue is no longer running. */ ++ Command->running = gcvFALSE; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Commit ++** ++** Commit a command buffer to the command queue. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to a gckCOMMAND object. ++** ++** gckCONTEXT Context ++** Pointer to a gckCONTEXT object. ++** ++** gcoCMDBUF CommandBuffer ++** Pointer to a gcoCMDBUF object. ++** ++** gcsSTATE_DELTA_PTR StateDelta ++** Pointer to the state delta. ++** ++** gctUINT32 ProcessID ++** Current process ID. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_Commit( ++ IN gckCOMMAND Command, ++ IN gckCONTEXT Context, ++ IN gcoCMDBUF CommandBuffer, ++ IN gcsSTATE_DELTA_PTR StateDelta, ++ IN gcsQUEUE_PTR EventQueue, ++ IN gctUINT32 ProcessID ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL commitEntered = gcvFALSE; ++ gctBOOL contextAcquired = gcvFALSE; ++ gckHARDWARE hardware; ++ gctBOOL needCopy = gcvFALSE; ++ gcsQUEUE_PTR eventRecord = gcvNULL; ++ gcsQUEUE _eventRecord; ++ gcsQUEUE_PTR nextEventRecord; ++ gctBOOL commandBufferMapped = gcvFALSE; ++ gcoCMDBUF commandBufferObject = gcvNULL; ++ ++#if !gcdNULL_DRIVER ++ gcsCONTEXT_PTR contextBuffer; ++ struct _gcoCMDBUF _commandBufferObject; ++ gctPHYS_ADDR commandBufferPhysical; ++ gctUINT8_PTR commandBufferLogical = gcvNULL; ++ gctUINT32 commandBufferAddress = 0; ++ gctUINT8_PTR commandBufferLink = gcvNULL; ++ gctUINT commandBufferSize; ++ gctSIZE_T nopBytes; ++ gctUINT32 pipeBytes; ++ gctUINT32 linkBytes; ++ gctSIZE_T bytes; ++ gctUINT32 offset; ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ gctPHYS_ADDR entryPhysical; ++#endif ++ gctPOINTER entryLogical; ++ gctUINT32 entryAddress; ++ gctUINT32 entryBytes; ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ gctPHYS_ADDR exitPhysical; ++#endif ++ gctPOINTER exitLogical; ++ gctUINT32 exitAddress; ++ gctUINT32 exitBytes; ++ gctPHYS_ADDR waitLinkPhysical; ++ gctPOINTER waitLinkLogical; ++ gctUINT32 waitLinkAddress; ++ gctUINT32 waitLinkBytes; ++ gctPHYS_ADDR waitPhysical; ++ gctPOINTER waitLogical; ++ gctUINT32 waitOffset; ++ gctUINT32 waitSize; ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gctSIZE_T mmuConfigureBytes; ++ gctPOINTER mmuConfigureLogical = gcvNULL; ++ gctUINT32 mmuConfigureAddress; ++ gctPOINTER mmuConfigurePhysical = 0; ++ gctSIZE_T mmuConfigureWaitLinkOffset; ++ gckMMU mmu; ++ gctSIZE_T reservedBytes; ++ gctUINT32 oldValue; ++#endif ++ ++#if gcdDUMP_COMMAND ++ gctPOINTER contextDumpLogical = gcvNULL; ++ gctSIZE_T contextDumpBytes = 0; ++ gctPOINTER bufferDumpLogical = gcvNULL; ++ gctSIZE_T bufferDumpBytes = 0; ++# endif ++#endif ++ ++#if VIVANTE_PROFILER_CONTEXT ++ gctBOOL sequenceAcquired = gcvFALSE; ++#endif ++ ++ gctPOINTER pointer = gcvNULL; ++ ++ gcmkHEADER_ARG( ++ "Command=0x%x CommandBuffer=0x%x ProcessID=%d", ++ Command, CommandBuffer, ProcessID ++ ); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ if (Command->kernel->hardware->type== gcvHARDWARE_2D) ++ { ++ /* There is no context for 2D. */ ++ Context = gcvNULL; ++ } ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkONERROR(gckKERNEL_GetProcessMMU(Command->kernel, &mmu)); ++ ++ gcmkONERROR(gckOS_AtomicExchange(Command->os, ++ mmu->pageTableDirty[Command->kernel->core], ++ 0, ++ &oldValue)); ++#else ++#endif ++ ++#if VIVANTE_PROFILER_CONTEXT ++ if((Command->kernel->hardware->gpuProfiler) && (Command->kernel->profileEnable)) ++ { ++ /* Acquire the context sequnence mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex( ++ Command->os, Command->mutexContextSeq, gcvINFINITE ++ )); ++ sequenceAcquired = gcvTRUE; ++ } ++#endif ++ ++ /* Acquire the command queue. */ ++ gcmkONERROR(gckCOMMAND_EnterCommit(Command, gcvFALSE)); ++ commitEntered = gcvTRUE; ++ ++ /* Acquire the context switching mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex( ++ Command->os, Command->mutexContext, gcvINFINITE ++ )); ++ contextAcquired = gcvTRUE; ++ ++ /* Extract the gckHARDWARE and gckEVENT objects. */ ++ hardware = Command->kernel->hardware; ++ ++ /* Check wehther we need to copy the structures or not. */ ++ gcmkONERROR(gckOS_QueryNeedCopy(Command->os, ProcessID, &needCopy)); ++ ++#if gcdNULL_DRIVER ++ /* Context switch required? */ ++ if ((Context != gcvNULL) && (Command->currContext != Context)) ++ { ++ /* Yes, merge in the deltas. */ ++ gckCONTEXT_Update(Context, ProcessID, StateDelta); ++ ++ /* Update the current context. */ ++ Command->currContext = Context; ++ } ++#else ++ if (needCopy) ++ { ++ commandBufferObject = &_commandBufferObject; ++ ++ gcmkONERROR(gckOS_CopyFromUserData( ++ Command->os, ++ commandBufferObject, ++ CommandBuffer, ++ gcmSIZEOF(struct _gcoCMDBUF) ++ )); ++ ++ gcmkVERIFY_OBJECT(commandBufferObject, gcvOBJ_COMMANDBUFFER); ++ } ++ else ++ { ++ gcmkONERROR(gckOS_MapUserPointer( ++ Command->os, ++ CommandBuffer, ++ gcmSIZEOF(struct _gcoCMDBUF), ++ &pointer ++ )); ++ ++ commandBufferObject = pointer; ++ ++ gcmkVERIFY_OBJECT(commandBufferObject, gcvOBJ_COMMANDBUFFER); ++ commandBufferMapped = gcvTRUE; ++ } ++ ++ /* Query the size of NOP command. */ ++ gcmkONERROR(gckHARDWARE_Nop( ++ hardware, gcvNULL, &nopBytes ++ )); ++ ++ /* Query the size of pipe select command sequence. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ hardware, gcvNULL, gcvPIPE_3D, &pipeBytes ++ )); ++ ++ /* Query the size of LINK command. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, gcvNULL, 0, 0, &linkBytes ++ )); ++ ++ /* Compute the command buffer entry and the size. */ ++ commandBufferLogical ++ = (gctUINT8_PTR) gcmUINT64_TO_PTR(commandBufferObject->logical) ++ + commandBufferObject->startOffset; ++ ++ /* Get the hardware address. */ ++ if (Command->kernel->virtualCommandBuffer) ++ { ++ gcmkONERROR(gckKERNEL_GetGPUAddress( ++ Command->kernel, ++ commandBufferLogical, ++ gcvTRUE, ++ &commandBufferAddress ++ )); ++ } ++ else ++ { ++ gcmkONERROR(gckHARDWARE_ConvertLogical( ++ hardware, ++ commandBufferLogical, ++ gcvTRUE, ++ &commandBufferAddress ++ )); ++ } ++ ++ /* Get the physical address. */ ++ gcmkONERROR(gckOS_UserLogicalToPhysical( ++ Command->os, ++ commandBufferLogical, ++ (gctUINT32_PTR)&commandBufferPhysical ++ )); ++ ++ commandBufferSize ++ = commandBufferObject->offset ++ + Command->reservedTail ++ - commandBufferObject->startOffset; ++ ++ gcmkONERROR(_FlushMMU(Command)); ++ ++ /* Get the current offset. */ ++ offset = Command->offset; ++ ++ /* Compute number of bytes left in current kernel command queue. */ ++ bytes = Command->pageSize - offset; ++ ++ /* Query the size of WAIT/LINK command sequence. */ ++ gcmkONERROR(gckHARDWARE_WaitLink( ++ hardware, ++ gcvNULL, ++ offset, ++ &waitLinkBytes, ++ gcvNULL, ++ gcvNULL ++ )); ++ ++ /* Is there enough space in the current command queue? */ ++ if (bytes < waitLinkBytes) ++ { ++ /* No, create a new one. */ ++ gcmkONERROR(_NewQueue(Command)); ++ ++ /* Get the new current offset. */ ++ offset = Command->offset; ++ ++ /* Recompute the number of bytes in the new kernel command queue. */ ++ bytes = Command->pageSize - offset; ++ gcmkASSERT(bytes >= waitLinkBytes); ++ } ++ ++ /* Compute the location if WAIT/LINK command sequence. */ ++ waitLinkPhysical = (gctUINT8_PTR) Command->physical + offset; ++ waitLinkLogical = (gctUINT8_PTR) Command->logical + offset; ++ waitLinkAddress = Command->address + offset; ++ ++ /* Context switch required? */ ++ if (Context == gcvNULL) ++ { ++ /* See if we have to switch pipes for the command buffer. */ ++ if (commandBufferObject->entryPipe == Command->pipeSelect) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the entry command buffer pipes ++ ** are different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* Compute the entry. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) commandBufferPhysical + offset; ++#endif ++ entryLogical = commandBufferLogical + offset; ++ entryAddress = commandBufferAddress + offset; ++ entryBytes = commandBufferSize - offset; ++ ++ Command->currContext = gcvNULL; ++ } ++ else if (Command->currContext != Context) ++ { ++ /* Temporary disable context length oprimization. */ ++ Context->dirty = gcvTRUE; ++ ++ /* Get the current context buffer. */ ++ contextBuffer = Context->buffer; ++ ++ /* Yes, merge in the deltas. */ ++ gcmkONERROR(gckCONTEXT_Update(Context, ProcessID, StateDelta)); ++ ++ /* Determine context entry and exit points. */ ++ if (0) ++ { ++ /* Reset 2D dirty flag. */ ++ Context->dirty2D = gcvFALSE; ++ ++ if (Context->dirty || commandBufferObject->using3D) ++ { ++ /*************************************************************** ++ ** SWITCHING CONTEXT: 2D and 3D are used. ++ */ ++ ++ /* Reset 3D dirty flag. */ ++ Context->dirty3D = gcvFALSE; ++ ++ /* Compute the entry. */ ++ if (Command->pipeSelect == gcvPIPE_2D) ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; ++ entryAddress = contextBuffer->address + pipeBytes; ++ entryBytes = Context->bufferSize - pipeBytes; ++ } ++ else ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical; ++ entryAddress = contextBuffer->address; ++ entryBytes = Context->bufferSize; ++ } ++ ++ /* See if we have to switch pipes between the context ++ and command buffers. */ ++ if (commandBufferObject->entryPipe == gcvPIPE_3D) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the initial context pipes are ++ different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* Ensure the NOP between 2D and 3D is in place so that the ++ execution falls through from 2D to 3D. */ ++ gcmkONERROR(gckHARDWARE_Nop( ++ hardware, ++ contextBuffer->link2D, ++ &nopBytes ++ )); ++ ++ /* Generate a LINK from the context buffer to ++ the command buffer. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ contextBuffer->link3D, ++ commandBufferAddress + offset, ++ commandBufferSize - offset, ++ &linkBytes ++ )); ++ ++ /* Mark context as not dirty. */ ++ Context->dirty = gcvFALSE; ++ } ++ else ++ { ++ /*************************************************************** ++ ** SWITCHING CONTEXT: 2D only command buffer. ++ */ ++ ++ /* Mark 3D as dirty. */ ++ Context->dirty3D = gcvTRUE; ++ ++ /* Compute the entry. */ ++ if (Command->pipeSelect == gcvPIPE_2D) ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; ++ entryAddress = contextBuffer->address + pipeBytes; ++ entryBytes = Context->entryOffset3D - pipeBytes; ++ } ++ else ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical; ++ entryAddress = contextBuffer->address; ++ entryBytes = Context->entryOffset3D; ++ } ++ ++ /* Store the current context buffer. */ ++ Context->dirtyBuffer = contextBuffer; ++ ++ /* See if we have to switch pipes between the context ++ and command buffers. */ ++ if (commandBufferObject->entryPipe == gcvPIPE_2D) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the initial context pipes are ++ different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* 3D is not used, generate a LINK from the end of 2D part of ++ the context buffer to the command buffer. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ contextBuffer->link2D, ++ commandBufferAddress + offset, ++ commandBufferSize - offset, ++ &linkBytes ++ )); ++ } ++ } ++ ++ /* Not using 2D. */ ++ else ++ { ++ ++ /* Store the current context buffer. */ ++ Context->dirtyBuffer = contextBuffer; ++ ++ if (Context->dirty || commandBufferObject->using3D) ++ { ++ /*************************************************************** ++ ** SWITCHING CONTEXT: 3D only command buffer. ++ */ ++ ++ /* Reset 3D dirty flag. */ ++ Context->dirty3D = gcvFALSE; ++ ++ /* Determine context buffer entry offset. */ ++ offset = (Command->pipeSelect == gcvPIPE_3D) ++ ++ /* Skip pipe switching sequence. */ ++ ? Context->entryOffset3D + Context->pipeSelectBytes ++ ++ /* Do not skip pipe switching sequence. */ ++ : Context->entryOffset3D; ++ ++ /* Compute the entry. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical + offset; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical + offset; ++ entryAddress = contextBuffer->address + offset; ++ entryBytes = Context->bufferSize - offset; ++ ++ /* See if we have to switch pipes between the context ++ and command buffers. */ ++ if (commandBufferObject->entryPipe == gcvPIPE_3D) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the initial context pipes are ++ different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* Generate a LINK from the context buffer to ++ the command buffer. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ contextBuffer->link3D, ++ commandBufferAddress + offset, ++ commandBufferSize - offset, ++ &linkBytes ++ )); ++ } ++ else ++ { ++ /*************************************************************** ++ ** SWITCHING CONTEXT: "XD" command buffer - neither 2D nor 3D. ++ */ ++ ++ /* Mark 3D as dirty. */ ++ Context->dirty3D = gcvTRUE; ++ ++ /* Compute the entry. */ ++ if (Command->pipeSelect == gcvPIPE_3D) ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical ++ = (gctUINT8_PTR) contextBuffer->physical ++ + Context->entryOffsetXDFrom3D; ++#endif ++ entryLogical ++ = (gctUINT8_PTR) contextBuffer->logical ++ + Context->entryOffsetXDFrom3D; ++ ++ entryAddress ++ = contextBuffer->address ++ + Context->entryOffsetXDFrom3D; ++ ++ entryBytes ++ = Context->bufferSize ++ - Context->entryOffsetXDFrom3D; ++ } ++ else ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical ++ = (gctUINT8_PTR) contextBuffer->physical ++ + Context->entryOffsetXDFrom2D; ++#endif ++ entryLogical ++ = (gctUINT8_PTR) contextBuffer->logical ++ + Context->entryOffsetXDFrom2D; ++ ++ entryAddress ++ = contextBuffer->address ++ + Context->entryOffsetXDFrom2D; ++ ++ entryBytes ++ = Context->totalSize ++ - Context->entryOffsetXDFrom2D; ++ } ++ ++ /* See if we have to switch pipes between the context ++ and command buffers. */ ++ if (commandBufferObject->entryPipe == gcvPIPE_3D) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the initial context pipes are ++ different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* Generate a LINK from the context buffer to ++ the command buffer. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ contextBuffer->link3D, ++ commandBufferAddress + offset, ++ commandBufferSize - offset, ++ &linkBytes ++ )); ++ } ++ } ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the context buffer cache. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ Command->kernelProcessID, ++ gcvNULL, ++ (gctUINT32)entryPhysical, ++ entryLogical, ++ entryBytes ++ )); ++#endif ++ ++ /* Update the current context. */ ++ Command->currContext = Context; ++ ++#if gcdDUMP_COMMAND ++ contextDumpLogical = entryLogical; ++ contextDumpBytes = entryBytes; ++#endif ++ ++#if gcdRECORD_COMMAND ++ gckRECORDER_Record( ++ Command->recorder, ++ gcvNULL, ++ 0xFFFFFFFF, ++ entryLogical, ++ entryBytes - 8 ++ ); ++#endif ++ } ++ ++ /* Same context. */ ++ else ++ { ++ /* Determine context entry and exit points. */ ++ if (commandBufferObject->using2D && Context->dirty2D) ++ { ++ /* Reset 2D dirty flag. */ ++ Context->dirty2D = gcvFALSE; ++ ++ /* Get the "dirty" context buffer. */ ++ contextBuffer = Context->dirtyBuffer; ++ ++ if (commandBufferObject->using3D && Context->dirty3D) ++ { ++ /* Reset 3D dirty flag. */ ++ Context->dirty3D = gcvFALSE; ++ ++ /* Compute the entry. */ ++ if (Command->pipeSelect == gcvPIPE_2D) ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; ++ entryAddress = contextBuffer->address + pipeBytes; ++ entryBytes = Context->bufferSize - pipeBytes; ++ } ++ else ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical; ++ entryAddress = contextBuffer->address; ++ entryBytes = Context->bufferSize; ++ } ++ ++ /* See if we have to switch pipes between the context ++ and command buffers. */ ++ if (commandBufferObject->entryPipe == gcvPIPE_3D) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the initial context pipes are ++ different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* Ensure the NOP between 2D and 3D is in place so that the ++ execution falls through from 2D to 3D. */ ++ gcmkONERROR(gckHARDWARE_Nop( ++ hardware, ++ contextBuffer->link2D, ++ &nopBytes ++ )); ++ ++ /* Generate a LINK from the context buffer to ++ the command buffer. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ contextBuffer->link3D, ++ commandBufferAddress + offset, ++ commandBufferSize - offset, ++ &linkBytes ++ )); ++ } ++ else ++ { ++ /* Compute the entry. */ ++ if (Command->pipeSelect == gcvPIPE_2D) ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; ++ entryAddress = contextBuffer->address + pipeBytes; ++ entryBytes = Context->entryOffset3D - pipeBytes; ++ } ++ else ++ { ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical; ++ entryAddress = contextBuffer->address; ++ entryBytes = Context->entryOffset3D; ++ } ++ ++ /* See if we have to switch pipes between the context ++ and command buffers. */ ++ if (commandBufferObject->entryPipe == gcvPIPE_2D) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the initial context pipes are ++ different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* 3D is not used, generate a LINK from the end of 2D part of ++ the context buffer to the command buffer. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ contextBuffer->link2D, ++ commandBufferAddress + offset, ++ commandBufferSize - offset, ++ &linkBytes ++ )); ++ } ++ } ++ else ++ { ++ if (commandBufferObject->using3D && Context->dirty3D) ++ { ++ /* Reset 3D dirty flag. */ ++ Context->dirty3D = gcvFALSE; ++ ++ /* Get the "dirty" context buffer. */ ++ contextBuffer = Context->dirtyBuffer; ++ ++ /* Determine context buffer entry offset. */ ++ offset = (Command->pipeSelect == gcvPIPE_3D) ++ ++ /* Skip pipe switching sequence. */ ++ ? Context->entryOffset3D + pipeBytes ++ ++ /* Do not skip pipe switching sequence. */ ++ : Context->entryOffset3D; ++ ++ /* Compute the entry. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) contextBuffer->physical + offset; ++#endif ++ entryLogical = (gctUINT8_PTR) contextBuffer->logical + offset; ++ entryAddress = contextBuffer->address + offset; ++ entryBytes = Context->bufferSize - offset; ++ ++ /* See if we have to switch pipes between the context ++ and command buffers. */ ++ if (commandBufferObject->entryPipe == gcvPIPE_3D) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the initial context pipes are ++ different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* Generate a LINK from the context buffer to ++ the command buffer. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ contextBuffer->link3D, ++ commandBufferAddress + offset, ++ commandBufferSize - offset, ++ &linkBytes ++ )); ++ } ++ else ++ { ++ /* See if we have to switch pipes for the command buffer. */ ++ if (commandBufferObject->entryPipe == Command->pipeSelect) ++ { ++ /* Skip pipe switching sequence. */ ++ offset = pipeBytes; ++ } ++ else ++ { ++ /* The current hardware and the entry command buffer pipes ++ ** are different, switch to the correct pipe. */ ++ gcmkONERROR(gckHARDWARE_PipeSelect( ++ Command->kernel->hardware, ++ commandBufferLogical, ++ commandBufferObject->entryPipe, ++ &pipeBytes ++ )); ++ ++ /* Do not skip pipe switching sequence. */ ++ offset = 0; ++ } ++ ++ /* Compute the entry. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ entryPhysical = (gctUINT8_PTR) commandBufferPhysical + offset; ++#endif ++ entryLogical = commandBufferLogical + offset; ++ entryAddress = commandBufferAddress + offset; ++ entryBytes = commandBufferSize - offset; ++ } ++ } ++ } ++ ++#if gcdDUMP_COMMAND ++ bufferDumpLogical = commandBufferLogical + offset; ++ bufferDumpBytes = commandBufferSize - offset; ++#endif ++ ++ /* Determine the location to jump to for the command buffer being ++ ** scheduled. */ ++ if (Command->newQueue) ++ { ++ /* New command queue, jump to the beginning of it. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ exitPhysical = Command->physical; ++#endif ++ ++ exitLogical = Command->logical; ++ exitAddress = Command->address; ++ exitBytes = Command->offset + waitLinkBytes; ++ } ++ else ++ { ++ /* Still within the preexisting command queue, jump to the new ++ WAIT/LINK command sequence. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ exitPhysical = waitLinkPhysical; ++#endif ++ exitLogical = waitLinkLogical; ++ exitAddress = waitLinkAddress; ++ exitBytes = waitLinkBytes; ++ } ++ ++ /* Add a new WAIT/LINK command sequence. When the command buffer which is ++ currently being scheduled is fully executed by the GPU, the FE will ++ jump to this WAIT/LINK sequence. */ ++ gcmkONERROR(gckHARDWARE_WaitLink( ++ hardware, ++ waitLinkLogical, ++ offset, ++ &waitLinkBytes, ++ &waitOffset, ++ &waitSize ++ )); ++ ++ /* Compute the location if WAIT command. */ ++ waitPhysical = (gctUINT8_PTR) waitLinkPhysical + waitOffset; ++ waitLogical = (gctUINT8_PTR) waitLinkLogical + waitOffset; ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the command queue cache. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ Command->kernelProcessID, ++ gcvNULL, ++ (gctUINT32)exitPhysical, ++ exitLogical, ++ exitBytes ++ )); ++#endif ++ ++ /* Determine the location of the LINK command in the command buffer. */ ++ commandBufferLink ++ = (gctUINT8_PTR) gcmUINT64_TO_PTR(commandBufferObject->logical) ++ + commandBufferObject->offset; ++ ++ /* Generate a LINK from the end of the command buffer being scheduled ++ back to the kernel command queue. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ commandBufferLink, ++ exitAddress, ++ exitBytes, ++ &linkBytes ++ )); ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the command buffer cache. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ ProcessID, ++ gcvNULL, ++ (gctUINT32)commandBufferPhysical, ++ commandBufferLogical, ++ commandBufferSize ++ )); ++#endif ++ ++#if gcdRECORD_COMMAND ++ gckRECORDER_Record( ++ Command->recorder, ++ commandBufferLogical + offset, ++ commandBufferSize - offset - 8, ++ gcvNULL, ++ 0xFFFFFFFF ++ ); ++ ++ gckRECORDER_AdvanceIndex(Command->recorder, Command->commitStamp); ++ ++ Command->commitStamp++; ++#endif ++ ++ /* Generate a LINK from the previous WAIT/LINK command sequence to the ++ entry determined above (either the context or the command buffer). ++ This LINK replaces the WAIT instruction from the previous WAIT/LINK ++ pair, therefore we use WAIT metrics for generation of this LINK. ++ This action will execute the entire sequence. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ hardware, ++ Command->waitLogical, ++ entryAddress, ++ entryBytes, ++ &Command->waitSize ++ )); ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the cache for the link. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ Command->kernelProcessID, ++ gcvNULL, ++ (gctUINT32)Command->waitPhysical, ++ Command->waitLogical, ++ Command->waitSize ++ )); ++#endif ++ ++ gcmkDUMPCOMMAND( ++ Command->os, ++ Command->waitLogical, ++ Command->waitSize, ++ gceDUMP_BUFFER_LINK, ++ gcvFALSE ++ ); ++ ++ gcmkDUMPCOMMAND( ++ Command->os, ++ contextDumpLogical, ++ contextDumpBytes, ++ gceDUMP_BUFFER_CONTEXT, ++ gcvFALSE ++ ); ++ ++ gcmkDUMPCOMMAND( ++ Command->os, ++ bufferDumpLogical, ++ bufferDumpBytes, ++ gceDUMP_BUFFER_USER, ++ gcvFALSE ++ ); ++ ++ gcmkDUMPCOMMAND( ++ Command->os, ++ waitLinkLogical, ++ waitLinkBytes, ++ gceDUMP_BUFFER_WAITLINK, ++ gcvFALSE ++ ); ++ ++ /* Update the current pipe. */ ++ Command->pipeSelect = commandBufferObject->exitPipe; ++ ++ /* Update command queue offset. */ ++ Command->offset += waitLinkBytes; ++ Command->newQueue = gcvFALSE; ++ ++ /* Update address of last WAIT. */ ++ Command->waitPhysical = waitPhysical; ++ Command->waitLogical = waitLogical; ++ Command->waitSize = waitSize; ++ ++ /* Update queue tail pointer. */ ++ gcmkONERROR(gckHARDWARE_UpdateQueueTail( ++ hardware, Command->logical, Command->offset ++ )); ++ ++#if gcdDUMP_COMMAND ++ gcmkPRINT("@[kernel.commit]"); ++#endif ++#endif /* gcdNULL_DRIVER */ ++ ++ /* Release the context switching mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); ++ contextAcquired = gcvFALSE; ++ ++ /* Release the command queue. */ ++ gcmkONERROR(gckCOMMAND_ExitCommit(Command, gcvFALSE)); ++ commitEntered = gcvFALSE; ++ ++#if VIVANTE_PROFILER_CONTEXT ++ if(sequenceAcquired) ++ { ++ gcmkONERROR(gckCOMMAND_Stall(Command, gcvTRUE)); ++ if (Command->currContext) ++ { ++ gcmkONERROR(gckHARDWARE_UpdateContextProfile( ++ hardware, ++ Command->currContext)); ++ } ++ ++ /* Release the context switching mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContextSeq)); ++ sequenceAcquired = gcvFALSE; ++ } ++#endif ++ ++ /* Loop while there are records in the queue. */ ++ while (EventQueue != gcvNULL) ++ { ++ if (needCopy) ++ { ++ /* Point to stack record. */ ++ eventRecord = &_eventRecord; ++ ++ /* Copy the data from the client. */ ++ gcmkONERROR(gckOS_CopyFromUserData( ++ Command->os, eventRecord, EventQueue, gcmSIZEOF(gcsQUEUE) ++ )); ++ } ++ else ++ { ++ /* Map record into kernel memory. */ ++ gcmkONERROR(gckOS_MapUserPointer(Command->os, ++ EventQueue, ++ gcmSIZEOF(gcsQUEUE), ++ &pointer)); ++ ++ eventRecord = pointer; ++ } ++ ++ /* Append event record to event queue. */ ++ gcmkONERROR(gckEVENT_AddList( ++ Command->kernel->eventObj, &eventRecord->iface, gcvKERNEL_PIXEL, gcvTRUE, gcvFALSE ++ )); ++ ++ /* Next record in the queue. */ ++ nextEventRecord = gcmUINT64_TO_PTR(eventRecord->next); ++ ++ if (!needCopy) ++ { ++ /* Unmap record from kernel memory. */ ++ gcmkONERROR(gckOS_UnmapUserPointer( ++ Command->os, EventQueue, gcmSIZEOF(gcsQUEUE), (gctPOINTER *) eventRecord ++ )); ++ ++ eventRecord = gcvNULL; ++ } ++ ++ EventQueue = nextEventRecord; ++ } ++ ++ if (Command->kernel->eventObj->queueHead == gcvNULL ++ && Command->kernel->hardware->powerManagement == gcvTRUE ++ ) ++ { ++ /* Commit done event by which work thread knows all jobs done. */ ++ gcmkVERIFY_OK( ++ gckEVENT_CommitDone(Command->kernel->eventObj, gcvKERNEL_PIXEL)); ++ } ++ ++ /* Submit events. */ ++ status = gckEVENT_Submit(Command->kernel->eventObj, gcvTRUE, gcvFALSE, gcvTRUE); ++ if (status == gcvSTATUS_INTERRUPTED) ++ { ++ gcmkTRACE( ++ gcvLEVEL_INFO, ++ "%s(%d): Intterupted in gckEVENT_Submit", ++ __FUNCTION__, __LINE__ ++ ); ++ status = gcvSTATUS_OK; ++ } ++ else ++ { ++ gcmkONERROR(status); ++ } ++ ++ /* Unmap the command buffer pointer. */ ++ if (commandBufferMapped) ++ { ++ gcmkONERROR(gckOS_UnmapUserPointer( ++ Command->os, ++ CommandBuffer, ++ gcmSIZEOF(struct _gcoCMDBUF), ++ commandBufferObject ++ )); ++ ++ commandBufferMapped = gcvFALSE; ++ } ++ ++ /* Return status. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if ((eventRecord != gcvNULL) && !needCopy) ++ { ++ /* Roll back. */ ++ gcmkVERIFY_OK(gckOS_UnmapUserPointer( ++ Command->os, ++ EventQueue, ++ gcmSIZEOF(gcsQUEUE), ++ (gctPOINTER *) eventRecord ++ )); ++ } ++ ++ if (contextAcquired) ++ { ++ /* Release the context switching mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); ++ } ++ ++ if (commitEntered) ++ { ++ /* Release the command queue mutex. */ ++ gcmkVERIFY_OK(gckCOMMAND_ExitCommit(Command, gcvFALSE)); ++ } ++ ++#if VIVANTE_PROFILER_CONTEXT ++ if (sequenceAcquired) ++ { ++ /* Release the context sequence mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContextSeq)); ++ } ++#endif ++ ++ /* Unmap the command buffer pointer. */ ++ if (commandBufferMapped) ++ { ++ gcmkVERIFY_OK(gckOS_UnmapUserPointer( ++ Command->os, ++ CommandBuffer, ++ gcmSIZEOF(struct _gcoCMDBUF), ++ commandBufferObject ++ )); ++ } ++ ++ /* Return status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Reserve ++** ++** Reserve space in the command queue. Also acquire the command queue mutex. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object. ++** ++** gctSIZE_T RequestedBytes ++** Number of bytes previously reserved. ++** ++** OUTPUT: ++** ++** gctPOINTER * Buffer ++** Pointer to a variable that will receive the address of the reserved ++** space. ++** ++** gctSIZE_T * BufferSize ++** Pointer to a variable that will receive the number of bytes ++** available in the command queue. ++*/ ++gceSTATUS ++gckCOMMAND_Reserve( ++ IN gckCOMMAND Command, ++ IN gctUINT32 RequestedBytes, ++ OUT gctPOINTER * Buffer, ++ OUT gctUINT32 * BufferSize ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 bytes; ++ gctUINT32 requiredBytes; ++ gctUINT32 requestedAligned; ++ ++ gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ /* Compute aligned number of reuested bytes. */ ++ requestedAligned = gcmALIGN(RequestedBytes, Command->alignment); ++ ++ /* Another WAIT/LINK command sequence will have to be appended after ++ the requested area being reserved. Compute the number of bytes ++ required for WAIT/LINK at the location after the reserved area. */ ++ gcmkONERROR(gckHARDWARE_WaitLink( ++ Command->kernel->hardware, ++ gcvNULL, ++ Command->offset + requestedAligned, ++ &requiredBytes, ++ gcvNULL, ++ gcvNULL ++ )); ++ ++ /* Compute total number of bytes required. */ ++ requiredBytes += requestedAligned; ++ ++ /* Compute number of bytes available in command queue. */ ++ bytes = Command->pageSize - Command->offset; ++ ++ /* Is there enough space in the current command queue? */ ++ if (bytes < requiredBytes) ++ { ++ /* Create a new command queue. */ ++ gcmkONERROR(_NewQueue(Command)); ++ ++ /* Recompute the number of bytes in the new kernel command queue. */ ++ bytes = Command->pageSize - Command->offset; ++ ++ /* Still not enough space? */ ++ if (bytes < requiredBytes) ++ { ++ /* Rare case, not enough room in command queue. */ ++ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); ++ } ++ } ++ ++ /* Return pointer to empty slot command queue. */ ++ *Buffer = (gctUINT8 *) Command->logical + Command->offset; ++ ++ /* Return number of bytes left in command queue. */ ++ *BufferSize = bytes; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Buffer=0x%x *BufferSize=%lu", *Buffer, *BufferSize); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Execute ++** ++** Execute a previously reserved command queue by appending a WAIT/LINK command ++** sequence after it and modifying the last WAIT into a LINK command. The ++** command FIFO mutex will be released whether this function succeeds or not. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object. ++** ++** gctSIZE_T RequestedBytes ++** Number of bytes previously reserved. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_Execute( ++ IN gckCOMMAND Command, ++ IN gctUINT32 RequestedBytes ++ ) ++{ ++ gceSTATUS status; ++ ++ gctPHYS_ADDR waitLinkPhysical; ++ gctUINT8_PTR waitLinkLogical; ++ gctUINT32 waitLinkOffset; ++ gctUINT32 waitLinkBytes; ++ ++ gctPHYS_ADDR waitPhysical; ++ gctPOINTER waitLogical; ++ gctUINT32 waitOffset; ++ gctUINT32 waitBytes; ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ gctPHYS_ADDR execPhysical; ++#endif ++ gctPOINTER execLogical; ++ gctUINT32 execAddress; ++ gctUINT32 execBytes; ++ ++ gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ /* Compute offset for WAIT/LINK. */ ++ waitLinkOffset = Command->offset + RequestedBytes; ++ ++ /* Compute number of bytes left in command queue. */ ++ waitLinkBytes = Command->pageSize - waitLinkOffset; ++ ++ /* Compute the location if WAIT/LINK command sequence. */ ++ waitLinkPhysical = (gctUINT8_PTR) Command->physical + waitLinkOffset; ++ waitLinkLogical = (gctUINT8_PTR) Command->logical + waitLinkOffset; ++ ++ /* Append WAIT/LINK in command queue. */ ++ gcmkONERROR(gckHARDWARE_WaitLink( ++ Command->kernel->hardware, ++ waitLinkLogical, ++ waitLinkOffset, ++ &waitLinkBytes, ++ &waitOffset, ++ &waitBytes ++ )); ++ ++ /* Compute the location if WAIT command. */ ++ waitPhysical = (gctUINT8_PTR) waitLinkPhysical + waitOffset; ++ waitLogical = waitLinkLogical + waitOffset; ++ ++ /* Determine the location to jump to for the command buffer being ++ ** scheduled. */ ++ if (Command->newQueue) ++ { ++ /* New command queue, jump to the beginning of it. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ execPhysical = Command->physical; ++#endif ++ execLogical = Command->logical; ++ execAddress = Command->address; ++ execBytes = waitLinkOffset + waitLinkBytes; ++ } ++ else ++ { ++ /* Still within the preexisting command queue, jump directly to the ++ reserved area. */ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ execPhysical = (gctUINT8 *) Command->physical + Command->offset; ++#endif ++ execLogical = (gctUINT8 *) Command->logical + Command->offset; ++ execAddress = Command->address + Command->offset; ++ execBytes = RequestedBytes + waitLinkBytes; ++ } ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the cache. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ Command->kernelProcessID, ++ gcvNULL, ++ (gctUINT32)execPhysical, ++ execLogical, ++ execBytes ++ )); ++#endif ++ ++ /* Convert the last WAIT into a LINK. */ ++ gcmkONERROR(gckHARDWARE_Link( ++ Command->kernel->hardware, ++ Command->waitLogical, ++ execAddress, ++ execBytes, ++ &Command->waitSize ++ )); ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the cache. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Command->os, ++ Command->kernelProcessID, ++ gcvNULL, ++ (gctUINT32)Command->waitPhysical, ++ Command->waitLogical, ++ Command->waitSize ++ )); ++#endif ++ ++ gcmkDUMPCOMMAND( ++ Command->os, ++ Command->waitLogical, ++ Command->waitSize, ++ gceDUMP_BUFFER_LINK, ++ gcvFALSE ++ ); ++ ++ gcmkDUMPCOMMAND( ++ Command->os, ++ execLogical, ++ execBytes, ++ gceDUMP_BUFFER_KERNEL, ++ gcvFALSE ++ ); ++ ++ /* Update the pointer to the last WAIT. */ ++ Command->waitPhysical = waitPhysical; ++ Command->waitLogical = waitLogical; ++ Command->waitSize = waitBytes; ++ ++ /* Update the command queue. */ ++ Command->offset += RequestedBytes + waitLinkBytes; ++ Command->newQueue = gcvFALSE; ++ ++ /* Update queue tail pointer. */ ++ gcmkONERROR(gckHARDWARE_UpdateQueueTail( ++ Command->kernel->hardware, Command->logical, Command->offset ++ )); ++ ++#if gcdDUMP_COMMAND ++ gcmkPRINT("@[kernel.execute]"); ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Stall ++** ++** The calling thread will be suspended until the command queue has been ++** completed. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to an gckCOMMAND object. ++** ++** gctBOOL FromPower ++** Determines whether the call originates from inside the power ++** management or not. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_Stall( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromPower ++ ) ++{ ++#if gcdNULL_DRIVER ++ /* Do nothing with infinite hardware. */ ++ return gcvSTATUS_OK; ++#else ++ gckOS os; ++ gckHARDWARE hardware; ++ gckEVENT eventObject; ++ gceSTATUS status; ++ gctSIGNAL signal = gcvNULL; ++ gctUINT timer = 0; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ /* Extract the gckOS object pointer. */ ++ os = Command->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Extract the gckHARDWARE object pointer. */ ++ hardware = Command->kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ /* Extract the gckEVENT object pointer. */ ++ eventObject = Command->kernel->eventObj; ++ gcmkVERIFY_OBJECT(eventObject, gcvOBJ_EVENT); ++ ++ /* Allocate the signal. */ ++ gcmkONERROR(gckOS_CreateSignal(os, gcvTRUE, &signal)); ++ ++ /* Append the EVENT command to trigger the signal. */ ++ gcmkONERROR(gckEVENT_Signal(eventObject, signal, gcvKERNEL_PIXEL)); ++ ++ /* Submit the event queue. */ ++ gcmkONERROR(gckEVENT_Submit(eventObject, gcvTRUE, FromPower, gcvFALSE)); ++ ++#if gcdDUMP_COMMAND ++ gcmkPRINT("@[kernel.stall]"); ++#endif ++ ++ if (status == gcvSTATUS_CHIP_NOT_READY) ++ { ++ /* Error. */ ++ goto OnError; ++ } ++ ++ do ++ { ++ /* Wait for the signal. */ ++ status = gckOS_WaitSignal(os, signal, gcdGPU_ADVANCETIMER); ++ ++ if (status == gcvSTATUS_TIMEOUT) ++ { ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++ gctUINT32 idle; ++ ++ /* Read idle register. */ ++ gcmkVERIFY_OK(gckHARDWARE_GetIdle( ++ hardware, gcvFALSE, &idle ++ )); ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): idle=%08x", ++ __FUNCTION__, __LINE__, idle ++ ); ++ ++ gcmkVERIFY_OK(gckOS_MemoryBarrier(os, gcvNULL)); ++#endif ++ ++ /* Advance timer. */ ++ timer += gcdGPU_ADVANCETIMER; ++ } ++ else if (status == gcvSTATUS_INTERRUPTED) ++ { ++ gcmkONERROR(gcvSTATUS_INTERRUPTED); ++ } ++ ++ } ++ while (gcmIS_ERROR(status)); ++ ++ /* Bail out on timeout. */ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Broadcast the stuck GPU. */ ++ gcmkONERROR(gckOS_Broadcast( ++ os, hardware, gcvBROADCAST_GPU_STUCK ++ )); ++ } ++ ++ /* Delete the signal. */ ++ gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (signal != gcvNULL) ++ { ++ /* Free the signal. */ ++ gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++#endif ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Attach ++** ++** Attach user process. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to a gckCOMMAND object. ++** ++** gctUINT32 ProcessID ++** Current process ID. ++** ++** OUTPUT: ++** ++** gckCONTEXT * Context ++** Pointer to a variable that will receive a pointer to a new ++** gckCONTEXT object. ++** ++** gctSIZE_T * StateCount ++** Pointer to a variable that will receive the number of states ++** in the context buffer. ++*/ ++#if (gcdENABLE_3D || gcdENABLE_2D) ++gceSTATUS ++gckCOMMAND_Attach( ++ IN gckCOMMAND Command, ++ OUT gckCONTEXT * Context, ++ OUT gctSIZE_T * StateCount, ++ IN gctUINT32 ProcessID ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ /* Acquire the context switching mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex( ++ Command->os, Command->mutexContext, gcvINFINITE ++ )); ++ acquired = gcvTRUE; ++ ++ /* Construct a gckCONTEXT object. */ ++ gcmkONERROR(gckCONTEXT_Construct( ++ Command->os, ++ Command->kernel->hardware, ++ ProcessID, ++ Context ++ )); ++ ++ /* Return the number of states in the context. */ ++ * StateCount = (* Context)->stateCount; ++ ++ /* Release the context switching mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); ++ acquired = gcvFALSE; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Context=0x%x", *Context); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Release mutex. */ ++ if (acquired) ++ { ++ /* Release the context switching mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); ++ acquired = gcvFALSE; ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckCOMMAND_Detach ++** ++** Detach user process. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to a gckCOMMAND object. ++** ++** gckCONTEXT Context ++** Pointer to a gckCONTEXT object to be destroyed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_Detach( ++ IN gckCOMMAND Command, ++ IN gckCONTEXT Context ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Command=0x%x Context=0x%x", Command, Context); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ /* Acquire the context switching mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex( ++ Command->os, Command->mutexContext, gcvINFINITE ++ )); ++ acquired = gcvTRUE; ++ ++ /* Construct a gckCONTEXT object. */ ++ gcmkONERROR(gckCONTEXT_Destroy(Context)); ++ ++ if (Command->currContext == Context) ++ { ++ /* Detach from gckCOMMAND object if the destoryed context is current context. */ ++ Command->currContext = gcvNULL; ++ } ++ ++ /* Release the context switching mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); ++ acquired = gcvFALSE; ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Release mutex. */ ++ if (acquired) ++ { ++ /* Release the context switching mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); ++ acquired = gcvFALSE; ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckCOMMAND_DumpExecutingBuffer ++** ++** Dump the command buffer which GPU is executing. ++** ++** INPUT: ++** ++** gckCOMMAND Command ++** Pointer to a gckCOMMAND object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckCOMMAND_DumpExecutingBuffer( ++ IN gckCOMMAND Command ++ ) ++{ ++ gceSTATUS status; ++ gckVIRTUAL_COMMAND_BUFFER_PTR buffer; ++ gctUINT32 gpuAddress; ++ gctSIZE_T pageCount; ++ gctPOINTER entry; ++ gckOS os = Command->os; ++ gckKERNEL kernel = Command->kernel; ++ gctINT pid; ++ gctUINT32 i, rear; ++ gctUINT32 start, end; ++ gctUINT32 dumpFront, dumpRear; ++ gckLINKQUEUE queue = &kernel->hardware->linkQueue; ++ gckLINKQUEUE queueMirror; ++ gctUINT32 bytes; ++ gckLINKDATA linkData; ++ ++ gcmkPRINT("**************************\n"); ++ gcmkPRINT("**** COMMAND BUF DUMP ****\n"); ++ gcmkPRINT("**************************\n"); ++ ++ gcmkVERIFY_OK(gckOS_ReadRegisterEx(os, kernel->core, 0x664, &gpuAddress)); ++ ++ gcmkPRINT("DMA Address 0x%08X", gpuAddress); ++ ++ if (Command->kernel->stuckDump > gcdSTUCK_DUMP_MIDDLE) ++ { ++ gcmkPRINT("Dump Level is %d", Command->kernel->stuckDump); ++ ++ /* Duplicate queue because it will be changed.*/ ++ gcmkONERROR(gckOS_AllocateMemory(os, ++ sizeof(struct _gckLINKQUEUE), ++ (gctPOINTER *)&queueMirror)); ++ ++ gckOS_MemCopy(queueMirror, ++ queue, ++ sizeof(struct _gckLINKQUEUE)); ++ ++ /* If kernel command buffer link to a context buffer, then link to a user command ++ ** buffer, the second link will be in queue first, so we must fix this. ++ ** In Queue: C1 U1 U2 C2 U3 U4 U5 C3 ++ ** Real: C1 X1 U1 C2 U2 U3 U4 C3 U5 ++ ** Command buffer X1 which is after C1 is out of queue, so C1 is meaningless. ++ */ ++ for (i = 0; i < gcdLINK_QUEUE_SIZE; i++) ++ { ++ gckLINKQUEUE_GetData(queueMirror, i, &linkData); ++ ++ status = gckKERNEL_QueryGPUAddress(kernel, linkData->start, &buffer); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Can't find it in virtual command buffer list, ignore it. */ ++ continue; ++ } ++ ++ if (buffer->kernelLogical) ++ { ++ /* It is a context buffer. */ ++ if (i == 0) ++ { ++ /* The real command buffer is out, so clear this slot. */ ++ linkData->start = 0; ++ linkData->end = 0; ++ linkData->pid = 0; ++ } ++ else ++ { ++ /* switch context buffer and command buffer. */ ++ struct _gckLINKDATA tmp = *linkData; ++ gckLINKDATA linkDataPrevious; ++ ++ gckLINKQUEUE_GetData(queueMirror, i - 1, &linkDataPrevious); ++ *linkData = *linkDataPrevious; ++ *linkDataPrevious = tmp; ++ } ++ } ++ } ++ ++ /* Clear search result. */ ++ dumpFront = dumpRear = gcvINFINITE; ++ ++ gcmkPRINT("Link Stack:"); ++ ++ /* Search stuck address in link queue from rear. */ ++ rear = gcdLINK_QUEUE_SIZE - 1; ++ for (i = 0; i < gcdLINK_QUEUE_SIZE; i++) ++ { ++ gckLINKQUEUE_GetData(queueMirror, rear, &linkData); ++ ++ start = linkData->start; ++ end = linkData->end; ++ pid = linkData->pid; ++ ++ if (gpuAddress >= start && gpuAddress < end) ++ { ++ /* Find latest matched command buffer. */ ++ gcmkPRINT(" %d, [%08X - %08X]", pid, start, end); ++ ++ /* Initiliaze dump information. */ ++ dumpFront = dumpRear = rear; ++ } ++ ++ /* Advance to previous one. */ ++ rear--; ++ ++ if (dumpFront != gcvINFINITE) ++ { ++ break; ++ } ++ } ++ ++ if (dumpFront == gcvINFINITE) ++ { ++ /* Can't find matched record in link queue, dump kernel command buffer. */ ++ _DumpKernelCommandBuffer(Command); ++ ++ /* Free local copy. */ ++ gcmkOS_SAFE_FREE(os, queueMirror); ++ return gcvSTATUS_OK; ++ } ++ ++ /* Search the last context buffer linked. */ ++ while (rear > 0) ++ { ++ gckLINKQUEUE_GetData(queueMirror, rear, &linkData); ++ ++ gcmkPRINT(" %d, [%08X - %08X]", ++ linkData->pid, ++ linkData->start, ++ linkData->end); ++ ++ status = gckKERNEL_QueryGPUAddress(kernel, linkData->start, &buffer); ++ ++ if (gcmIS_SUCCESS(status) && buffer->kernelLogical) ++ { ++ /* Find a context buffer. */ ++ dumpFront = rear; ++ break; ++ } ++ ++ rear--; ++ } ++ ++ if (dumpFront == dumpRear) ++ { ++ /* No context buffer is found, dump all we got.*/ ++ dumpFront = 0; ++ } ++ ++ /* Dump from last context buffer to last command buffer where hang happens. */ ++ for (i = dumpFront; i <= dumpRear; i++) ++ { ++ gckLINKQUEUE_GetData(queueMirror, i, &linkData); ++ ++ /* Get gpu address of this command buffer. */ ++ gpuAddress = linkData->start; ++ bytes = linkData->end - gpuAddress; ++ ++ /* Get the whole buffer. */ ++ status = gckKERNEL_QueryGPUAddress(kernel, gpuAddress, &buffer); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ gcmkPRINT("Buffer [%08X - %08X] is lost or not belong to current process", ++ linkData->start, ++ linkData->end); ++ continue; ++ } ++ ++ /* Get kernel logical for dump. */ ++ if (buffer->kernelLogical) ++ { ++ /* Get kernel logical directly if it is a context buffer. */ ++ entry = buffer->kernelLogical; ++ gcmkPRINT("Context Buffer:"); ++ } ++ else ++ { ++ /* Make it accessiable by kernel if it is a user command buffer. */ ++ gcmkVERIFY_OK( ++ gckOS_CreateKernelVirtualMapping(os, ++ buffer->physical, ++ buffer->bytes, ++ &entry, ++ &pageCount)); ++ gcmkPRINT("User Command Buffer:"); ++ } ++ ++ /* Dump from the entry. */ ++ _DumpBuffer((gctUINT8_PTR)entry + (gpuAddress - buffer->gpuAddress), gpuAddress, bytes); ++ ++ /* Release kernel logical address if neccessary. */ ++ if (!buffer->kernelLogical) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DestroyKernelVirtualMapping(os, ++ buffer->physical, ++ buffer->bytes, ++ entry)); ++ } ++ } ++ ++ /* Free local copy. */ ++ gcmkOS_SAFE_FREE(os, queueMirror); ++ return gcvSTATUS_OK; ++ OnError: ++ return status; ++ } ++ else ++ { ++ gcmkPRINT("Dump Level is %d, dump memory near the stuck address", ++ Command->kernel->stuckDump); ++ ++ /* Without link queue information, we don't know the entry of last command ++ ** buffer, just dump the page where GPU stuck. */ ++ status = gckKERNEL_QueryGPUAddress(kernel, gpuAddress, &buffer); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ gcmkVERIFY_OK( ++ gckOS_CreateKernelVirtualMapping(os, ++ buffer->physical, ++ buffer->bytes, ++ &entry, ++ &pageCount)); ++ ++ if (entry) ++ { ++ gctUINT32 offset = gpuAddress - buffer->gpuAddress; ++ gctPOINTER entryDump = entry; ++ ++ /* Dump one pages. */ ++ gctUINT32 bytes = 4096; ++ ++ /* Align to page. */ ++ offset &= 0xfffff000; ++ ++ /* Kernel address of page where stall point stay. */ ++ entryDump = (gctUINT8_PTR)entryDump + offset; ++ ++ /* Align to page. */ ++ gpuAddress &= 0xfffff000; ++ ++ gcmkPRINT("User Command Buffer:\n"); ++ _DumpBuffer(entryDump, gpuAddress, bytes); ++ } ++ ++ gcmkVERIFY_OK( ++ gckOS_DestroyKernelVirtualMapping(os, ++ buffer->physical, ++ buffer->bytes, ++ entry)); ++ } ++ else ++ { ++ _DumpKernelCommandBuffer(Command); ++ } ++ ++ return gcvSTATUS_OK; ++ } ++} ++ ++gceSTATUS ++gckCOMMAND_AddressInKernelCommandBuffer( ++ IN gckCOMMAND Command, ++ IN gctUINT32 Address, ++ OUT gctBOOL *In ++ ) ++{ ++ gctBOOL in = gcvFALSE; ++ gctINT i; ++ ++ for (i = 0; i < gcdCOMMAND_QUEUES; i++) ++ { ++ if ((Address >= Command->queues[i].address) ++ && (Address < (Command->queues[i].address + Command->pageSize)) ++ ) ++ { ++ in = gcvTRUE; ++ break; ++ } ++ } ++ ++ *In = in; ++ return gcvSTATUS_OK; ++} +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_command_vg.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_command_vg.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_command_vg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_command_vg.c 2016-06-19 22:11:55.137151030 +0200 +@@ -0,0 +1,3678 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#if gcdENABLE_VG ++ ++#include "gc_hal_kernel_hardware_command_vg.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_COMMAND ++ ++/******************************************************************************\ ++*********************************** Debugging ********************************** ++\******************************************************************************/ ++ ++#define gcvDISABLE_TIMEOUT 1 ++#define gcvDUMP_COMMAND_BUFFER 0 ++#define gcvDUMP_COMMAND_LINES 0 ++ ++ ++#if gcvDEBUG || defined(EMULATOR) || gcvDISABLE_TIMEOUT ++# define gcvQUEUE_TIMEOUT ~0 ++#else ++# define gcvQUEUE_TIMEOUT 10 ++#endif ++ ++ ++/******************************************************************************\ ++********************************** Definitions ********************************* ++\******************************************************************************/ ++ ++/* Minimum buffer size. */ ++#define gcvMINUMUM_BUFFER \ ++ gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + \ ++ gcmSIZEOF(gcsKERNEL_CMDQUEUE) * 2 ++ ++#define gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \ ++ static gceSTATUS \ ++ _EventHandler_##Block##_##Number( \ ++ IN gckVGKERNEL Kernel \ ++ ) ++ ++#define gcmDEFINE_INTERRUPT_HANDLER(Block, Number) \ ++ gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \ ++ { \ ++ return _EventHandler_Block( \ ++ Kernel, \ ++ &Kernel->command->taskTable[gcvBLOCK_##Block], \ ++ gcvFALSE \ ++ ); \ ++ } ++ ++#define gcmDEFINE_INTERRUPT_HANDLER_ENTRY(Block, Number) \ ++ { gcvBLOCK_##Block, _EventHandler_##Block##_##Number } ++ ++/* Block interrupt handling table entry. */ ++typedef struct _gcsBLOCK_INTERRUPT_HANDLER * gcsBLOCK_INTERRUPT_HANDLER_PTR; ++typedef struct _gcsBLOCK_INTERRUPT_HANDLER ++{ ++ gceBLOCK block; ++ gctINTERRUPT_HANDLER handler; ++} ++gcsBLOCK_INTERRUPT_HANDLER; ++ ++/* Queue control functions. */ ++typedef struct _gcsQUEUE_UPDATE_CONTROL * gcsQUEUE_UPDATE_CONTROL_PTR; ++typedef struct _gcsQUEUE_UPDATE_CONTROL ++{ ++ gctOBJECT_HANDLER execute; ++ gctOBJECT_HANDLER update; ++ gctOBJECT_HANDLER lastExecute; ++ gctOBJECT_HANDLER lastUpdate; ++} ++gcsQUEUE_UPDATE_CONTROL; ++ ++ ++/******************************************************************************\ ++********************************* Support Code ********************************* ++\******************************************************************************/ ++static gceSTATUS ++_FlushMMU( ++ IN gckVGCOMMAND Command ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 oldValue; ++ gckVGHARDWARE hardware = Command->hardware; ++ ++ gcmkONERROR(gckOS_AtomicExchange(Command->os, ++ hardware->pageTableDirty, ++ 0, ++ &oldValue)); ++ ++ if (oldValue) ++ { ++ /* Page Table is upated, flush mmu before commit. */ ++ gcmkONERROR(gckVGHARDWARE_FlushMMU(hardware)); ++ } ++ ++ return gcvSTATUS_OK; ++OnError: ++ return status; ++} ++ ++static gceSTATUS ++_WaitForIdle( ++ IN gckVGCOMMAND Command, ++ IN gcsKERNEL_QUEUE_HEADER_PTR Queue ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gctUINT32 idle; ++ gctUINT timeout = 0; ++ ++ /* Loop while not idle. */ ++ while (Queue->pending) ++ { ++ /* Did we reach the timeout limit? */ ++ if (timeout == gcvQUEUE_TIMEOUT) ++ { ++ /* Hardware is probably dead... */ ++ return gcvSTATUS_TIMEOUT; ++ } ++ ++ /* Sleep for 100ms. */ ++ gcmkERR_BREAK(gckOS_Delay(Command->os, 100)); ++ ++ /* Not the first loop? */ ++ if (timeout > 0) ++ { ++ /* Read IDLE register. */ ++ gcmkVERIFY_OK(gckVGHARDWARE_GetIdle(Command->hardware, &idle)); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_COMMAND, ++ "%s: timeout, IDLE=%08X\n", ++ __FUNCTION__, idle ++ ); ++ } ++ ++ /* Increment the timeout counter. */ ++ timeout += 1; ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gctINT32 ++_GetNextInterrupt( ++ IN gckVGCOMMAND Command, ++ IN gceBLOCK Block ++ ) ++{ ++ gctUINT index; ++ gcsBLOCK_TASK_ENTRY_PTR entry; ++ gctINT32 interrupt; ++ ++ /* Get the block entry. */ ++ entry = &Command->taskTable[Block]; ++ ++ /* Make sure we have initialized interrupts. */ ++ gcmkASSERT(entry->interruptCount > 0); ++ ++ /* Decrement the interrupt usage semaphore. */ ++ gcmkVERIFY_OK(gckOS_DecrementSemaphore( ++ Command->os, entry->interruptSemaphore ++ )); ++ ++ /* Get the value index. */ ++ index = entry->interruptIndex; ++ ++ /* Get the interrupt value. */ ++ interrupt = entry->interruptArray[index]; ++ ++ /* Must be a valid value. */ ++ gcmkASSERT((interrupt >= 0) && (interrupt <= 31)); ++ ++ /* Advance the index to the next value. */ ++ index += 1; ++ ++ /* Set the new index. */ ++ entry->interruptIndex = (index == entry->interruptCount) ++ ? 0 ++ : index; ++ ++ /* Return interrupt value. */ ++ return interrupt; ++} ++ ++ ++/******************************************************************************\ ++***************************** Task Storage Management ************************** ++\******************************************************************************/ ++ ++/* Minimum task buffer size. */ ++#define gcvMIN_TASK_BUFFER \ ++( \ ++ gcmSIZEOF(gcsTASK_CONTAINER) + 128 \ ++) ++ ++/* Free list terminator. */ ++#define gcvFREE_TASK_TERMINATOR \ ++( \ ++ (gcsTASK_CONTAINER_PTR) gcmINT2PTR(~0) \ ++) ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*------------------- Allocated Task Buffer List Management ------------------*/ ++ ++static void ++_InsertTaskBuffer( ++ IN gcsTASK_CONTAINER_PTR AddAfter, ++ IN gcsTASK_CONTAINER_PTR Buffer ++ ) ++{ ++ gcsTASK_CONTAINER_PTR addBefore; ++ ++ /* Cannot add before the first buffer. */ ++ gcmkASSERT(AddAfter != gcvNULL); ++ ++ /* Create a shortcut to the next buffer. */ ++ addBefore = AddAfter->allocNext; ++ ++ /* Initialize the links. */ ++ Buffer->allocPrev = AddAfter; ++ Buffer->allocNext = addBefore; ++ ++ /* Link to the previous buffer. */ ++ AddAfter->allocNext = Buffer; ++ ++ /* Link to the next buffer. */ ++ if (addBefore != gcvNULL) ++ { ++ addBefore->allocPrev = Buffer; ++ } ++} ++ ++static void ++_RemoveTaskBuffer( ++ IN gcsTASK_CONTAINER_PTR Buffer ++ ) ++{ ++ gcsTASK_CONTAINER_PTR prev; ++ gcsTASK_CONTAINER_PTR next; ++ ++ /* Cannot remove the first buffer. */ ++ gcmkASSERT(Buffer->allocPrev != gcvNULL); ++ ++ /* Create shortcuts to the previous and next buffers. */ ++ prev = Buffer->allocPrev; ++ next = Buffer->allocNext; ++ ++ /* Tail buffer? */ ++ if (next == gcvNULL) ++ { ++ /* Remove from the list. */ ++ prev->allocNext = gcvNULL; ++ } ++ ++ /* Buffer from the middle. */ ++ else ++ { ++ prev->allocNext = next; ++ next->allocPrev = prev; ++ } ++} ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*--------------------- Free Task Buffer List Management ---------------------*/ ++ ++static void ++_AppendToFreeList( ++ IN gckVGCOMMAND Command, ++ IN gcsTASK_CONTAINER_PTR Buffer ++ ) ++{ ++ /* Cannot be a part of the free list already. */ ++ gcmkASSERT(Buffer->freePrev == gcvNULL); ++ gcmkASSERT(Buffer->freeNext == gcvNULL); ++ ++ /* First buffer to add? */ ++ if (Command->taskFreeHead == gcvNULL) ++ { ++ /* Terminate the links. */ ++ Buffer->freePrev = gcvFREE_TASK_TERMINATOR; ++ Buffer->freeNext = gcvFREE_TASK_TERMINATOR; ++ ++ /* Initialize the list pointer. */ ++ Command->taskFreeHead = Command->taskFreeTail = Buffer; ++ } ++ ++ /* Not the first, add after the tail. */ ++ else ++ { ++ /* Initialize the new tail buffer. */ ++ Buffer->freePrev = Command->taskFreeTail; ++ Buffer->freeNext = gcvFREE_TASK_TERMINATOR; ++ ++ /* Add after the tail. */ ++ Command->taskFreeTail->freeNext = Buffer; ++ Command->taskFreeTail = Buffer; ++ } ++} ++ ++static void ++_RemoveFromFreeList( ++ IN gckVGCOMMAND Command, ++ IN gcsTASK_CONTAINER_PTR Buffer ++ ) ++{ ++ /* Has to be a part of the free list. */ ++ gcmkASSERT(Buffer->freePrev != gcvNULL); ++ gcmkASSERT(Buffer->freeNext != gcvNULL); ++ ++ /* Head buffer? */ ++ if (Buffer->freePrev == gcvFREE_TASK_TERMINATOR) ++ { ++ /* Tail buffer as well? */ ++ if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR) ++ { ++ /* Reset the list pointer. */ ++ Command->taskFreeHead = Command->taskFreeTail = gcvNULL; ++ } ++ ++ /* No, just the head. */ ++ else ++ { ++ /* Update the head. */ ++ Command->taskFreeHead = Buffer->freeNext; ++ ++ /* Terminate the next buffer. */ ++ Command->taskFreeHead->freePrev = gcvFREE_TASK_TERMINATOR; ++ } ++ } ++ ++ /* Not the head. */ ++ else ++ { ++ /* Tail buffer? */ ++ if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR) ++ { ++ /* Update the tail. */ ++ Command->taskFreeTail = Buffer->freePrev; ++ ++ /* Terminate the previous buffer. */ ++ Command->taskFreeTail->freeNext = gcvFREE_TASK_TERMINATOR; ++ } ++ ++ /* A buffer in the middle. */ ++ else ++ { ++ /* Remove the buffer from the list. */ ++ Buffer->freePrev->freeNext = Buffer->freeNext; ++ Buffer->freeNext->freePrev = Buffer->freePrev; ++ } ++ } ++ ++ /* Reset free list pointers. */ ++ Buffer->freePrev = gcvNULL; ++ Buffer->freeNext = gcvNULL; ++} ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*-------------------------- Task Buffer Allocation --------------------------*/ ++ ++static void ++_SplitTaskBuffer( ++ IN gckVGCOMMAND Command, ++ IN gcsTASK_CONTAINER_PTR Buffer, ++ IN gctUINT Size ++ ) ++{ ++ /* Determine the size of the new buffer. */ ++ gctINT splitBufferSize = Buffer->size - Size; ++ gcmkASSERT(splitBufferSize >= 0); ++ ++ /* Is the split buffer big enough to become a separate buffer? */ ++ if (splitBufferSize >= gcvMIN_TASK_BUFFER) ++ { ++ /* Place the new path data. */ ++ gcsTASK_CONTAINER_PTR splitBuffer = (gcsTASK_CONTAINER_PTR) ++ ( ++ (gctUINT8_PTR) Buffer + Size ++ ); ++ ++ /* Set the trimmed buffer size. */ ++ Buffer->size = Size; ++ ++ /* Initialize the split buffer. */ ++ splitBuffer->referenceCount = 0; ++ splitBuffer->size = splitBufferSize; ++ splitBuffer->freePrev = gcvNULL; ++ splitBuffer->freeNext = gcvNULL; ++ ++ /* Link in. */ ++ _InsertTaskBuffer(Buffer, splitBuffer); ++ _AppendToFreeList(Command, splitBuffer); ++ } ++} ++ ++static gceSTATUS ++_AllocateTaskContainer( ++ IN gckVGCOMMAND Command, ++ IN gctUINT Size, ++ OUT gcsTASK_CONTAINER_PTR * Buffer ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Command=0x%x Size=0x%x, Buffer ==0x%x", Command, Size, Buffer); ++ ++ /* Verify arguments. */ ++ gcmkVERIFY_ARGUMENT(Buffer != gcvNULL); ++ ++ do ++ { ++ gcsTASK_STORAGE_PTR storage; ++ gcsTASK_CONTAINER_PTR buffer; ++ ++ /* Adjust the size. */ ++ Size += gcmSIZEOF(gcsTASK_CONTAINER); ++ ++ /* Adjust the allocation size if not big enough. */ ++ if (Size > Command->taskStorageUsable) ++ { ++ Command->taskStorageGranularity ++ = gcmALIGN(Size + gcmSIZEOF(gcsTASK_STORAGE), 1024); ++ ++ Command->taskStorageUsable ++ = Command->taskStorageGranularity - gcmSIZEOF(gcsTASK_STORAGE); ++ } ++ ++ /* Is there a free buffer available? */ ++ else if (Command->taskFreeHead != gcvNULL) ++ { ++ /* Set the initial free buffer. */ ++ gcsTASK_CONTAINER_PTR buffer = Command->taskFreeHead; ++ ++ do ++ { ++ /* Is the buffer big enough? */ ++ if (buffer->size >= Size) ++ { ++ /* Remove the buffer from the free list. */ ++ _RemoveFromFreeList(Command, buffer); ++ ++ /* Split the buffer. */ ++ _SplitTaskBuffer(Command, buffer, Size); ++ ++ /* Set the result. */ ++ * Buffer = buffer; ++ ++ gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer); ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ ++ /* Get the next free buffer. */ ++ buffer = buffer->freeNext; ++ } ++ while (buffer != gcvFREE_TASK_TERMINATOR); ++ } ++ ++ /* Allocate a container. */ ++ gcmkERR_BREAK(gckOS_Allocate( ++ Command->os, ++ Command->taskStorageGranularity, ++ (gctPOINTER *) &storage ++ )); ++ ++ /* Link in the storage buffer. */ ++ storage->next = Command->taskStorage; ++ Command->taskStorage = storage; ++ ++ /* Place the task buffer. */ ++ buffer = (gcsTASK_CONTAINER_PTR) (storage + 1); ++ ++ /* Determine the size of the buffer. */ ++ buffer->size ++ = Command->taskStorageGranularity ++ - gcmSIZEOF(gcsTASK_STORAGE); ++ ++ /* Initialize the task buffer. */ ++ buffer->referenceCount = 0; ++ buffer->allocPrev = gcvNULL; ++ buffer->allocNext = gcvNULL; ++ buffer->freePrev = gcvNULL; ++ buffer->freeNext = gcvNULL; ++ ++ /* Split the buffer. */ ++ _SplitTaskBuffer(Command, buffer, Size); ++ ++ /* Set the result. */ ++ * Buffer = buffer; ++ ++ gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer); ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++static void ++_FreeTaskContainer( ++ IN gckVGCOMMAND Command, ++ IN gcsTASK_CONTAINER_PTR Buffer ++ ) ++{ ++ gcsTASK_CONTAINER_PTR prev; ++ gcsTASK_CONTAINER_PTR next; ++ gcsTASK_CONTAINER_PTR merged; ++ ++ gctUINT32 mergedSize; ++ ++ /* Verify arguments. */ ++ gcmkASSERT(Buffer != gcvNULL); ++ gcmkASSERT(Buffer->freePrev == gcvNULL); ++ gcmkASSERT(Buffer->freeNext == gcvNULL); ++ ++ /* Get shortcuts to the previous and next path data buffers. */ ++ prev = Buffer->allocPrev; ++ next = Buffer->allocNext; ++ ++ /* Is the previous path data buffer already free? */ ++ if (prev && prev->freeNext) ++ { ++ /* The previous path data buffer is the one that remains. */ ++ merged = prev; ++ ++ /* Is the next path data buffer already free? */ ++ if (next && next->freeNext) ++ { ++ /* Merge all three path data buffers into the previous. */ ++ mergedSize = prev->size + Buffer->size + next->size; ++ ++ /* Remove the next path data buffer. */ ++ _RemoveFromFreeList(Command, next); ++ _RemoveTaskBuffer(next); ++ } ++ else ++ { ++ /* Merge the current path data buffer into the previous. */ ++ mergedSize = prev->size + Buffer->size; ++ } ++ ++ /* Delete the current path data buffer. */ ++ _RemoveTaskBuffer(Buffer); ++ ++ /* Set new size. */ ++ merged->size = mergedSize; ++ } ++ else ++ { ++ /* The current path data buffer is the one that remains. */ ++ merged = Buffer; ++ ++ /* Is the next buffer already free? */ ++ if (next && next->freeNext) ++ { ++ /* Merge the next into the current. */ ++ mergedSize = Buffer->size + next->size; ++ ++ /* Remove the next buffer. */ ++ _RemoveFromFreeList(Command, next); ++ _RemoveTaskBuffer(next); ++ ++ /* Set new size. */ ++ merged->size = mergedSize; ++ } ++ ++ /* Add the current buffer into the free list. */ ++ _AppendToFreeList(Command, merged); ++ } ++} ++ ++gceSTATUS ++_RemoveRecordFromProcesDB( ++ IN gckVGCOMMAND Command, ++ IN gcsTASK_HEADER_PTR Task ++ ) ++{ ++ gceSTATUS status; ++ gcsTASK_PTR task = (gcsTASK_PTR)((gctUINT8_PTR)Task - sizeof(gcsTASK)); ++ gcsTASK_FREE_VIDEO_MEMORY_PTR freeVideoMemory; ++ gcsTASK_UNLOCK_VIDEO_MEMORY_PTR unlockVideoMemory; ++ gctINT pid; ++ gctUINT32 size; ++ gctUINT32 handle; ++ gckKERNEL kernel = Command->kernel->kernel; ++ gckVIDMEM_NODE unlockNode = gcvNULL; ++ gckVIDMEM_NODE nodeObject = gcvNULL; ++ gceDATABASE_TYPE type; ++ ++ /* Get the total size of all tasks. */ ++ size = task->size; ++ ++ gcmkVERIFY_OK(gckOS_GetProcessID((gctUINT32_PTR)&pid)); ++ ++ do ++ { ++ switch (Task->id) ++ { ++ case gcvTASK_FREE_VIDEO_MEMORY: ++ freeVideoMemory = (gcsTASK_FREE_VIDEO_MEMORY_PTR)Task; ++ ++ handle = (gctUINT32)freeVideoMemory->node; ++ ++ status = gckVIDMEM_HANDLE_Lookup( ++ Command->kernel->kernel, ++ pid, ++ handle, ++ &nodeObject); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ return status; ++ } ++ ++ gckVIDMEM_HANDLE_Dereference(kernel, pid, handle); ++ freeVideoMemory->node = gcmALL_TO_UINT32(nodeObject); ++ ++ type = gcvDB_VIDEO_MEMORY ++ | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT) ++ | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT); ++ ++ /* Remove record from process db. */ ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Command->kernel->kernel, ++ pid, ++ type, ++ gcmINT2PTR(handle))); ++ ++ /* Advance to next task. */ ++ size -= sizeof(gcsTASK_FREE_VIDEO_MEMORY); ++ Task = (gcsTASK_HEADER_PTR)(freeVideoMemory + 1); ++ ++ break; ++ case gcvTASK_UNLOCK_VIDEO_MEMORY: ++ unlockVideoMemory = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR)Task; ++ ++ /* Remove record from process db. */ ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Command->kernel->kernel, ++ pid, ++ gcvDB_VIDEO_MEMORY_LOCKED, ++ gcmUINT64_TO_PTR(unlockVideoMemory->node))); ++ ++ handle = (gctUINT32)unlockVideoMemory->node; ++ ++ status = gckVIDMEM_HANDLE_Lookup( ++ Command->kernel->kernel, ++ pid, ++ handle, ++ &unlockNode); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ return status; ++ } ++ ++ gckVIDMEM_HANDLE_Dereference(kernel, pid, handle); ++ unlockVideoMemory->node = gcmPTR_TO_UINT64(unlockNode); ++ ++ /* Advance to next task. */ ++ size -= sizeof(gcsTASK_UNLOCK_VIDEO_MEMORY); ++ Task = (gcsTASK_HEADER_PTR)(unlockVideoMemory + 1); ++ ++ break; ++ default: ++ /* Skip the whole task. */ ++ size = 0; ++ break; ++ } ++ } ++ while(size); ++ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************\ ++********************************* Task Scheduling ****************************** ++\******************************************************************************/ ++ ++static gceSTATUS ++_ScheduleTasks( ++ IN gckVGCOMMAND Command, ++ IN gcsTASK_MASTER_TABLE_PTR TaskTable, ++ IN gctUINT8_PTR PreviousEnd ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ gctINT block; ++ gcsTASK_CONTAINER_PTR container; ++ gcsTASK_MASTER_ENTRY_PTR userTaskEntry; ++ gcsBLOCK_TASK_ENTRY_PTR kernelTaskEntry; ++ gcsTASK_PTR userTask; ++ gctUINT8_PTR kernelTask; ++ gctINT32 interrupt; ++ gctUINT8_PTR eventCommand; ++ ++ /* Nothing to schedule? */ ++ if (TaskTable->size == 0) ++ { ++ status = gcvSTATUS_OK; ++ break; ++ } ++ ++ /* Acquire the mutex. */ ++ gcmkERR_BREAK(gckOS_AcquireMutex( ++ Command->os, ++ Command->taskMutex, ++ gcvINFINITE ++ )); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d)\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ do ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " number of tasks scheduled = %d\n" ++ " size of event data in bytes = %d\n", ++ TaskTable->count, ++ TaskTable->size ++ ); ++ ++ /* Allocate task buffer. */ ++ gcmkERR_BREAK(_AllocateTaskContainer( ++ Command, ++ TaskTable->size, ++ &container ++ )); ++ ++ /* Determine the task data pointer. */ ++ kernelTask = (gctUINT8_PTR) (container + 1); ++ ++ /* Initialize the reference count. */ ++ container->referenceCount = TaskTable->count; ++ ++ /* Process tasks. */ ++ for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1) ++ { ++ /* Get the current user table entry. */ ++ userTaskEntry = &TaskTable->table[block]; ++ ++ /* Are there tasks scheduled? */ ++ if (userTaskEntry->head == gcvNULL) ++ { ++ /* No, skip to the next block. */ ++ continue; ++ } ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " processing tasks for block %d\n", ++ block ++ ); ++ ++ /* Get the current kernel table entry. */ ++ kernelTaskEntry = &Command->taskTable[block]; ++ ++ /* Are there tasks for the current block scheduled? */ ++ if (kernelTaskEntry->container == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " first task container for the block added\n", ++ block ++ ); ++ ++ /* Nothing yet, set the container buffer pointer. */ ++ kernelTaskEntry->container = container; ++ kernelTaskEntry->task = (gcsTASK_HEADER_PTR) kernelTask; ++ } ++ ++ /* Yes, append to the end. */ ++ else ++ { ++ kernelTaskEntry->link->cotainer = container; ++ kernelTaskEntry->link->task = (gcsTASK_HEADER_PTR) kernelTask; ++ } ++ ++ /* Set initial task. */ ++ userTask = userTaskEntry->head; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " copying user tasks over to the kernel\n" ++ ); ++ ++ /* Copy tasks. */ ++ do ++ { ++ gcsTASK_HEADER_PTR taskHeader; ++ ++ taskHeader = (gcsTASK_HEADER_PTR) (userTask + 1); ++ ++ gcmkVERIFY_OK(_RemoveRecordFromProcesDB(Command, taskHeader)); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " task ID = %d, size = %d\n", ++ ((gcsTASK_HEADER_PTR) (userTask + 1))->id, ++ userTask->size ++ ); ++ ++ /* Copy the task data. */ ++ gcmkVERIFY_OK(gckOS_MemCopy( ++ kernelTask, taskHeader, userTask->size ++ )); ++ ++ /* Advance to the next task. */ ++ kernelTask += userTask->size; ++ userTask = userTask->next; ++ } ++ while (userTask != gcvNULL); ++ ++ /* Update link pointer in the header. */ ++ kernelTaskEntry->link = (gcsTASK_LINK_PTR) kernelTask; ++ ++ /* Initialize link task. */ ++ kernelTaskEntry->link->id = gcvTASK_LINK; ++ kernelTaskEntry->link->cotainer = gcvNULL; ++ kernelTaskEntry->link->task = gcvNULL; ++ ++ /* Advance the task data pointer. */ ++ kernelTask += gcmSIZEOF(gcsTASK_LINK); ++ } ++ } ++ while (gcvFALSE); ++ ++ /* Release the mutex. */ ++ gcmkERR_BREAK(gckOS_ReleaseMutex( ++ Command->os, ++ Command->taskMutex ++ )); ++ ++ /* Assign interrupts to the blocks. */ ++ eventCommand = PreviousEnd; ++ ++ for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1) ++ { ++ /* Get the current user table entry. */ ++ userTaskEntry = &TaskTable->table[block]; ++ ++ /* Are there tasks scheduled? */ ++ if (userTaskEntry->head == gcvNULL) ++ { ++ /* No, skip to the next block. */ ++ continue; ++ } ++ ++ /* Get the interrupt number. */ ++ interrupt = _GetNextInterrupt(Command, block); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d): block = %d interrupt = %d\n", ++ __FUNCTION__, __LINE__, ++ block, interrupt ++ ); ++ ++ /* Determine the command position. */ ++ eventCommand -= Command->info.eventCommandSize; ++ ++ /* Append an EVENT command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_EventCommand( ++ Command, eventCommand, block, interrupt, gcvNULL ++ )); ++ } ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++ ++/******************************************************************************\ ++******************************** Memory Management ***************************** ++\******************************************************************************/ ++ ++static gceSTATUS ++_HardwareToKernel( ++ IN gckOS Os, ++ IN gcuVIDMEM_NODE_PTR Node, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * KernelPointer ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM memory; ++ gctUINT32 offset; ++ gctUINT32 nodePhysical; ++ gctPOINTER *logical; ++ gctSIZE_T bytes; ++ status = gcvSTATUS_OK; ++ ++ memory = Node->VidMem.memory; ++ ++ if (memory->object.type == gcvOBJ_VIDMEM) ++ { ++ nodePhysical = memory->baseAddress ++ + (gctUINT32)Node->VidMem.offset ++ + Node->VidMem.alignment; ++ bytes = Node->VidMem.bytes; ++ logical = &Node->VidMem.kernelVirtual; ++ } ++ else ++ { ++ nodePhysical = Node->Virtual.physicalAddress; ++ bytes = Node->Virtual.bytes; ++ logical = &Node->Virtual.kernelVirtual; ++ } ++ ++ if (*logical == gcvNULL) ++ { ++ status = gckOS_MapPhysical(Os, nodePhysical, bytes, logical); ++ ++ if (gcmkIS_ERROR(status)) ++ { ++ return status; ++ } ++ } ++ ++ offset = Address - nodePhysical; ++ *KernelPointer = (gctPOINTER)((gctUINT8_PTR)(*logical) + offset); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_ConvertUserCommandBufferPointer( ++ IN gckVGCOMMAND Command, ++ IN gcsCMDBUFFER_PTR UserCommandBuffer, ++ OUT gcsCMDBUFFER_PTR * KernelCommandBuffer ++ ) ++{ ++ gceSTATUS status, last; ++ gcsCMDBUFFER_PTR mappedUserCommandBuffer = gcvNULL; ++ gckKERNEL kernel = Command->kernel->kernel; ++ gctUINT32 pid; ++ gckVIDMEM_NODE node; ++ ++ gckOS_GetProcessID(&pid); ++ ++ do ++ { ++ gctUINT32 headerAddress; ++ ++ /* Map the command buffer structure into the kernel space. */ ++ gcmkERR_BREAK(gckOS_MapUserPointer( ++ Command->os, ++ UserCommandBuffer, ++ gcmSIZEOF(gcsCMDBUFFER), ++ (gctPOINTER *) &mappedUserCommandBuffer ++ )); ++ ++ /* Determine the address of the header. */ ++ headerAddress ++ = mappedUserCommandBuffer->address ++ - mappedUserCommandBuffer->bufferOffset; ++ ++ gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup( ++ kernel, ++ pid, ++ gcmPTR2INT32(mappedUserCommandBuffer->node), ++ &node)); ++ ++ /* Translate the logical address to the kernel space. */ ++ gcmkERR_BREAK(_HardwareToKernel( ++ Command->os, ++ node->node, ++ headerAddress, ++ (gctPOINTER *) KernelCommandBuffer ++ )); ++ } ++ while (gcvFALSE); ++ ++ /* Unmap the user command buffer. */ ++ if (mappedUserCommandBuffer != gcvNULL) ++ { ++ gcmkCHECK_STATUS(gckOS_UnmapUserPointer( ++ Command->os, ++ UserCommandBuffer, ++ gcmSIZEOF(gcsCMDBUFFER), ++ mappedUserCommandBuffer ++ )); ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_AllocateLinear( ++ IN gckVGCOMMAND Command, ++ IN gctUINT Size, ++ IN gctUINT Alignment, ++ OUT gcuVIDMEM_NODE_PTR * Node, ++ OUT gctUINT32 * Address, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ gceSTATUS status, last; ++ gctPOINTER logical; ++ gctPHYS_ADDR physical; ++ gctUINT32 address; ++ gctSIZE_T size = Size; ++ ++ do ++ { ++ gcmkERR_BREAK(gckOS_AllocateContiguous( ++ Command->os, ++ gcvFALSE, ++ &size, ++ &physical, ++ &logical ++ )); ++ ++ gcmkERR_BREAK(gckOS_GetPhysicalAddress(Command->os, logical, &address)); ++ ++ /* Set return values. */ ++ * Node = physical; ++ * Address = address; ++ * Logical = logical; ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Roll back. */ ++ if (physical != gcvNULL) ++ { ++ /* Free the command buffer. */ ++ gcmkCHECK_STATUS(gckOS_FreeContiguous(Command->os, physical, logical, size)); ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_FreeLinear( ++ IN gckVGKERNEL Kernel, ++ IN gcuVIDMEM_NODE_PTR Node, ++ IN gctPOINTER Logical ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ ++ do ++ { ++ gcmkERR_BREAK(gckOS_FreeContiguous(Kernel->os, Node, Logical, 1)); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++gceSTATUS ++_AllocateCommandBuffer( ++ IN gckVGCOMMAND Command, ++ IN gctSIZE_T Size, ++ OUT gcsCMDBUFFER_PTR * CommandBuffer ++ ) ++{ ++ gceSTATUS status, last; ++ gcuVIDMEM_NODE_PTR node = gcvNULL; ++ gcsCMDBUFFER_PTR commandBuffer = gcvNULL; ++ ++ do ++ { ++ gctUINT alignedHeaderSize; ++ gctUINT requestedSize; ++ gctUINT allocationSize; ++ gctUINT32 address = 0; ++ gctUINT8_PTR endCommand; ++ ++ /* Determine the aligned header size. */ ++ alignedHeaderSize ++ = (gctUINT32)gcmALIGN(gcmSIZEOF(gcsCMDBUFFER), Command->info.addressAlignment); ++ ++ /* Align the requested size. */ ++ requestedSize ++ = (gctUINT32)gcmALIGN(Size, Command->info.commandAlignment); ++ ++ /* Determine the size of the buffer to allocate. */ ++ allocationSize ++ = alignedHeaderSize ++ + requestedSize ++ + (gctUINT32)Command->info.staticTailSize; ++ ++ /* Allocate the command buffer. */ ++ gcmkERR_BREAK(_AllocateLinear( ++ Command, ++ allocationSize, ++ Command->info.addressAlignment, ++ &node, ++ &address, ++ (gctPOINTER *) &commandBuffer ++ )); ++ ++ /* Initialize the structure. */ ++ commandBuffer->completion = gcvVACANT_BUFFER; ++ commandBuffer->node = node; ++ commandBuffer->address = address + alignedHeaderSize; ++ commandBuffer->bufferOffset = alignedHeaderSize; ++ commandBuffer->size = requestedSize; ++ commandBuffer->offset = requestedSize; ++ commandBuffer->nextAllocated = gcvNULL; ++ commandBuffer->nextSubBuffer = gcvNULL; ++ ++ /* Determine the data count. */ ++ commandBuffer->dataCount ++ = (requestedSize + Command->info.staticTailSize) ++ / Command->info.commandAlignment; ++ ++ /* Determine the location of the END command. */ ++ endCommand ++ = (gctUINT8_PTR) commandBuffer ++ + alignedHeaderSize ++ + requestedSize; ++ ++ /* Append an END command. */ ++ gcmkERR_BREAK(gckVGCOMMAND_EndCommand( ++ Command, ++ endCommand, ++ Command->info.feBufferInt, ++ gcvNULL ++ )); ++ ++ /* Set the return pointer. */ ++ * CommandBuffer = commandBuffer; ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Roll back. */ ++ if (node != gcvNULL) ++ { ++ /* Free the command buffer. */ ++ gcmkCHECK_STATUS(_FreeLinear(Command->kernel, node, commandBuffer)); ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_FreeCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsCMDBUFFER_PTR CommandBuffer ++ ) ++{ ++ gceSTATUS status; ++ ++ /* Free the buffer. */ ++ status = _FreeLinear(Kernel, CommandBuffer->node, CommandBuffer); ++ ++ /* Return status. */ ++ return status; ++} ++ ++ ++/******************************************************************************\ ++****************************** TS Overflow Handler ***************************** ++\******************************************************************************/ ++ ++static gceSTATUS ++_EventHandler_TSOverflow( ++ IN gckVGKERNEL Kernel ++ ) ++{ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): **** TS OVERFLOW ENCOUNTERED ****\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ return gcvSTATUS_OK; ++} ++ ++ ++/******************************************************************************\ ++****************************** Bus Error Handler ******************************* ++\******************************************************************************/ ++ ++static gceSTATUS ++_EventHandler_BusError( ++ IN gckVGKERNEL Kernel ++ ) ++{ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): **** BUS ERROR ENCOUNTERED ****\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************\ ++****************************** Power Stall Handler ******************************* ++\******************************************************************************/ ++ ++static gceSTATUS ++_EventHandler_PowerStall( ++ IN gckVGKERNEL Kernel ++ ) ++{ ++ /* Signal. */ ++ return gckOS_Signal( ++ Kernel->os, ++ Kernel->command->powerStallSignal, ++ gcvTRUE); ++} ++ ++/******************************************************************************\ ++******************************** Task Routines ********************************* ++\******************************************************************************/ ++ ++typedef gceSTATUS (* gctTASKROUTINE) ( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskLink( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskCluster( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskIncrement( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskDecrement( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskSignal( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskLockdown( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskUnlockVideoMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskFreeVideoMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskFreeContiguousMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gceSTATUS ++_TaskUnmapUserMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ); ++ ++static gctTASKROUTINE _taskRoutine[] = ++{ ++ _TaskLink, /* gcvTASK_LINK */ ++ _TaskCluster, /* gcvTASK_CLUSTER */ ++ _TaskIncrement, /* gcvTASK_INCREMENT */ ++ _TaskDecrement, /* gcvTASK_DECREMENT */ ++ _TaskSignal, /* gcvTASK_SIGNAL */ ++ _TaskLockdown, /* gcvTASK_LOCKDOWN */ ++ _TaskUnlockVideoMemory, /* gcvTASK_UNLOCK_VIDEO_MEMORY */ ++ _TaskFreeVideoMemory, /* gcvTASK_FREE_VIDEO_MEMORY */ ++ _TaskFreeContiguousMemory, /* gcvTASK_FREE_CONTIGUOUS_MEMORY */ ++ _TaskUnmapUserMemory, /* gcvTASK_UNMAP_USER_MEMORY */ ++}; ++ ++static gceSTATUS ++_TaskLink( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ /* Cast the task pointer. */ ++ gcsTASK_LINK_PTR task = (gcsTASK_LINK_PTR) TaskHeader->task; ++ ++ /* Save the pointer to the container. */ ++ gcsTASK_CONTAINER_PTR container = TaskHeader->container; ++ ++ /* No more tasks in the list? */ ++ if (task->task == gcvNULL) ++ { ++ /* Reset the entry. */ ++ TaskHeader->container = gcvNULL; ++ TaskHeader->task = gcvNULL; ++ TaskHeader->link = gcvNULL; ++ } ++ else ++ { ++ /* Update the entry. */ ++ TaskHeader->container = task->cotainer; ++ TaskHeader->task = task->task; ++ } ++ ++ /* Decrement the task buffer reference. */ ++ gcmkASSERT(container->referenceCount >= 0); ++ if (container->referenceCount == 0) ++ { ++ /* Free the container. */ ++ _FreeTaskContainer(Command, container); ++ } ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++static gceSTATUS ++_TaskCluster( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ ++ /* Cast the task pointer. */ ++ gcsTASK_CLUSTER_PTR cluster = (gcsTASK_CLUSTER_PTR) TaskHeader->task; ++ ++ /* Get the number of tasks. */ ++ gctUINT taskCount = cluster->taskCount; ++ ++ /* Advance to the next task. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (cluster + 1); ++ ++ /* Perform all tasks in the cluster. */ ++ while (taskCount) ++ { ++ /* Perform the current task. */ ++ gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id]( ++ Command, ++ TaskHeader ++ )); ++ ++ /* Update the task count. */ ++ taskCount -= 1; ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskIncrement( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_INCREMENT_PTR task = (gcsTASK_INCREMENT_PTR) TaskHeader->task; ++ ++ /* Convert physical into logical address. */ ++ gctUINT32_PTR logical; ++ gcmkERR_BREAK(gckOS_MapPhysical( ++ Command->os, ++ task->address, ++ gcmSIZEOF(gctUINT32), ++ (gctPOINTER *) &logical ++ )); ++ ++ /* Increment data. */ ++ (* logical) += 1; ++ ++ /* Unmap the physical memory. */ ++ gcmkERR_BREAK(gckOS_UnmapPhysical( ++ Command->os, ++ logical, ++ gcmSIZEOF(gctUINT32) ++ )); ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskDecrement( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_DECREMENT_PTR task = (gcsTASK_DECREMENT_PTR) TaskHeader->task; ++ ++ /* Convert physical into logical address. */ ++ gctUINT32_PTR logical; ++ gcmkERR_BREAK(gckOS_MapPhysical( ++ Command->os, ++ task->address, ++ gcmSIZEOF(gctUINT32), ++ (gctPOINTER *) &logical ++ )); ++ ++ /* Decrement data. */ ++ (* logical) -= 1; ++ ++ /* Unmap the physical memory. */ ++ gcmkERR_BREAK(gckOS_UnmapPhysical( ++ Command->os, ++ logical, ++ gcmSIZEOF(gctUINT32) ++ )); ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskSignal( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_SIGNAL_PTR task = (gcsTASK_SIGNAL_PTR) TaskHeader->task; ++ ++ ++ /* Map the signal into kernel space. */ ++ gcmkERR_BREAK(gckOS_UserSignal( ++ Command->os, task->signal, task->process ++ )); ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskLockdown( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32_PTR userCounter = gcvNULL; ++ gctUINT32_PTR kernelCounter = gcvNULL; ++ gctSIGNAL signal = gcvNULL; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_LOCKDOWN_PTR task = (gcsTASK_LOCKDOWN_PTR) TaskHeader->task; ++ ++ /* Convert physical addresses into logical. */ ++ gcmkERR_BREAK(gckOS_MapPhysical( ++ Command->os, ++ task->userCounter, ++ gcmSIZEOF(gctUINT32), ++ (gctPOINTER *) &userCounter ++ )); ++ ++ gcmkERR_BREAK(gckOS_MapPhysical( ++ Command->os, ++ task->kernelCounter, ++ gcmSIZEOF(gctUINT32), ++ (gctPOINTER *) &kernelCounter ++ )); ++ ++ /* Update the kernel counter. */ ++ (* kernelCounter) += 1; ++ ++ /* Are the counters equal? */ ++ if ((* userCounter) == (* kernelCounter)) ++ { ++ /* Map the signal into kernel space. */ ++ gcmkERR_BREAK(gckOS_MapSignal( ++ Command->os, task->signal, task->process, &signal ++ )); ++ ++ if (signal == gcvNULL) ++ { ++ /* Signal. */ ++ gcmkERR_BREAK(gckOS_Signal( ++ Command->os, task->signal, gcvTRUE ++ )); ++ } ++ else ++ { ++ /* Signal. */ ++ gcmkERR_BREAK(gckOS_Signal( ++ Command->os, signal, gcvTRUE ++ )); ++ } ++ } ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Destroy the mapped signal. */ ++ if (signal != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DestroySignal( ++ Command->os, signal ++ )); ++ } ++ ++ /* Unmap the physical memory. */ ++ if (kernelCounter != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_UnmapPhysical( ++ Command->os, ++ kernelCounter, ++ gcmSIZEOF(gctUINT32) ++ )); ++ } ++ ++ if (userCounter != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_UnmapPhysical( ++ Command->os, ++ userCounter, ++ gcmSIZEOF(gctUINT32) ++ )); ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskUnlockVideoMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_UNLOCK_VIDEO_MEMORY_PTR task ++ = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR) TaskHeader->task; ++ ++ /* Unlock video memory. */ ++ gcmkERR_BREAK(gckVIDMEM_Unlock( ++ Command->kernel->kernel, ++ (gckVIDMEM_NODE)gcmUINT64_TO_PTR(task->node), ++ gcvSURF_TYPE_UNKNOWN, ++ gcvNULL)); ++ ++ gcmkERR_BREAK(gckVIDMEM_NODE_Dereference( ++ Command->kernel->kernel, ++ gcmUINT64_TO_PTR(task->node))); ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskFreeVideoMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_FREE_VIDEO_MEMORY_PTR task ++ = (gcsTASK_FREE_VIDEO_MEMORY_PTR) TaskHeader->task; ++ ++ /* Free video memory. */ ++ gcmkERR_BREAK(gckVIDMEM_NODE_Dereference( ++ Command->kernel->kernel, ++ gcmINT2PTR(task->node))); ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskFreeContiguousMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR task ++ = (gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR) TaskHeader->task; ++ ++ /* Free contiguous memory. */ ++ gcmkERR_BREAK(gckOS_FreeContiguous( ++ Command->os, task->physical, task->logical, task->bytes ++ )); ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_TaskUnmapUserMemory( ++ gckVGCOMMAND Command, ++ gcsBLOCK_TASK_ENTRY_PTR TaskHeader ++ ) ++{ ++ gceSTATUS status; ++ gctPOINTER info; ++ ++ do ++ { ++ /* Cast the task pointer. */ ++ gcsTASK_UNMAP_USER_MEMORY_PTR task ++ = (gcsTASK_UNMAP_USER_MEMORY_PTR) TaskHeader->task; ++ ++ info = gckKERNEL_QueryPointerFromName( ++ Command->kernel->kernel, gcmALL_TO_UINT32(task->info)); ++ ++ /* Unmap the user memory. */ ++ gcmkERR_BREAK(gckOS_UnmapUserMemory( ++ Command->os, gcvCORE_VG, task->memory, task->size, info, task->address ++ )); ++ ++ /* Update the reference counter. */ ++ TaskHeader->container->referenceCount -= 1; ++ ++ /* Update the task pointer. */ ++ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++/******************************************************************************\ ++************ Hardware Block Interrupt Handlers For Scheduled Events ************ ++\******************************************************************************/ ++ ++static gceSTATUS ++_EventHandler_Block( ++ IN gckVGKERNEL Kernel, ++ IN gcsBLOCK_TASK_ENTRY_PTR TaskHeader, ++ IN gctBOOL ProcessAll ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK, last; ++ ++ gcmkHEADER_ARG("Kernel=0x%x TaskHeader=0x%x ProcessAll=0x%x", Kernel, TaskHeader, ProcessAll); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ if (TaskHeader->task == gcvNULL) ++ { ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++ } ++ ++ do ++ { ++ gckVGCOMMAND command; ++ ++ /* Get the command buffer object. */ ++ command = Kernel->command; ++ ++ /* Increment the interrupt usage semaphore. */ ++ gcmkERR_BREAK(gckOS_IncrementSemaphore( ++ command->os, TaskHeader->interruptSemaphore ++ )); ++ ++ /* Acquire the mutex. */ ++ gcmkERR_BREAK(gckOS_AcquireMutex( ++ command->os, ++ command->taskMutex, ++ gcvINFINITE ++ )); ++ ++ /* Verify inputs. */ ++ gcmkASSERT(TaskHeader != gcvNULL); ++ gcmkASSERT(TaskHeader->container != gcvNULL); ++ gcmkASSERT(TaskHeader->task != gcvNULL); ++ gcmkASSERT(TaskHeader->link != gcvNULL); ++ ++ /* Process tasks. */ ++ do ++ { ++ /* Process the current task. */ ++ gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id]( ++ command, ++ TaskHeader ++ )); ++ ++ /* Is the next task is LINK? */ ++ if (TaskHeader->task->id == gcvTASK_LINK) ++ { ++ gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id]( ++ command, ++ TaskHeader ++ )); ++ ++ /* Done. */ ++ break; ++ } ++ } ++ while (ProcessAll); ++ ++ /* Release the mutex. */ ++ gcmkCHECK_STATUS(gckOS_ReleaseMutex( ++ command->os, ++ command->taskMutex ++ )); ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++gcmDECLARE_INTERRUPT_HANDLER(COMMAND, 0) ++{ ++ gceSTATUS status, last; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ", Kernel); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ ++ do ++ { ++ gckVGCOMMAND command; ++ gcsKERNEL_QUEUE_HEADER_PTR mergeQueue; ++ gcsKERNEL_QUEUE_HEADER_PTR queueTail; ++ gcsKERNEL_CMDQUEUE_PTR entry; ++ gctUINT entryCount; ++ ++ /* Get the command buffer object. */ ++ command = Kernel->command; ++ ++ /* Acquire the mutex. */ ++ gcmkERR_BREAK(gckOS_AcquireMutex( ++ command->os, ++ command->queueMutex, ++ gcvINFINITE ++ )); ++ ++ /* Get the current queue. */ ++ queueTail = command->queueTail; ++ ++ /* Get the current queue entry. */ ++ entry = queueTail->currentEntry; ++ ++ /* Get the number of entries in the queue. */ ++ entryCount = queueTail->pending; ++ ++ /* Process all entries. */ ++ while (gcvTRUE) ++ { ++ /* Call post-execution function. */ ++ status = entry->handler(Kernel, entry); ++ ++ /* Failed? */ ++ if (gcmkIS_ERROR(status)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, ++ gcvZONE_COMMAND, ++ "[%s] line %d: post action failed.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ ++ /* Executed the next buffer? */ ++ if (status == gcvSTATUS_EXECUTED) ++ { ++ /* Update the queue. */ ++ queueTail->pending = entryCount; ++ queueTail->currentEntry = entry; ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ ++ /* Break out of the loop. */ ++ break; ++ } ++ ++ /* Advance to the next entry. */ ++ entry += 1; ++ entryCount -= 1; ++ ++ /* Last entry? */ ++ if (entryCount == 0) ++ { ++ /* Reset the queue to idle. */ ++ queueTail->pending = 0; ++ ++ /* Get a shortcut to the queue to merge with. */ ++ mergeQueue = command->mergeQueue; ++ ++ /* Merge the queues if necessary. */ ++ if (mergeQueue != queueTail) ++ { ++ gcmkASSERT(mergeQueue < queueTail); ++ gcmkASSERT(mergeQueue->next == queueTail); ++ ++ mergeQueue->size ++ += gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) ++ + queueTail->size; ++ ++ mergeQueue->next = queueTail->next; ++ } ++ ++ /* Advance to the next queue. */ ++ queueTail = queueTail->next; ++ ++ /* Did it wrap around? */ ++ if (command->queue == queueTail) ++ { ++ /* Reset merge queue. */ ++ command->mergeQueue = queueTail; ++ } ++ ++ /* Set new queue. */ ++ command->queueTail = queueTail; ++ ++ /* Is the next queue scheduled? */ ++ if (queueTail->pending > 0) ++ { ++ gcsCMDBUFFER_PTR commandBuffer; ++ ++ /* The first entry must be a command buffer. */ ++ commandBuffer = queueTail->currentEntry->commandBuffer; ++ ++ /* Start the command processor. */ ++ status = gckVGHARDWARE_Execute( ++ command->hardware, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ ); ++ ++ /* Failed? */ ++ if (gcmkIS_ERROR(status)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, ++ gcvZONE_COMMAND, ++ "[%s] line %d: failed to start the next queue.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ } ++ else ++ { ++ status = gckVGHARDWARE_SetPowerManagementState( ++ Kernel->command->hardware, gcvPOWER_IDLE_BROADCAST ++ ); ++ } ++ ++ /* Break out of the loop. */ ++ break; ++ } ++ } ++ ++ /* Release the mutex. */ ++ gcmkCHECK_STATUS(gckOS_ReleaseMutex( ++ command->os, ++ command->queueMutex ++ )); ++ } ++ while (gcvFALSE); ++ ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++/* Define standard block interrupt handlers. */ ++gcmDEFINE_INTERRUPT_HANDLER(TESSELLATOR, 0) ++gcmDEFINE_INTERRUPT_HANDLER(VG, 0) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 0) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 1) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 2) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 3) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 4) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 5) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 6) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 7) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 8) ++gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 9) ++ ++/* The entries in the array are arranged by event priority. */ ++static gcsBLOCK_INTERRUPT_HANDLER _blockHandlers[] = ++{ ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(TESSELLATOR, 0), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(VG, 0), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 0), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 1), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 2), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 3), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 4), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 5), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 6), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 7), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 8), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 9), ++ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(COMMAND, 0), ++}; ++ ++ ++/******************************************************************************\ ++************************* Static Command Buffer Handlers *********************** ++\******************************************************************************/ ++ ++static gceSTATUS ++_UpdateStaticCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d)\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++static gceSTATUS ++_ExecuteStaticCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ gcsCMDBUFFER_PTR commandBuffer; ++ ++ /* Cast the command buffer header. */ ++ commandBuffer = Entry->commandBuffer; ++ ++ /* Set to update the command buffer next time. */ ++ Entry->handler = _UpdateStaticCommandBuffer; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", ++ __FUNCTION__, __LINE__, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ ); ++ ++ /* Start the command processor. */ ++ gcmkERR_BREAK(gckVGHARDWARE_Execute( ++ Kernel->hardware, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ )); ++ ++ /* Success. */ ++ return gcvSTATUS_EXECUTED; ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_UpdateLastStaticCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++#if gcvDEBUG || gcdFORCE_MESSAGES ++ /* Get the command buffer header. */ ++ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; ++ ++ /* Validate the command buffer. */ ++ gcmkASSERT(commandBuffer->completion != gcvNULL); ++ gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER); ++ ++#endif ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d): processing all tasks scheduled for FE.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Perform scheduled tasks. */ ++ return _EventHandler_Block( ++ Kernel, ++ &Kernel->command->taskTable[gcvBLOCK_COMMAND], ++ gcvTRUE ++ ); ++} ++ ++static gceSTATUS ++_ExecuteLastStaticCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the command buffer header. */ ++ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; ++ ++ /* Set to update the command buffer next time. */ ++ Entry->handler = _UpdateLastStaticCommandBuffer; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", ++ __FUNCTION__, __LINE__, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ ); ++ ++ /* Start the command processor. */ ++ gcmkERR_BREAK(gckVGHARDWARE_Execute( ++ Kernel->hardware, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ )); ++ ++ /* Success. */ ++ return gcvSTATUS_EXECUTED; ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++ ++/******************************************************************************\ ++************************* Dynamic Command Buffer Handlers ********************** ++\******************************************************************************/ ++ ++static gceSTATUS ++_UpdateDynamicCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d)\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++static gceSTATUS ++_ExecuteDynamicCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the command buffer header. */ ++ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; ++ ++ /* Set to update the command buffer next time. */ ++ Entry->handler = _UpdateDynamicCommandBuffer; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", ++ __FUNCTION__, __LINE__, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ ); ++ ++ /* Start the command processor. */ ++ gcmkERR_BREAK(gckVGHARDWARE_Execute( ++ Kernel->hardware, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ )); ++ ++ /* Success. */ ++ return gcvSTATUS_EXECUTED; ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_UpdateLastDynamicCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++#if gcvDEBUG || gcdFORCE_MESSAGES ++ /* Get the command buffer header. */ ++ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; ++ ++ /* Validate the command buffer. */ ++ gcmkASSERT(commandBuffer->completion != gcvNULL); ++ gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER); ++ ++#endif ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d): processing all tasks scheduled for FE.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Perform scheduled tasks. */ ++ return _EventHandler_Block( ++ Kernel, ++ &Kernel->command->taskTable[gcvBLOCK_COMMAND], ++ gcvTRUE ++ ); ++} ++ ++static gceSTATUS ++_ExecuteLastDynamicCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Cast the command buffer header. */ ++ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; ++ ++ /* Set to update the command buffer next time. */ ++ Entry->handler = _UpdateLastDynamicCommandBuffer; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", ++ __FUNCTION__, __LINE__, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ ); ++ ++ /* Start the command processor. */ ++ gcmkERR_BREAK(gckVGHARDWARE_Execute( ++ Kernel->hardware, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ )); ++ ++ /* Success. */ ++ return gcvSTATUS_EXECUTED; ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++ ++/******************************************************************************\ ++********************************* Other Handlers ******************************* ++\******************************************************************************/ ++ ++static gceSTATUS ++_FreeKernelCommandBuffer( ++ IN gckVGKERNEL Kernel, ++ IN gcsKERNEL_CMDQUEUE_PTR Entry ++ ) ++{ ++ gceSTATUS status; ++ ++ /* Free the command buffer. */ ++ status = _FreeCommandBuffer(Kernel, Entry->commandBuffer); ++ ++ /* Return status. */ ++ return status; ++} ++ ++ ++/******************************************************************************\ ++******************************* Queue Management ******************************* ++\******************************************************************************/ ++ ++#if gcvDUMP_COMMAND_BUFFER ++static void ++_DumpCommandQueue( ++ IN gckVGCOMMAND Command, ++ IN gcsKERNEL_QUEUE_HEADER_PTR QueueHeader, ++ IN gctUINT EntryCount ++ ) ++{ ++ gcsKERNEL_CMDQUEUE_PTR entry; ++ gctUINT queueIndex; ++ ++#if defined(gcvCOMMAND_BUFFER_NAME) ++ static gctUINT arrayCount = 0; ++#endif ++ ++ /* Is dumpinng enabled? */ ++ if (!Commad->enableDumping) ++ { ++ return; ++ } ++ ++#if !defined(gcvCOMMAND_BUFFER_NAME) ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_COMMAND, ++ "COMMAND QUEUE DUMP: %d entries\n", EntryCount ++ ); ++#endif ++ ++ /* Get the pointer to the first entry. */ ++ entry = QueueHeader->currentEntry; ++ ++ /* Iterate through the queue. */ ++ for (queueIndex = 0; queueIndex < EntryCount; queueIndex += 1) ++ { ++ gcsCMDBUFFER_PTR buffer; ++ gctUINT bufferCount; ++ gctUINT bufferIndex; ++ gctUINT i, count; ++ gctUINT size; ++ gctUINT32_PTR data; ++ ++#if gcvDUMP_COMMAND_LINES ++ gctUINT lineNumber; ++#endif ++ ++#if !defined(gcvCOMMAND_BUFFER_NAME) ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_COMMAND, ++ "ENTRY %d\n", queueIndex ++ ); ++#endif ++ ++ /* Reset the count. */ ++ bufferCount = 0; ++ ++ /* Set the initial buffer. */ ++ buffer = entry->commandBuffer; ++ ++ /* Loop through all subbuffers. */ ++ while (buffer) ++ { ++ /* Update the count. */ ++ bufferCount += 1; ++ ++ /* Advance to the next subbuffer. */ ++ buffer = buffer->nextSubBuffer; ++ } ++ ++#if !defined(gcvCOMMAND_BUFFER_NAME) ++ if (bufferCount > 1) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, ++ gcvZONE_COMMAND, ++ " COMMAND BUFFER SET: %d buffers.\n", ++ bufferCount ++ ); ++ } ++#endif ++ ++ /* Reset the buffer index. */ ++ bufferIndex = 0; ++ ++ /* Set the initial buffer. */ ++ buffer = entry->commandBuffer; ++ ++ /* Loop through all subbuffers. */ ++ while (buffer) ++ { ++ /* Determine the size of the buffer. */ ++ size = buffer->dataCount * Command->info.commandAlignment; ++ ++#if !defined(gcvCOMMAND_BUFFER_NAME) ++ /* A single buffer? */ ++ if (bufferCount == 1) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, ++ gcvZONE_COMMAND, ++ " COMMAND BUFFER: count=%d (0x%X), size=%d bytes @ %08X.\n", ++ buffer->dataCount, ++ buffer->dataCount, ++ size, ++ buffer->address ++ ); ++ } ++ else ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, ++ gcvZONE_COMMAND, ++ " COMMAND BUFFER %d: count=%d (0x%X), size=%d bytes @ %08X\n", ++ bufferIndex, ++ buffer->dataCount, ++ buffer->dataCount, ++ size, ++ buffer->address ++ ); ++ } ++#endif ++ ++ /* Determine the number of double words to print. */ ++ count = size / 4; ++ ++ /* Determine the buffer location. */ ++ data = (gctUINT32_PTR) ++ ( ++ (gctUINT8_PTR) buffer + buffer->bufferOffset ++ ); ++ ++#if defined(gcvCOMMAND_BUFFER_NAME) ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, ++ gcvZONE_COMMAND, ++ "unsigned int _" gcvCOMMAND_BUFFER_NAME "_%d[] =\n", ++ arrayCount ++ ); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, ++ gcvZONE_COMMAND, ++ "{\n" ++ ); ++ ++ arrayCount += 1; ++#endif ++ ++#if gcvDUMP_COMMAND_LINES ++ /* Reset the line number. */ ++ lineNumber = 0; ++#endif ++ ++#if defined(gcvCOMMAND_BUFFER_NAME) ++ count -= 2; ++#endif ++ ++ for (i = 0; i < count; i += 1) ++ { ++ if ((i % 8) == 0) ++ { ++#if defined(gcvCOMMAND_BUFFER_NAME) ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\t"); ++#else ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " "); ++#endif ++ } ++ ++#if gcvDUMP_COMMAND_LINES ++ if (lineNumber == gcvDUMP_COMMAND_LINES) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " . . . . . . . . .\n"); ++ break; ++ } ++#endif ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "0x%08X", data[i]); ++ ++ if (i + 1 == count) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\n"); ++ ++#if gcvDUMP_COMMAND_LINES ++ lineNumber += 1; ++#endif ++ } ++ else ++ { ++ if (((i + 1) % 8) == 0) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ",\n"); ++ ++#if gcvDUMP_COMMAND_LINES ++ lineNumber += 1; ++#endif ++ } ++ else ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ", "); ++ } ++ } ++ } ++ ++#if defined(gcvCOMMAND_BUFFER_NAME) ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, ++ gcvZONE_COMMAND, ++ "};\n\n" ++ ); ++#endif ++ ++ /* Advance to the next subbuffer. */ ++ buffer = buffer->nextSubBuffer; ++ bufferIndex += 1; ++ } ++ ++ /* Advance to the next entry. */ ++ entry += 1; ++ } ++} ++#endif ++ ++static gceSTATUS ++_LockCurrentQueue( ++ IN gckVGCOMMAND Command, ++ OUT gcsKERNEL_CMDQUEUE_PTR * Entries, ++ OUT gctUINT_PTR EntryCount ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ gcsKERNEL_QUEUE_HEADER_PTR queueHead; ++ ++ /* Get a shortcut to the head of the queue. */ ++ queueHead = Command->queueHead; ++ ++ /* Is the head buffer still being worked on? */ ++ if (queueHead->pending) ++ { ++ /* Increment overflow count. */ ++ Command->queueOverflow += 1; ++ ++ /* Wait until the head becomes idle. */ ++ gcmkERR_BREAK(_WaitForIdle(Command, queueHead)); ++ } ++ ++ /* Acquire the mutex. */ ++ gcmkERR_BREAK(gckOS_AcquireMutex( ++ Command->os, ++ Command->queueMutex, ++ gcvINFINITE ++ )); ++ ++ /* Determine the first queue entry. */ ++ queueHead->currentEntry = (gcsKERNEL_CMDQUEUE_PTR) ++ ( ++ (gctUINT8_PTR) queueHead + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) ++ ); ++ ++ /* Set the pointer to the first entry. */ ++ * Entries = queueHead->currentEntry; ++ ++ /* Determine the number of available entries. */ ++ * EntryCount = queueHead->size / gcmSIZEOF(gcsKERNEL_CMDQUEUE); ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++static gceSTATUS ++_UnlockCurrentQueue( ++ IN gckVGCOMMAND Command, ++ IN gctUINT EntryCount ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++#if !gcdENABLE_INFINITE_SPEED_HW ++ gcsKERNEL_QUEUE_HEADER_PTR queueTail; ++ gcsKERNEL_QUEUE_HEADER_PTR queueHead; ++ gcsKERNEL_QUEUE_HEADER_PTR queueNext; ++ gctUINT queueSize; ++ gctUINT newSize; ++ gctUINT unusedSize; ++ ++ /* Get shortcut to the head and to the tail of the queue. */ ++ queueTail = Command->queueTail; ++ queueHead = Command->queueHead; ++ ++ /* Dump the command buffer. */ ++#if gcvDUMP_COMMAND_BUFFER ++ _DumpCommandQueue(Command, queueHead, EntryCount); ++#endif ++ ++ /* Get a shortcut to the current queue size. */ ++ queueSize = queueHead->size; ++ ++ /* Determine the new queue size. */ ++ newSize = EntryCount * gcmSIZEOF(gcsKERNEL_CMDQUEUE); ++ gcmkASSERT(newSize <= queueSize); ++ ++ /* Determine the size of the unused area. */ ++ unusedSize = queueSize - newSize; ++ ++ /* Is the unused area big enough to become a buffer? */ ++ if (unusedSize >= gcvMINUMUM_BUFFER) ++ { ++ gcsKERNEL_QUEUE_HEADER_PTR nextHead; ++ ++ /* Place the new header. */ ++ nextHead = (gcsKERNEL_QUEUE_HEADER_PTR) ++ ( ++ (gctUINT8_PTR) queueHead ++ + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) ++ + newSize ++ ); ++ ++ /* Initialize the buffer. */ ++ nextHead->size = unusedSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER); ++ nextHead->pending = 0; ++ ++ /* Link the buffer in. */ ++ nextHead->next = queueHead->next; ++ queueHead->next = nextHead; ++ queueNext = nextHead; ++ ++ /* Update the size of the current buffer. */ ++ queueHead->size = newSize; ++ } ++ ++ /* Not big enough. */ ++ else ++ { ++ /* Determine the next queue. */ ++ queueNext = queueHead->next; ++ } ++ ++ /* Mark the buffer as busy. */ ++ queueHead->pending = EntryCount; ++ ++ /* Advance to the next buffer. */ ++ Command->queueHead = queueNext; ++ ++ /* Start the command processor if the queue was empty. */ ++ if (queueTail == queueHead) ++ { ++ gcsCMDBUFFER_PTR commandBuffer; ++ ++ /* The first entry must be a command buffer. */ ++ commandBuffer = queueTail->currentEntry->commandBuffer; ++ ++ /* Start the command processor. */ ++ gcmkERR_BREAK(gckVGHARDWARE_Execute( ++ Command->hardware, ++ commandBuffer->address, ++ commandBuffer->dataCount ++ )); ++ } ++ ++ /* The queue was not empty. */ ++ else ++ { ++ /* Advance the merge buffer if needed. */ ++ if (queueHead == Command->mergeQueue) ++ { ++ Command->mergeQueue = queueNext; ++ } ++ } ++#endif ++ ++ /* Release the mutex. */ ++ gcmkERR_BREAK(gckOS_ReleaseMutex( ++ Command->os, ++ Command->queueMutex ++ )); ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ return status; ++} ++ ++ ++ ++/******************************************************************************\ ++****************************** gckVGCOMMAND API Code ***************************** ++\******************************************************************************/ ++gceSTATUS ++gckVGCOMMAND_Construct( ++ IN gckVGKERNEL Kernel, ++ IN gctUINT TaskGranularity, ++ IN gctUINT QueueSize, ++ OUT gckVGCOMMAND * Command ++ ) ++{ ++ gceSTATUS status, last; ++ gckVGCOMMAND command = gcvNULL; ++ gcsKERNEL_QUEUE_HEADER_PTR queue; ++ gctUINT i, j; ++ ++ gcmkHEADER_ARG("Kernel=0x%x TaskGranularity=0x%x QueueSize=0x%x Command=0x%x", ++ Kernel, TaskGranularity, QueueSize, Command); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(QueueSize >= gcvMINUMUM_BUFFER); ++ gcmkVERIFY_ARGUMENT(Command != gcvNULL); ++ ++ do ++ { ++ /*********************************************************************** ++ ** Generic object initialization. ++ */ ++ ++ /* Allocate the gckVGCOMMAND structure. */ ++ gcmkERR_BREAK(gckOS_Allocate( ++ Kernel->os, ++ gcmSIZEOF(struct _gckVGCOMMAND), ++ (gctPOINTER *) &command ++ )); ++ ++ /* Initialize the object. */ ++ command->object.type = gcvOBJ_COMMAND; ++ ++ /* Set the object pointers. */ ++ command->kernel = Kernel; ++ command->os = Kernel->os; ++ command->hardware = Kernel->hardware; ++ ++ /* Reset pointers. */ ++ command->queue = gcvNULL; ++ command->queueMutex = gcvNULL; ++ command->taskMutex = gcvNULL; ++ command->commitMutex = gcvNULL; ++ ++ command->powerStallBuffer = gcvNULL; ++ command->powerStallSignal = gcvNULL; ++ command->powerSemaphore = gcvNULL; ++ ++ /* Reset context states. */ ++ command->contextCounter = 0; ++ command->currentContext = 0; ++ ++ /* Enable command buffer dumping. */ ++ command->enableDumping = gcvTRUE; ++ ++ /* Set features. */ ++ command->fe20 = Kernel->hardware->fe20; ++ command->vg20 = Kernel->hardware->vg20; ++ command->vg21 = Kernel->hardware->vg21; ++ ++ /* Reset task table .*/ ++ gcmkVERIFY_OK(gckOS_ZeroMemory( ++ command->taskTable, gcmSIZEOF(command->taskTable) ++ )); ++ ++ /* Query command buffer attributes. */ ++ gcmkERR_BREAK(gckVGCOMMAND_InitializeInfo(command)); ++ ++ /* Create the control mutexes. */ ++ gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->queueMutex)); ++ gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->taskMutex)); ++ gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->commitMutex)); ++ ++ /* Create the power management semaphore. */ ++ gcmkERR_BREAK(gckOS_CreateSemaphore(Kernel->os, ++ &command->powerSemaphore)); ++ ++ gcmkERR_BREAK(gckOS_CreateSignal(Kernel->os, ++ gcvFALSE, &command->powerStallSignal)); ++ ++ /*********************************************************************** ++ ** Command queue initialization. ++ */ ++ ++ /* Allocate the command queue. */ ++ gcmkERR_BREAK(gckOS_Allocate( ++ Kernel->os, ++ QueueSize, ++ (gctPOINTER *) &command->queue ++ )); ++ ++ /* Initialize the command queue. */ ++ queue = command->queue; ++ ++ queue->size = QueueSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER); ++ queue->pending = 0; ++ queue->next = queue; ++ ++ command->queueHead = ++ command->queueTail = ++ command->mergeQueue = command->queue; ++ ++ command->queueOverflow = 0; ++ ++ ++ /*********************************************************************** ++ ** Enable TS overflow interrupt. ++ */ ++ ++ command->info.tsOverflowInt = 0; ++ gcmkERR_BREAK(gckVGINTERRUPT_Enable( ++ Kernel->interrupt, ++ &command->info.tsOverflowInt, ++ _EventHandler_TSOverflow ++ )); ++ ++ /* Mask out the interrupt. */ ++ Kernel->hardware->eventMask &= ~(1 << command->info.tsOverflowInt); ++ ++ ++ /*********************************************************************** ++ ** Enable Bus Error interrupt. ++ */ ++ ++ /* Hardwired to bit 31. */ ++ command->busErrorInt = 31; ++ ++ /* Enable the interrupt. */ ++ gcmkERR_BREAK(gckVGINTERRUPT_Enable( ++ Kernel->interrupt, ++ &command->busErrorInt, ++ _EventHandler_BusError ++ )); ++ ++ ++ command->powerStallInt = 30; ++ /* Enable the interrupt. */ ++ gcmkERR_BREAK(gckVGINTERRUPT_Enable( ++ Kernel->interrupt, ++ &command->powerStallInt, ++ _EventHandler_PowerStall ++ )); ++ ++ /*********************************************************************** ++ ** Task management initialization. ++ */ ++ ++ command->taskStorage = gcvNULL; ++ command->taskStorageGranularity = TaskGranularity; ++ command->taskStorageUsable = TaskGranularity - gcmSIZEOF(gcsTASK_STORAGE); ++ ++ command->taskFreeHead = gcvNULL; ++ command->taskFreeTail = gcvNULL; ++ ++ /* Enable block handlers. */ ++ for (i = 0; i < gcmCOUNTOF(_blockHandlers); i += 1) ++ { ++ /* Get the target hardware block. */ ++ gceBLOCK block = _blockHandlers[i].block; ++ ++ /* Get the interrupt array entry. */ ++ gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[block]; ++ ++ /* Determine the interrupt value index. */ ++ gctUINT index = entry->interruptCount; ++ ++ /* Create the block semaphore. */ ++ if (entry->interruptSemaphore == gcvNULL) ++ { ++ gcmkERR_BREAK(gckOS_CreateSemaphoreVG( ++ command->os, &entry->interruptSemaphore ++ )); ++ } ++ ++ /* Enable auto-detection. */ ++ entry->interruptArray[index] = -1; ++ ++ /* Enable interrupt for the block. */ ++ gcmkERR_BREAK(gckVGINTERRUPT_Enable( ++ Kernel->interrupt, ++ &entry->interruptArray[index], ++ _blockHandlers[i].handler ++ )); ++ ++ /* Update the number of registered interrupts. */ ++ entry->interruptCount += 1; ++ ++ /* Inrement the semaphore to allow the usage of the registered ++ interrupt. */ ++ gcmkERR_BREAK(gckOS_IncrementSemaphore( ++ command->os, entry->interruptSemaphore ++ )); ++ ++ } ++ ++ /* Error? */ ++ if (gcmkIS_ERROR(status)) ++ { ++ break; ++ } ++ ++ /* Get the FE interrupt. */ ++ command->info.feBufferInt ++ = command->taskTable[gcvBLOCK_COMMAND].interruptArray[0]; ++ ++ /* Return gckVGCOMMAND object pointer. */ ++ *Command = command; ++ ++ gcmkFOOTER_ARG("*Command=0x%x",*Command); ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Roll back. */ ++ if (command != gcvNULL) ++ { ++ /* Disable block handlers. */ ++ for (i = 0; i < gcvBLOCK_COUNT; i += 1) ++ { ++ /* Get the task table entry. */ ++ gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[i]; ++ ++ /* Destroy the semaphore. */ ++ if (entry->interruptSemaphore != gcvNULL) ++ { ++ gcmkCHECK_STATUS(gckOS_DestroySemaphore( ++ command->os, entry->interruptSemaphore ++ )); ++ } ++ ++ /* Disable all enabled interrupts. */ ++ for (j = 0; j < entry->interruptCount; j += 1) ++ { ++ /* Must be a valid value. */ ++ gcmkASSERT(entry->interruptArray[j] >= 0); ++ gcmkASSERT(entry->interruptArray[j] <= 31); ++ ++ /* Disable the interrupt. */ ++ gcmkCHECK_STATUS(gckVGINTERRUPT_Disable( ++ Kernel->interrupt, ++ entry->interruptArray[j] ++ )); ++ } ++ } ++ ++ /* Disable the bus error interrupt. */ ++ gcmkCHECK_STATUS(gckVGINTERRUPT_Disable( ++ Kernel->interrupt, ++ command->busErrorInt ++ )); ++ ++ /* Disable TS overflow interrupt. */ ++ if (command->info.tsOverflowInt != -1) ++ { ++ gcmkCHECK_STATUS(gckVGINTERRUPT_Disable( ++ Kernel->interrupt, ++ command->info.tsOverflowInt ++ )); ++ } ++ ++ /* Delete the commit mutex. */ ++ if (command->commitMutex != gcvNULL) ++ { ++ gcmkCHECK_STATUS(gckOS_DeleteMutex( ++ Kernel->os, command->commitMutex ++ )); ++ } ++ ++ /* Delete the command queue mutex. */ ++ if (command->taskMutex != gcvNULL) ++ { ++ gcmkCHECK_STATUS(gckOS_DeleteMutex( ++ Kernel->os, command->taskMutex ++ )); ++ } ++ ++ /* Delete the command queue mutex. */ ++ if (command->queueMutex != gcvNULL) ++ { ++ gcmkCHECK_STATUS(gckOS_DeleteMutex( ++ Kernel->os, command->queueMutex ++ )); ++ } ++ ++ /* Delete the command queue. */ ++ if (command->queue != gcvNULL) ++ { ++ gcmkCHECK_STATUS(gckOS_Free( ++ Kernel->os, command->queue ++ )); ++ } ++ ++ if (command->powerSemaphore != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DestroySemaphore( ++ Kernel->os, command->powerSemaphore)); ++ } ++ ++ if (command->powerStallSignal != gcvNULL) ++ { ++ /* Create the power management semaphore. */ ++ gcmkVERIFY_OK(gckOS_DestroySignal( ++ Kernel->os, ++ command->powerStallSignal)); ++ } ++ ++ /* Free the gckVGCOMMAND structure. */ ++ gcmkCHECK_STATUS(gckOS_Free( ++ Kernel->os, command ++ )); ++ } ++ ++ gcmkFOOTER(); ++ /* Return the error. */ ++ return status; ++} ++ ++gceSTATUS ++gckVGCOMMAND_Destroy( ++ OUT gckVGCOMMAND Command ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ ++ gcmkHEADER_ARG("Command=0x%x", Command); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ ++ do ++ { ++ gctUINT i; ++ gcsTASK_STORAGE_PTR nextStorage; ++ ++ if (Command->queueHead != gcvNULL) ++ { ++ /* Wait until the head becomes idle. */ ++ gcmkERR_BREAK(_WaitForIdle(Command, Command->queueHead)); ++ } ++ ++ /* Disable block handlers. */ ++ for (i = 0; i < gcvBLOCK_COUNT; i += 1) ++ { ++ /* Get the interrupt array entry. */ ++ gcsBLOCK_TASK_ENTRY_PTR entry = &Command->taskTable[i]; ++ ++ /* Determine the index of the last interrupt in the array. */ ++ gctINT index = entry->interruptCount - 1; ++ ++ /* Destroy the semaphore. */ ++ if (entry->interruptSemaphore != gcvNULL) ++ { ++ gcmkERR_BREAK(gckOS_DestroySemaphore( ++ Command->os, entry->interruptSemaphore ++ )); ++ } ++ ++ /* Disable all enabled interrupts. */ ++ while (index >= 0) ++ { ++ /* Must be a valid value. */ ++ gcmkASSERT(entry->interruptArray[index] >= 0); ++ gcmkASSERT(entry->interruptArray[index] <= 31); ++ ++ /* Disable the interrupt. */ ++ gcmkERR_BREAK(gckVGINTERRUPT_Disable( ++ Command->kernel->interrupt, ++ entry->interruptArray[index] ++ )); ++ ++ /* Update to the next interrupt. */ ++ index -= 1; ++ entry->interruptCount -= 1; ++ } ++ ++ /* Error? */ ++ if (gcmkIS_ERROR(status)) ++ { ++ break; ++ } ++ } ++ ++ /* Error? */ ++ if (gcmkIS_ERROR(status)) ++ { ++ break; ++ } ++ ++ /* Disable the bus error interrupt. */ ++ gcmkERR_BREAK(gckVGINTERRUPT_Disable( ++ Command->kernel->interrupt, ++ Command->busErrorInt ++ )); ++ ++ /* Disable TS overflow interrupt. */ ++ if (Command->info.tsOverflowInt != -1) ++ { ++ gcmkERR_BREAK(gckVGINTERRUPT_Disable( ++ Command->kernel->interrupt, ++ Command->info.tsOverflowInt ++ )); ++ ++ Command->info.tsOverflowInt = -1; ++ } ++ ++ /* Delete the commit mutex. */ ++ if (Command->commitMutex != gcvNULL) ++ { ++ gcmkERR_BREAK(gckOS_DeleteMutex( ++ Command->os, Command->commitMutex ++ )); ++ ++ Command->commitMutex = gcvNULL; ++ } ++ ++ /* Delete the command queue mutex. */ ++ if (Command->taskMutex != gcvNULL) ++ { ++ gcmkERR_BREAK(gckOS_DeleteMutex( ++ Command->os, Command->taskMutex ++ )); ++ ++ Command->taskMutex = gcvNULL; ++ } ++ ++ /* Delete the command queue mutex. */ ++ if (Command->queueMutex != gcvNULL) ++ { ++ gcmkERR_BREAK(gckOS_DeleteMutex( ++ Command->os, Command->queueMutex ++ )); ++ ++ Command->queueMutex = gcvNULL; ++ } ++ ++ if (Command->powerSemaphore != gcvNULL) ++ { ++ /* Destroy the power management semaphore. */ ++ gcmkERR_BREAK(gckOS_DestroySemaphore( ++ Command->os, Command->powerSemaphore)); ++ } ++ ++ if (Command->powerStallSignal != gcvNULL) ++ { ++ /* Create the power management semaphore. */ ++ gcmkERR_BREAK(gckOS_DestroySignal( ++ Command->os, ++ Command->powerStallSignal)); ++ } ++ ++ if (Command->queue != gcvNULL) ++ { ++ /* Delete the command queue. */ ++ gcmkERR_BREAK(gckOS_Free( ++ Command->os, Command->queue ++ )); ++ } ++ ++ /* Destroy all allocated buffers. */ ++ while (Command->taskStorage) ++ { ++ /* Copy the buffer pointer. */ ++ nextStorage = Command->taskStorage->next; ++ ++ /* Free the current container. */ ++ gcmkERR_BREAK(gckOS_Free( ++ Command->os, Command->taskStorage ++ )); ++ ++ /* Advance to the next one. */ ++ Command->taskStorage = nextStorage; ++ } ++ ++ /* Error? */ ++ if (gcmkIS_ERROR(status)) ++ { ++ break; ++ } ++ ++ /* Mark the object as unknown. */ ++ Command->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckVGCOMMAND structure. */ ++ gcmkERR_BREAK(gckOS_Free(Command->os, Command)); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Restore the object type if failed. */ ++ Command->object.type = gcvOBJ_COMMAND; ++ ++ gcmkFOOTER(); ++ /* Return the error. */ ++ return status; ++} ++ ++gceSTATUS ++gckVGCOMMAND_QueryCommandBuffer( ++ IN gckVGCOMMAND Command, ++ OUT gcsCOMMAND_BUFFER_INFO_PTR Information ++ ) ++{ ++ gcmkHEADER_ARG("Command=0x%x Information=0x%x", Command, Information); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ gcmkVERIFY_ARGUMENT(Information != gcvNULL); ++ ++ /* Copy the information. */ ++ gcmkVERIFY_OK(gckOS_MemCopy( ++ Information, &Command->info, sizeof(gcsCOMMAND_BUFFER_INFO) ++ )); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckVGCOMMAND_Allocate( ++ IN gckVGCOMMAND Command, ++ IN gctSIZE_T Size, ++ OUT gcsCMDBUFFER_PTR * CommandBuffer, ++ OUT gctPOINTER * Data ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Command=0x%x Size=0x%x CommandBuffer=0x%x Data=0x%x", ++ Command, Size, CommandBuffer, Data); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ gcmkVERIFY_ARGUMENT(Data != gcvNULL); ++ ++ do ++ { ++ /* Allocate the buffer. */ ++ gcmkERR_BREAK(_AllocateCommandBuffer(Command, Size, CommandBuffer)); ++ ++ /* Determine the data pointer. */ ++ * Data = (gctUINT8_PTR) (*CommandBuffer) + (* CommandBuffer)->bufferOffset; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++gceSTATUS ++gckVGCOMMAND_Free( ++ IN gckVGCOMMAND Command, ++ IN gcsCMDBUFFER_PTR CommandBuffer ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x", ++ Command, CommandBuffer); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL); ++ ++ /* Free command buffer. */ ++ status = _FreeCommandBuffer(Command->kernel, CommandBuffer); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++gceSTATUS ++gckVGCOMMAND_Execute( ++ IN gckVGCOMMAND Command, ++ IN gcsCMDBUFFER_PTR CommandBuffer ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x", ++ Command, CommandBuffer); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL); ++ ++ do ++ { ++ gctUINT queueLength; ++ gcsKERNEL_CMDQUEUE_PTR kernelEntry; ++ ++ /* Lock the current queue. */ ++ gcmkERR_BREAK(_LockCurrentQueue( ++ Command, &kernelEntry, &queueLength ++ )); ++ ++ /* Set the buffer. */ ++ kernelEntry->commandBuffer = CommandBuffer; ++ kernelEntry->handler = _FreeKernelCommandBuffer; ++ ++ /* Lock the current queue. */ ++ gcmkERR_BREAK(_UnlockCurrentQueue( ++ Command, 1 ++ )); ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++gceSTATUS ++gckVGCOMMAND_Commit( ++ IN gckVGCOMMAND Command, ++ IN gcsVGCONTEXT_PTR Context, ++ IN gcsVGCMDQUEUE_PTR Queue, ++ IN gctUINT EntryCount, ++ IN gcsTASK_MASTER_TABLE_PTR TaskTable ++ ) ++{ ++ /* ++ The first buffer is executed through a direct gckVGHARDWARE_Execute call, ++ therefore only an update is needed after the execution is over. All ++ consequent buffers need to be executed upon the first update call from ++ the FE interrupt handler. ++ */ ++ ++ static gcsQUEUE_UPDATE_CONTROL _dynamicBuffer[] = ++ { ++ { ++ _UpdateDynamicCommandBuffer, ++ _UpdateDynamicCommandBuffer, ++ _UpdateLastDynamicCommandBuffer, ++ _UpdateLastDynamicCommandBuffer ++ }, ++ { ++ _ExecuteDynamicCommandBuffer, ++ _UpdateDynamicCommandBuffer, ++ _ExecuteLastDynamicCommandBuffer, ++ _UpdateLastDynamicCommandBuffer ++ } ++ }; ++ ++ static gcsQUEUE_UPDATE_CONTROL _staticBuffer[] = ++ { ++ { ++ _UpdateStaticCommandBuffer, ++ _UpdateStaticCommandBuffer, ++ _UpdateLastStaticCommandBuffer, ++ _UpdateLastStaticCommandBuffer ++ }, ++ { ++ _ExecuteStaticCommandBuffer, ++ _UpdateStaticCommandBuffer, ++ _ExecuteLastStaticCommandBuffer, ++ _UpdateLastStaticCommandBuffer ++ } ++ }; ++ ++ gceSTATUS status, last; ++ ++ gcmkHEADER_ARG("Command=0x%x Context=0x%x Queue=0x%x EntryCount=0x%x TaskTable=0x%x", ++ Command, Context, Queue, EntryCount, TaskTable); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); ++ gcmkVERIFY_ARGUMENT(Context != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Queue != gcvNULL); ++ gcmkVERIFY_ARGUMENT(EntryCount > 1); ++ ++ do ++ { ++ gctBOOL haveFETasks; ++ gctUINT queueSize; ++ gcsVGCMDQUEUE_PTR mappedQueue; ++ gcsVGCMDQUEUE_PTR userEntry; ++ gcsKERNEL_CMDQUEUE_PTR kernelEntry; ++ gcsQUEUE_UPDATE_CONTROL_PTR queueControl; ++ gctUINT currentLength; ++ gctUINT queueLength; ++ gctUINT entriesQueued; ++ gctUINT8_PTR previousEnd; ++ gctBOOL previousDynamic; ++ gctBOOL previousExecuted; ++ gctUINT controlIndex; ++ ++ gcmkERR_BREAK(gckVGHARDWARE_SetPowerManagementState( ++ Command->hardware, gcvPOWER_ON_AUTO ++ )); ++ ++ /* Acquire the power semaphore. */ ++ gcmkERR_BREAK(gckOS_AcquireSemaphore( ++ Command->os, Command->powerSemaphore ++ )); ++ ++ /* Acquire the mutex. */ ++ status = gckOS_AcquireMutex( ++ Command->os, ++ Command->commitMutex, ++ gcvINFINITE ++ ); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseSemaphore( ++ Command->os, Command->powerSemaphore)); ++ break; ++ } ++ ++ do ++ { ++ gcmkERR_BREAK(_FlushMMU(Command)); ++ ++ /* Assign a context ID if not yet assigned. */ ++ if (Context->id == 0) ++ { ++ /* Assign the next context number. */ ++ Context->id = ++ Command->contextCounter; ++ ++ /* See if we overflowed. */ ++ if (Command->contextCounter == 0) ++ { ++ /* We actually did overflow, wow... */ ++ status = gcvSTATUS_OUT_OF_RESOURCES; ++ break; ++ } ++ } ++ ++ /* The first entry in the queue is always the context buffer. ++ Verify whether the user context is the same as the current ++ context and if that's the case, skip the first entry. */ ++ if (Context->id == Command->currentContext) ++ { ++ /* Same context as before, skip the first entry. */ ++ EntryCount -= 1; ++ Queue += 1; ++ ++ /* Set the signal to avoid user waiting. */ ++ gcmkERR_BREAK(gckOS_UserSignal( ++ Command->os, Context->signal, Context->process ++ )); ++ } ++ else ++ { ++ /* Different user context - keep the first entry. ++ Set the user context as the current one. */ ++ Command->currentContext = Context->id; ++ } ++ ++ /* Reset pointers. */ ++ queueControl = gcvNULL; ++ previousEnd = gcvNULL; ++ ++ /* Determine whether there are FE tasks to be performed. */ ++ haveFETasks = (TaskTable->table[gcvBLOCK_COMMAND].head != gcvNULL); ++ ++ /* Determine the size of the queue. */ ++ queueSize = EntryCount * gcmSIZEOF(gcsVGCMDQUEUE); ++ ++ /* Map the command queue into the kernel space. */ ++ gcmkERR_BREAK(gckOS_MapUserPointer( ++ Command->os, ++ Queue, ++ queueSize, ++ (gctPOINTER *) &mappedQueue ++ )); ++ ++ /* Set the first entry. */ ++ userEntry = mappedQueue; ++ ++ /* Process the command queue. */ ++ while (EntryCount) ++ { ++ /* Lock the current queue. */ ++ gcmkERR_BREAK(_LockCurrentQueue( ++ Command, &kernelEntry, &queueLength ++ )); ++ ++ /* Determine the number of entries to process. */ ++ currentLength = (queueLength < EntryCount) ++ ? queueLength ++ : EntryCount; ++ ++ /* Update the number of the entries left to process. */ ++ EntryCount -= currentLength; ++ ++ /* Reset previous flags. */ ++ previousDynamic = gcvFALSE; ++ previousExecuted = gcvFALSE; ++ ++ /* Set the initial control index. */ ++ controlIndex = 0; ++ ++ /* Process entries. */ ++ for (entriesQueued = 0; entriesQueued < currentLength; entriesQueued += 1) ++ { ++ /* Get the kernel pointer to the command buffer header. */ ++ gcsCMDBUFFER_PTR commandBuffer = gcvNULL; ++ gcmkERR_BREAK(_ConvertUserCommandBufferPointer( ++ Command, ++ userEntry->commandBuffer, ++ &commandBuffer ++ )); ++ ++ /* Is it a dynamic command buffer? */ ++ if (userEntry->dynamic) ++ { ++ /* Select dynamic buffer control functions. */ ++ queueControl = &_dynamicBuffer[controlIndex]; ++ } ++ ++ /* No, a static command buffer. */ ++ else ++ { ++ /* Select static buffer control functions. */ ++ queueControl = &_staticBuffer[controlIndex]; ++ } ++ ++ /* Set the command buffer pointer to the entry. */ ++ kernelEntry->commandBuffer = commandBuffer; ++ ++ /* If the previous entry was a dynamic command buffer, ++ link it to the current. */ ++ if (previousDynamic) ++ { ++ gcmkERR_BREAK(gckVGCOMMAND_FetchCommand( ++ Command, ++ previousEnd, ++ commandBuffer->address, ++ commandBuffer->dataCount, ++ gcvNULL ++ )); ++ ++ /* The buffer will be auto-executed, only need to ++ update it after it has been executed. */ ++ kernelEntry->handler = queueControl->update; ++ ++ /* The buffer is only being updated. */ ++ previousExecuted = gcvFALSE; ++ } ++ else ++ { ++ /* Set the buffer up for execution. */ ++ kernelEntry->handler = queueControl->execute; ++ ++ /* The buffer is being updated. */ ++ previousExecuted = gcvTRUE; ++ } ++ ++ /* The current buffer's END command becomes the last END. */ ++ previousEnd ++ = ((gctUINT8_PTR) commandBuffer) ++ + commandBuffer->bufferOffset ++ + commandBuffer->dataCount * Command->info.commandAlignment ++ - Command->info.staticTailSize; ++ ++ /* Update the last entry info. */ ++ previousDynamic = userEntry->dynamic; ++ ++ /* Advance entries. */ ++ userEntry += 1; ++ kernelEntry += 1; ++ ++ /* Update the control index. */ ++ controlIndex = 1; ++ } ++ ++ /* If the previous entry was a dynamic command buffer, ++ terminate it with an END. */ ++ if (previousDynamic) ++ { ++ gcmkERR_BREAK(gckVGCOMMAND_EndCommand( ++ Command, ++ previousEnd, ++ Command->info.feBufferInt, ++ gcvNULL ++ )); ++ } ++ ++ /* Last buffer? */ ++ if (EntryCount == 0) ++ { ++ /* Modify the last command buffer's routines to handle ++ tasks if any.*/ ++ if (haveFETasks) ++ { ++ if (previousExecuted) ++ { ++ kernelEntry[-1].handler = queueControl->lastExecute; ++ } ++ else ++ { ++ kernelEntry[-1].handler = queueControl->lastUpdate; ++ } ++ } ++ ++ /* Release the mutex. */ ++ gcmkERR_BREAK(gckOS_ReleaseMutex( ++ Command->os, ++ Command->queueMutex ++ )); ++ /* Schedule tasks. */ ++ gcmkERR_BREAK(_ScheduleTasks(Command, TaskTable, previousEnd)); ++ ++ /* Acquire the mutex. */ ++ gcmkERR_BREAK(gckOS_AcquireMutex( ++ Command->os, ++ Command->queueMutex, ++ gcvINFINITE ++ )); ++ } ++ ++ /* Unkock and schedule the current queue for execution. */ ++ gcmkERR_BREAK(_UnlockCurrentQueue( ++ Command, currentLength ++ )); ++ } ++ ++ ++ /* Unmap the user command buffer. */ ++ gcmkERR_BREAK(gckOS_UnmapUserPointer( ++ Command->os, ++ Queue, ++ queueSize, ++ mappedQueue ++ )); ++ } ++ while (gcvFALSE); ++ ++ /* Release the mutex. */ ++ gcmkCHECK_STATUS(gckOS_ReleaseMutex( ++ Command->os, ++ Command->commitMutex ++ )); ++ ++ gcmkVERIFY_OK(gckOS_ReleaseSemaphore( ++ Command->os, Command->powerSemaphore)); ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++#endif /* gcdENABLE_VG */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_db.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_db.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_db.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_db.c 2016-06-19 22:11:55.137151030 +0200 +@@ -0,0 +1,1758 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_DATABASE ++ ++/******************************************************************************* ++***** Private fuctions ********************************************************/ ++ ++#define _GetSlot(database, x) \ ++ (gctUINT32)(gcmPTR_TO_UINT64(x) % gcmCOUNTOF(database->list)) ++ ++/******************************************************************************* ++** gckKERNEL_NewDatabase ++** ++** Create a new database structure and insert it to the head of the hash list. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** ProcessID that identifies the database. ++** ++** OUTPUT: ++** ++** gcsDATABASE_PTR * Database ++** Pointer to a variable receiving the database structure pointer on ++** success. ++*/ ++static gceSTATUS ++gckKERNEL_NewDatabase( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ OUT gcsDATABASE_PTR * Database ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gctBOOL acquired = gcvFALSE; ++ gctSIZE_T slot; ++ gcsDATABASE_PTR existingDatabase; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); ++ ++ /* Acquire the database mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Compute the hash for the database. */ ++ slot = ProcessID % gcmCOUNTOF(Kernel->db->db); ++ ++ /* Walk the hash list. */ ++ for (existingDatabase = Kernel->db->db[slot]; ++ existingDatabase != gcvNULL; ++ existingDatabase = existingDatabase->next) ++ { ++ if (existingDatabase->processID == ProcessID) ++ { ++ /* One process can't be added twice. */ ++ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); ++ } ++ } ++ ++ if (Kernel->db->freeDatabase != gcvNULL) ++ { ++ /* Allocate a database from the free list. */ ++ database = Kernel->db->freeDatabase; ++ Kernel->db->freeDatabase = database->next; ++ } ++ else ++ { ++ gctPOINTER pointer = gcvNULL; ++ ++ /* Allocate a new database from the heap. */ ++ gcmkONERROR(gckOS_Allocate(Kernel->os, ++ gcmSIZEOF(gcsDATABASE), ++ &pointer)); ++ ++ gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsDATABASE)); ++ ++ database = pointer; ++ ++ gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->counterMutex)); ++ } ++ ++ /* Insert the database into the hash. */ ++ database->next = Kernel->db->db[slot]; ++ Kernel->db->db[slot] = database; ++ ++ /* Save the hash slot. */ ++ database->slot = slot; ++ ++ /* Release the database mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Return the database. */ ++ *Database = database; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Database=0x%x", *Database); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_FindDatabase ++** ++** Find a database identified by a process ID and move it to the head of the ++** hash list. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** ProcessID that identifies the database. ++** ++** gctBOOL LastProcessID ++** gcvTRUE if searching for the last known process ID. gcvFALSE if ++** we need to search for the process ID specified by the ProcessID ++** argument. ++** ++** OUTPUT: ++** ++** gcsDATABASE_PTR * Database ++** Pointer to a variable receiving the database structure pointer on ++** success. ++*/ ++gceSTATUS ++gckKERNEL_FindDatabase( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctBOOL LastProcessID, ++ OUT gcsDATABASE_PTR * Database ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database, previous; ++ gctSIZE_T slot; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d", ++ Kernel, ProcessID, LastProcessID); ++ ++ /* Compute the hash for the database. */ ++ slot = ProcessID % gcmCOUNTOF(Kernel->db->db); ++ ++ /* Acquire the database mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Check whether we are getting the last known database. */ ++ if (LastProcessID) ++ { ++ /* Use last database. */ ++ database = Kernel->db->lastDatabase; ++ ++ if (database == gcvNULL) ++ { ++ /* Database not found. */ ++ gcmkONERROR(gcvSTATUS_INVALID_DATA); ++ } ++ } ++ else ++ { ++ /* Walk the hash list. */ ++ for (previous = gcvNULL, database = Kernel->db->db[slot]; ++ database != gcvNULL; ++ database = database->next) ++ { ++ if (database->processID == ProcessID) ++ { ++ /* Found it! */ ++ break; ++ } ++ ++ previous = database; ++ } ++ ++ if (database == gcvNULL) ++ { ++ /* Database not found. */ ++ gcmkONERROR(gcvSTATUS_INVALID_DATA); ++ } ++ ++ if (previous != gcvNULL) ++ { ++ /* Move database to the head of the hash list. */ ++ previous->next = database->next; ++ database->next = Kernel->db->db[slot]; ++ Kernel->db->db[slot] = database; ++ } ++ } ++ ++ /* Release the database mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Return the database. */ ++ *Database = database; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Database=0x%x", *Database); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_DeleteDatabase ++** ++** Remove a database from the hash list and delete its structure. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gcsDATABASE_PTR Database ++** Pointer to the database structure to remove. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++static gceSTATUS ++gckKERNEL_DeleteDatabase( ++ IN gckKERNEL Kernel, ++ IN gcsDATABASE_PTR Database ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gcsDATABASE_PTR database; ++ ++ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database); ++ ++ /* Acquire the database mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Check slot value. */ ++ gcmkVERIFY_ARGUMENT(Database->slot < gcmCOUNTOF(Kernel->db->db)); ++ ++ if (Database->slot < gcmCOUNTOF(Kernel->db->db)) ++ { ++ /* Check if database if the head of the hash list. */ ++ if (Kernel->db->db[Database->slot] == Database) ++ { ++ /* Remove the database from the hash list. */ ++ Kernel->db->db[Database->slot] = Database->next; ++ } ++ else ++ { ++ /* Walk the has list to find the database. */ ++ for (database = Kernel->db->db[Database->slot]; ++ database != gcvNULL; ++ database = database->next ++ ) ++ { ++ /* Check if the next list entry is this database. */ ++ if (database->next == Database) ++ { ++ /* Remove the database from the hash list. */ ++ database->next = Database->next; ++ break; ++ } ++ } ++ ++ if (database == gcvNULL) ++ { ++ /* Ouch! Something got corrupted. */ ++ gcmkONERROR(gcvSTATUS_INVALID_DATA); ++ } ++ } ++ } ++ ++ if (Kernel->db->lastDatabase != gcvNULL) ++ { ++ /* Insert database to the free list. */ ++ Kernel->db->lastDatabase->next = Kernel->db->freeDatabase; ++ Kernel->db->freeDatabase = Kernel->db->lastDatabase; ++ } ++ ++ /* Keep database as the last database. */ ++ Kernel->db->lastDatabase = Database; ++ ++ /* Destory handle db. */ ++ gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Database->handleDatabase)); ++ Database->handleDatabase = gcvNULL; ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Database->handleDatabaseMutex)); ++ Database->handleDatabaseMutex = gcvNULL; ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ /* Destory process MMU. */ ++ gcmkVERIFY_OK(gckEVENT_DestroyMmu(Kernel->eventObj, Database->mmu, gcvKERNEL_PIXEL)); ++ Database->mmu = gcvNULL; ++#endif ++ ++ /* Release the database mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_NewRecord ++** ++** Create a new database record structure and insert it to the head of the ++** database. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gcsDATABASE_PTR Database ++** Pointer to a database structure. ++** ++** OUTPUT: ++** ++** gcsDATABASE_RECORD_PTR * Record ++** Pointer to a variable receiving the database record structure ++** pointer on success. ++*/ ++static gceSTATUS ++gckKERNEL_NewRecord( ++ IN gckKERNEL Kernel, ++ IN gcsDATABASE_PTR Database, ++ IN gctUINT32 Slot, ++ OUT gcsDATABASE_RECORD_PTR * Record ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gcsDATABASE_RECORD_PTR record = gcvNULL; ++ ++ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database); ++ ++ /* Acquire the database mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ if (Kernel->db->freeRecord != gcvNULL) ++ { ++ /* Allocate the record from the free list. */ ++ record = Kernel->db->freeRecord; ++ Kernel->db->freeRecord = record->next; ++ } ++ else ++ { ++ gctPOINTER pointer = gcvNULL; ++ ++ /* Allocate the record from the heap. */ ++ gcmkONERROR(gckOS_Allocate(Kernel->os, ++ gcmSIZEOF(gcsDATABASE_RECORD), ++ &pointer)); ++ ++ record = pointer; ++ } ++ ++ /* Insert the record in the database. */ ++ record->next = Database->list[Slot]; ++ Database->list[Slot] = record; ++ ++ /* Release the database mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Return the record. */ ++ *Record = record; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Record=0x%x", *Record); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ } ++ if (record != gcvNULL) ++ { ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_DeleteRecord ++** ++** Remove a database record from the database and delete its structure. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gcsDATABASE_PTR Database ++** Pointer to a database structure. ++** ++** gceDATABASE_TYPE Type ++** Type of the record to remove. ++** ++** gctPOINTER Data ++** Data of the record to remove. ++** ++** OUTPUT: ++** ++** gctSIZE_T_PTR Bytes ++** Pointer to a variable that receives the size of the record deleted. ++** Can be gcvNULL if the size is not required. ++*/ ++static gceSTATUS ++gckKERNEL_DeleteRecord( ++ IN gckKERNEL Kernel, ++ IN gcsDATABASE_PTR Database, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Data, ++ OUT gctSIZE_T_PTR Bytes OPTIONAL ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gcsDATABASE_RECORD_PTR record, previous; ++ gctUINT32 slot = _GetSlot(Database, Data); ++ ++ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x", ++ Kernel, Database, Type, Data); ++ ++ /* Acquire the database mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Scan the database for this record. */ ++ for (record = Database->list[slot], previous = gcvNULL; ++ record != gcvNULL; ++ record = record->next ++ ) ++ { ++ if ((record->type == Type) ++ && (record->data == Data) ++ ) ++ { ++ /* Found it! */ ++ break; ++ } ++ ++ previous = record; ++ } ++ ++ if (record == gcvNULL) ++ { ++ /* Ouch! This record is not found? */ ++ gcmkONERROR(gcvSTATUS_INVALID_DATA); ++ } ++ ++ if (Bytes != gcvNULL) ++ { ++ /* Return size of record. */ ++ *Bytes = record->bytes; ++ } ++ ++ /* Remove record from database. */ ++ if (previous == gcvNULL) ++ { ++ Database->list[slot] = record->next; ++ } ++ else ++ { ++ previous->next = record->next; ++ } ++ ++ /* Insert record in free list. */ ++ record->next = Kernel->db->freeRecord; ++ Kernel->db->freeRecord = record; ++ ++ /* Release the database mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_FindRecord ++** ++** Find a database record from the database. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gcsDATABASE_PTR Database ++** Pointer to a database structure. ++** ++** gceDATABASE_TYPE Type ++** Type of the record to remove. ++** ++** gctPOINTER Data ++** Data of the record to remove. ++** ++** OUTPUT: ++** ++** gctSIZE_T_PTR Bytes ++** Pointer to a variable that receives the size of the record deleted. ++** Can be gcvNULL if the size is not required. ++*/ ++static gceSTATUS ++gckKERNEL_FindRecord( ++ IN gckKERNEL Kernel, ++ IN gcsDATABASE_PTR Database, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Data, ++ OUT gcsDATABASE_RECORD_PTR Record ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gcsDATABASE_RECORD_PTR record; ++ gctUINT32 slot = _GetSlot(Database, Data); ++ ++ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x", ++ Kernel, Database, Type, Data); ++ ++ /* Acquire the database mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Scan the database for this record. */ ++ for (record = Database->list[slot]; ++ record != gcvNULL; ++ record = record->next ++ ) ++ { ++ if ((record->type == Type) ++ && (record->data == Data) ++ ) ++ { ++ /* Found it! */ ++ break; ++ } ++ } ++ ++ if (record == gcvNULL) ++ { ++ /* Ouch! This record is not found? */ ++ gcmkONERROR(gcvSTATUS_INVALID_DATA); ++ } ++ ++ if (Record != gcvNULL) ++ { ++ /* Return information of record. */ ++ gcmkONERROR( ++ gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD))); ++ } ++ ++ /* Release the database mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("Record=0x%x", Record); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++***** Public API **************************************************************/ ++ ++/******************************************************************************* ++** gckKERNEL_CreateProcessDB ++** ++** Create a new process database. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** Process ID used to identify the database. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_CreateProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database = gcvNULL; ++ gctUINT32 i; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Create a new database. */ ++ gcmkONERROR(gckKERNEL_NewDatabase(Kernel, ProcessID, &database)); ++ ++ /* Initialize the database. */ ++ database->processID = ProcessID; ++ database->vidMem.bytes = 0; ++ database->vidMem.maxBytes = 0; ++ database->vidMem.totalBytes = 0; ++ database->nonPaged.bytes = 0; ++ database->nonPaged.maxBytes = 0; ++ database->nonPaged.totalBytes = 0; ++ database->contiguous.bytes = 0; ++ database->contiguous.maxBytes = 0; ++ database->contiguous.totalBytes = 0; ++ database->mapMemory.bytes = 0; ++ database->mapMemory.maxBytes = 0; ++ database->mapMemory.totalBytes = 0; ++ database->mapUserMemory.bytes = 0; ++ database->mapUserMemory.maxBytes = 0; ++ database->mapUserMemory.totalBytes = 0; ++ database->virtualCommandBuffer.bytes = 0; ++ database->virtualCommandBuffer.maxBytes = 0; ++ database->virtualCommandBuffer.totalBytes = 0; ++ ++ for (i = 0; i < gcmCOUNTOF(database->list); i++) ++ { ++ database->list[i] = gcvNULL; ++ } ++ ++ for (i = 0; i < gcvSURF_NUM_TYPES; i++) ++ { ++ database->vidMemType[i].bytes = 0; ++ database->vidMemType[i].maxBytes = 0; ++ database->vidMemType[i].totalBytes = 0; ++ } ++ ++ for (i = 0; i < gcvPOOL_NUMBER_OF_POOLS; i++) ++ { ++ database->vidMemPool[i].bytes = 0; ++ database->vidMemPool[i].maxBytes = 0; ++ database->vidMemPool[i].totalBytes = 0; ++ } ++ ++ gcmkASSERT(database->handleDatabase == gcvNULL); ++ gcmkONERROR( ++ gckKERNEL_CreateIntegerDatabase(Kernel, &database->handleDatabase)); ++ ++ gcmkASSERT(database->handleDatabaseMutex == gcvNULL); ++ gcmkONERROR( ++ gckOS_CreateMutex(Kernel->os, &database->handleDatabaseMutex)); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkASSERT(database->mmu == gcvNULL); ++ gcmkONERROR( ++ gckMMU_Construct(Kernel, gcdMMU_SIZE, &database->mmu)); ++#endif ++ ++ /* Reset idle timer. */ ++ Kernel->db->lastIdle = 0; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_AddProcessDB ++** ++** Add a record to a process database. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** Process ID used to identify the database. ++** ++** gceDATABASE_TYPE TYPE ++** Type of the record to add. ++** ++** gctPOINTER Pointer ++** Data of the record to add. ++** ++** gctPHYS_ADDR Physical ++** Physical address of the record to add. ++** ++** gctSIZE_T Size ++** Size of the record to add. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_AddProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Pointer, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Size ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gcsDATABASE_RECORD_PTR record = gcvNULL; ++ gcsDATABASE_COUNTERS * count; ++ gctUINT32 vidMemType; ++ gcePOOL vidMemPool; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x " ++ "Physical=0x%x Size=%lu", ++ Kernel, ProcessID, Type, Pointer, Physical, Size); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Decode type. */ ++ vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT; ++ vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT; ++ ++ Type &= gcdDATABASE_TYPE_MASK; ++ ++ /* Special case the idle record. */ ++ if (Type == gcvDB_IDLE) ++ { ++ gctUINT64 time; ++ ++ /* Get the current profile time. */ ++ gcmkONERROR(gckOS_GetProfileTick(&time)); ++ ++ if ((ProcessID == 0) && (Kernel->db->lastIdle != 0)) ++ { ++ /* Out of idle, adjust time it was idle. */ ++ Kernel->db->idleTime += time - Kernel->db->lastIdle; ++ Kernel->db->lastIdle = 0; ++ } ++ else if (ProcessID == 1) ++ { ++ /* Save current idle time. */ ++ Kernel->db->lastIdle = time; ++ } ++ ++#if gcdDYNAMIC_SPEED ++ { ++ /* Test for first call. */ ++ if (Kernel->db->lastSlowdown == 0) ++ { ++ /* Save milliseconds. */ ++ Kernel->db->lastSlowdown = time; ++ Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; ++ } ++ else ++ { ++ /* Compute ellapsed time in milliseconds. */ ++ gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown); ++ ++ /* Test for end of period. */ ++ if (delta >= gcdDYNAMIC_SPEED) ++ { ++ /* Compute number of idle milliseconds. */ ++ gctUINT idle = gckOS_ProfileToMS( ++ Kernel->db->idleTime - Kernel->db->lastSlowdownIdle); ++ ++ /* Broadcast to slow down the GPU. */ ++ gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os, ++ Kernel->hardware, ++ idle, ++ delta)); ++ ++ /* Save current time. */ ++ Kernel->db->lastSlowdown = time; ++ Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; ++ } ++ } ++ } ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ ++ /* Find the database. */ ++ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); ++ ++ /* Create a new record in the database. */ ++ gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record)); ++ ++ /* Initialize the record. */ ++ record->kernel = Kernel; ++ record->type = Type; ++ record->data = Pointer; ++ record->physical = Physical; ++ record->bytes = Size; ++ ++ /* Get pointer to counters. */ ++ switch (Type) ++ { ++ case gcvDB_VIDEO_MEMORY: ++ count = &database->vidMem; ++ break; ++ ++ case gcvDB_NON_PAGED: ++ count = &database->nonPaged; ++ break; ++ ++ case gcvDB_CONTIGUOUS: ++ count = &database->contiguous; ++ break; ++ ++ case gcvDB_MAP_MEMORY: ++ count = &database->mapMemory; ++ break; ++ ++ case gcvDB_MAP_USER_MEMORY: ++ count = &database->mapUserMemory; ++ break; ++ ++ case gcvDB_COMMAND_BUFFER: ++ count = &database->virtualCommandBuffer; ++ break; ++ ++ default: ++ count = gcvNULL; ++ break; ++ } ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE)); ++ ++ if (count != gcvNULL) ++ { ++ /* Adjust counters. */ ++ count->totalBytes += Size; ++ count->bytes += Size; ++ ++ if (count->bytes > count->maxBytes) ++ { ++ count->maxBytes = count->bytes; ++ } ++ } ++ ++ if (Type == gcvDB_VIDEO_MEMORY) ++ { ++ count = &database->vidMemType[vidMemType]; ++ ++ /* Adjust counters. */ ++ count->totalBytes += Size; ++ count->bytes += Size; ++ ++ if (count->bytes > count->maxBytes) ++ { ++ count->maxBytes = count->bytes; ++ } ++ ++ count = &database->vidMemPool[vidMemPool]; ++ ++ /* Adjust counters. */ ++ count->totalBytes += Size; ++ count->bytes += Size; ++ ++ if (count->bytes > count->maxBytes) ++ { ++ count->maxBytes = count->bytes; ++ } ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_RemoveProcessDB ++** ++** Remove a record from a process database. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** Process ID used to identify the database. ++** ++** gceDATABASE_TYPE TYPE ++** Type of the record to remove. ++** ++** gctPOINTER Pointer ++** Data of the record to remove. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_RemoveProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Pointer ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gctSIZE_T bytes = 0; ++ gctUINT32 vidMemType; ++ gcePOOL vidMempool; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x", ++ Kernel, ProcessID, Type, Pointer); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ ++ /* Decode type. */ ++ vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT; ++ vidMempool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT; ++ ++ Type &= gcdDATABASE_TYPE_MASK; ++ ++ /* Find the database. */ ++ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); ++ ++ /* Delete the record. */ ++ gcmkONERROR( ++ gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes)); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE)); ++ ++ /* Update counters. */ ++ switch (Type) ++ { ++ case gcvDB_VIDEO_MEMORY: ++ database->vidMem.bytes -= bytes; ++ database->vidMemType[vidMemType].bytes -= bytes; ++ database->vidMemPool[vidMempool].bytes -= bytes; ++ break; ++ ++ case gcvDB_NON_PAGED: ++ database->nonPaged.bytes -= bytes; ++ break; ++ ++ case gcvDB_CONTIGUOUS: ++ database->contiguous.bytes -= bytes; ++ break; ++ ++ case gcvDB_MAP_MEMORY: ++ database->mapMemory.bytes -= bytes; ++ break; ++ ++ case gcvDB_MAP_USER_MEMORY: ++ database->mapUserMemory.bytes -= bytes; ++ break; ++ ++ case gcvDB_COMMAND_BUFFER: ++ database->virtualCommandBuffer.bytes -= bytes; ++ break; ++ ++ default: ++ break; ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_FindProcessDB ++** ++** Find a record from a process database. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** Process ID used to identify the database. ++** ++** gceDATABASE_TYPE TYPE ++** Type of the record to remove. ++** ++** gctPOINTER Pointer ++** Data of the record to remove. ++** ++** OUTPUT: ++** ++** gcsDATABASE_RECORD_PTR Record ++** Copy of record. ++*/ ++gceSTATUS ++gckKERNEL_FindProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 ThreadID, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Pointer, ++ OUT gcsDATABASE_RECORD_PTR Record ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x", ++ Kernel, ProcessID, ThreadID, Type, Pointer); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ ++ /* Find the database. */ ++ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); ++ ++ /* Find the record. */ ++ gcmkONERROR( ++ gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_DestroyProcessDB ++** ++** Destroy a process database. If the database contains any records, the data ++** inside those records will be deleted as well. This aids in the cleanup if ++** a process has died unexpectedly or has memory leaks. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** Process ID used to identify the database. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_DestroyProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gcsDATABASE_RECORD_PTR record, next; ++ gctBOOL asynchronous = gcvTRUE; ++ gckVIDMEM_NODE nodeObject; ++ gctPHYS_ADDR physical; ++ gckKERNEL kernel = Kernel; ++ gctUINT32 handle; ++ gctUINT32 i; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Find the database. */ ++ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, ++ "DB(%d): VidMem: total=%lu max=%lu", ++ ProcessID, database->vidMem.totalBytes, ++ database->vidMem.maxBytes); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, ++ "DB(%d): NonPaged: total=%lu max=%lu", ++ ProcessID, database->nonPaged.totalBytes, ++ database->nonPaged.maxBytes); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, ++ "DB(%d): Contiguous: total=%lu max=%lu", ++ ProcessID, database->contiguous.totalBytes, ++ database->contiguous.maxBytes); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, ++ "DB(%d): Idle time=%llu", ++ ProcessID, Kernel->db->idleTime); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, ++ "DB(%d): Map: total=%lu max=%lu", ++ ProcessID, database->mapMemory.totalBytes, ++ database->mapMemory.maxBytes); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, ++ "DB(%d): Map: total=%lu max=%lu", ++ ProcessID, database->mapUserMemory.totalBytes, ++ database->mapUserMemory.maxBytes); ++ ++ if (database->list != gcvNULL) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "Process %d has entries in its database:", ++ ProcessID); ++ } ++ ++ for(i = 0; i < gcmCOUNTOF(database->list); i++) ++ { ++ ++ /* Walk all records. */ ++ for (record = database->list[i]; record != gcvNULL; record = next) ++ { ++ /* Next next record. */ ++ next = record->next; ++ ++ /* Dispatch on record type. */ ++ switch (record->type) ++ { ++ case gcvDB_VIDEO_MEMORY: ++ gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel, ++ ProcessID, ++ gcmPTR2INT32(record->data), ++ &nodeObject)); ++ ++ /* Free the video memory. */ ++ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel, ++ ProcessID, ++ gcmPTR2INT32(record->data))); ++ ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel, ++ nodeObject)); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: VIDEO_MEMORY 0x%x (status=%d)", ++ record->data, status); ++ break; ++ ++ case gcvDB_NON_PAGED: ++ physical = gcmNAME_TO_PTR(record->physical); ++ /* Unmap user logical memory first. */ ++ status = gckOS_UnmapUserLogical(Kernel->os, ++ physical, ++ record->bytes, ++ record->data); ++ ++ /* Free the non paged memory. */ ++ status = gckEVENT_FreeNonPagedMemory(Kernel->eventObj, ++ record->bytes, ++ physical, ++ record->data, ++ gcvKERNEL_PIXEL); ++ gcmRELEASE_NAME(record->physical); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)", ++ record->data, record->bytes, status); ++ break; ++ ++ case gcvDB_COMMAND_BUFFER: ++ /* Free the command buffer. */ ++ status = gckEVENT_DestroyVirtualCommandBuffer(record->kernel->eventObj, ++ record->bytes, ++ gcmNAME_TO_PTR(record->physical), ++ record->data, ++ gcvKERNEL_PIXEL); ++ gcmRELEASE_NAME(record->physical); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: COMMAND_BUFFER 0x%x, bytes=%lu (status=%d)", ++ record->data, record->bytes, status); ++ break; ++ ++ case gcvDB_CONTIGUOUS: ++ physical = gcmNAME_TO_PTR(record->physical); ++ /* Unmap user logical memory first. */ ++ status = gckOS_UnmapUserLogical(Kernel->os, ++ physical, ++ record->bytes, ++ record->data); ++ ++ /* Free the contiguous memory. */ ++ status = gckEVENT_FreeContiguousMemory(Kernel->eventObj, ++ record->bytes, ++ physical, ++ record->data, ++ gcvKERNEL_PIXEL); ++ gcmRELEASE_NAME(record->physical); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: CONTIGUOUS 0x%x bytes=%lu (status=%d)", ++ record->data, record->bytes, status); ++ break; ++ ++ case gcvDB_SIGNAL: ++ /* Free the user signal. */ ++ status = gckOS_DestroyUserSignal(Kernel->os, ++ gcmPTR2INT32(record->data)); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: SIGNAL %d (status=%d)", ++ (gctINT)(gctUINTPTR_T)record->data, status); ++ break; ++ ++ case gcvDB_VIDEO_MEMORY_LOCKED: ++ handle = gcmPTR2INT32(record->data); ++ ++ gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel, ++ ProcessID, ++ handle, ++ &nodeObject)); ++ ++ /* Unlock what we still locked */ ++ status = gckVIDMEM_Unlock(record->kernel, ++ nodeObject, ++ nodeObject->type, ++ &asynchronous); ++ ++#if gcdENABLE_VG ++ if (record->kernel->core == gcvCORE_VG) ++ { ++ if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous)) ++ { ++ /* TODO: we maybe need to schedule a event here */ ++ status = gckVIDMEM_Unlock(record->kernel, ++ nodeObject, ++ nodeObject->type, ++ gcvNULL); ++ } ++ ++ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel, ++ ProcessID, ++ handle)); ++ ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel, ++ nodeObject)); ++ } ++ else ++#endif ++ { ++ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel, ++ ProcessID, ++ handle)); ++ ++ if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous)) ++ { ++ status = gckEVENT_Unlock(record->kernel->eventObj, ++ gcvKERNEL_PIXEL, ++ nodeObject, ++ nodeObject->type); ++ } ++ else ++ { ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel, ++ nodeObject)); ++ } ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)", ++ record->data, status); ++ break; ++ ++ case gcvDB_CONTEXT: ++ /* TODO: Free the context */ ++ status = gckCOMMAND_Detach(Kernel->command, gcmNAME_TO_PTR(record->data)); ++ gcmRELEASE_NAME(record->data); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: CONTEXT 0x%x (status=%d)", ++ record->data, status); ++ break; ++ ++ case gcvDB_MAP_MEMORY: ++ /* Unmap memory. */ ++ status = gckKERNEL_UnmapMemory(Kernel, ++ record->physical, ++ record->bytes, ++ record->data); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: MAP MEMORY %d (status=%d)", ++ gcmPTR2INT32(record->data), status); ++ break; ++ ++ case gcvDB_MAP_USER_MEMORY: ++ /* TODO: Unmap user memory. */ ++ status = gckOS_UnmapUserMemory(Kernel->os, ++ Kernel->core, ++ record->physical, ++ record->bytes, ++ gcmNAME_TO_PTR(record->data), ++ 0); ++ gcmRELEASE_NAME(record->data); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: MAP USER MEMORY %d (status=%d)", ++ gcmPTR2INT32(record->data), status); ++ break; ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ case gcvDB_SYNC_POINT: ++ /* Free the user signal. */ ++ status = gckOS_DestroySyncPoint(Kernel->os, ++ (gctSYNC_POINT) record->data); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: SYNC POINT %d (status=%d)", ++ (gctINT)(gctUINTPTR_T)record->data, status); ++ break; ++#endif ++ ++ case gcvDB_SHBUF: ++ /* Free shared buffer. */ ++ status = gckKERNEL_DestroyShBuffer(Kernel, ++ (gctSHBUF) record->data); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, ++ "DB: SHBUF %u (status=%d)", ++ (gctUINT32)(gctUINTPTR_T) record->data, status); ++ break; ++ ++ default: ++ gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE, ++ "DB: Correcupted record=0x%08x type=%d", ++ record, record->type); ++ break; ++ } ++ ++ /* Delete the record. */ ++ gcmkONERROR(gckKERNEL_DeleteRecord(Kernel, ++ database, ++ record->type, ++ record->data, ++ gcvNULL)); ++ } ++ ++ } ++ ++ /* Delete the database. */ ++ gcmkONERROR(gckKERNEL_DeleteDatabase(Kernel, database)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckKERNEL_QueryProcessDB ++** ++** Query a process database for the current usage of a particular record type. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to a gckKERNEL object. ++** ++** gctUINT32 ProcessID ++** Process ID used to identify the database. ++** ++** gctBOOL LastProcessID ++** gcvTRUE if searching for the last known process ID. gcvFALSE if ++** we need to search for the process ID specified by the ProcessID ++** argument. ++** ++** gceDATABASE_TYPE Type ++** Type of the record to query. ++** ++** OUTPUT: ++** ++** gcuDATABASE_INFO * Info ++** Pointer to a variable that receives the requested information. ++*/ ++gceSTATUS ++gckKERNEL_QueryProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctBOOL LastProcessID, ++ IN gceDATABASE_TYPE Type, ++ OUT gcuDATABASE_INFO * Info ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gcePOOL vidMemPool; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x", ++ Kernel, ProcessID, Type, Info); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Info != gcvNULL); ++ ++ /* Deocde pool. */ ++ vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT; ++ ++ Type &= gcdDATABASE_TYPE_MASK; ++ ++ /* Find the database. */ ++ if(Type != gcvDB_IDLE) ++ { ++ gcmkONERROR( ++ gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database)); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE)); ++ ++ /* Get pointer to counters. */ ++ switch (Type) ++ { ++ case gcvDB_VIDEO_MEMORY: ++ if (vidMemPool != gcvPOOL_UNKNOWN) ++ { ++ gckOS_MemCopy(&Info->counters, ++ &database->vidMemPool[vidMemPool], ++ gcmSIZEOF(database->vidMemPool[vidMemPool])); ++ } ++ else ++ { ++ gckOS_MemCopy(&Info->counters, ++ &database->vidMem, ++ gcmSIZEOF(database->vidMem)); ++ } ++ break; ++ ++ case gcvDB_NON_PAGED: ++ gckOS_MemCopy(&Info->counters, ++ &database->nonPaged, ++ gcmSIZEOF(database->vidMem)); ++ break; ++ ++ case gcvDB_CONTIGUOUS: ++ gckOS_MemCopy(&Info->counters, ++ &database->contiguous, ++ gcmSIZEOF(database->vidMem)); ++ break; ++ ++ case gcvDB_MAP_MEMORY: ++ gckOS_MemCopy(&Info->counters, ++ &database->mapMemory, ++ gcmSIZEOF(database->mapMemory)); ++ break; ++ ++ case gcvDB_MAP_USER_MEMORY: ++ gckOS_MemCopy(&Info->counters, ++ &database->mapUserMemory, ++ gcmSIZEOF(database->mapUserMemory)); ++ break; ++ ++ case gcvDB_COMMAND_BUFFER: ++ gckOS_MemCopy(&Info->counters, ++ &database->virtualCommandBuffer, ++ gcmSIZEOF(database->virtualCommandBuffer)); ++ break; ++ ++ default: ++ break; ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex)); ++ } ++ else ++ { ++ Info->time = Kernel->db->idleTime; ++ Kernel->db->idleTime = 0; ++ } ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_FindHandleDatbase( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ OUT gctPOINTER * HandleDatabase, ++ OUT gctPOINTER * HandleDatabaseMutex ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", ++ Kernel, ProcessID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Find the database. */ ++ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); ++ ++ *HandleDatabase = database->handleDatabase; ++ *HandleDatabaseMutex = database->handleDatabaseMutex; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gceSTATUS ++gckKERNEL_GetProcessMMU( ++ IN gckKERNEL Kernel, ++ OUT gckMMU * Mmu ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gctUINT32 processID; ++ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, processID, gcvFALSE, &database)); ++ ++ *Mmu = database->mmu; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++#endif ++ ++gceSTATUS ++gckKERNEL_DumpProcessDB( ++ IN gckKERNEL Kernel ++ ) ++{ ++ gcsDATABASE_PTR database; ++ gctINT i, pid; ++ gctUINT8 name[24]; ++ ++ gcmkHEADER_ARG("Kernel=0x%x", Kernel); ++ ++ /* Acquire the database mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ ++ gcmkPRINT("**************************\n"); ++ gcmkPRINT("*** PROCESS DB DUMP ***\n"); ++ gcmkPRINT("**************************\n"); ++ ++ gcmkPRINT_N(8, "%-8s%s\n", "PID", "NAME"); ++ /* Walk the databases. */ ++ for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i) ++ { ++ for (database = Kernel->db->db[i]; ++ database != gcvNULL; ++ database = database->next) ++ { ++ pid = database->processID; ++ ++ gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name))); ++ ++ gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name)); ++ ++ gcmkPRINT_N(8, "%-8d%s\n", pid, name); ++ } ++ } ++ ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++void ++_DumpCounter( ++ IN gcsDATABASE_COUNTERS * Counter, ++ IN gctCONST_STRING Name ++ ) ++{ ++ gcmkPRINT("%s:", Name); ++ gcmkPRINT(" Currently allocated : %10lld", Counter->bytes); ++ gcmkPRINT(" Maximum allocated : %10lld", Counter->maxBytes); ++ gcmkPRINT(" Total allocated : %10lld", Counter->totalBytes); ++} ++ ++gceSTATUS ++gckKERNEL_DumpVidMemUsage( ++ IN gckKERNEL Kernel, ++ IN gctINT32 ProcessID ++ ) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gcsDATABASE_COUNTERS * counter; ++ gctUINT32 i = 0; ++ ++ static gctCONST_STRING surfaceTypes[] = { ++ "UNKNOWN", ++ "INDEX", ++ "VERTEX", ++ "TEXTURE", ++ "RENDER_TARGET", ++ "DEPTH", ++ "BITMAP", ++ "TILE_STATUS", ++ "IMAGE", ++ "MASK", ++ "SCISSOR", ++ "HIERARCHICAL_DEPTH", ++ }; ++ ++ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", ++ Kernel, ProcessID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Find the database. */ ++ gcmkONERROR( ++ gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); ++ ++ gcmkPRINT("VidMem Usage (Process %d):", ProcessID); ++ ++ /* Get pointer to counters. */ ++ counter = &database->vidMem; ++ ++ _DumpCounter(counter, "Total Video Memory"); ++ ++ for (i = 0; i < gcvSURF_NUM_TYPES; i++) ++ { ++ counter = &database->vidMemType[i]; ++ ++ _DumpCounter(counter, surfaceTypes[i]); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debug.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debug.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debug.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debug.c 2016-06-19 22:11:55.137151030 +0200 +@@ -0,0 +1,2766 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++#include ++ ++/******************************************************************************\ ++******************************** Debug Variables ******************************* ++\******************************************************************************/ ++ ++static gceSTATUS _lastError = gcvSTATUS_OK; ++static gctUINT32 _debugLevel = gcvLEVEL_ERROR; ++/* ++_debugZones config value ++Please Reference define in gc_hal_base.h ++*/ ++static gctUINT32 _debugZones = gcvZONE_ALL; ++ ++/******************************************************************************\ ++********************************* Debug Switches ******************************* ++\******************************************************************************/ ++ ++/* ++ gcdBUFFERED_OUTPUT ++ ++ When set to non-zero, all output is collected into a buffer with the ++ specified size. Once the buffer gets full, the debug buffer will be ++ printed to the console. gcdBUFFERED_SIZE determines the size of the buffer. ++*/ ++#define gcdBUFFERED_OUTPUT 0 ++ ++/* ++ gcdBUFFERED_SIZE ++ ++ When set to non-zero, all output is collected into a buffer with the ++ specified size. Once the buffer gets full, the debug buffer will be ++ printed to the console. ++*/ ++#define gcdBUFFERED_SIZE (1024 * 1024 * 2) ++ ++/* ++ gcdDMA_BUFFER_COUNT ++ ++ If greater then zero, the debugger will attempt to find the command buffer ++ where DMA is currently executing and then print this buffer and ++ (gcdDMA_BUFFER_COUNT - 1) buffers before the current one. If set to zero ++ or the current buffer is not found, all buffers are printed. ++*/ ++#define gcdDMA_BUFFER_COUNT 0 ++ ++/* ++ gcdTHREAD_BUFFERS ++ ++ When greater then one, will accumulate messages from the specified number ++ of threads in separate output buffers. ++*/ ++#define gcdTHREAD_BUFFERS 1 ++ ++/* ++ gcdENABLE_OVERFLOW ++ ++ When set to non-zero, and the output buffer gets full, instead of being ++ printed, it will be allowed to overflow removing the oldest messages. ++*/ ++#define gcdENABLE_OVERFLOW 1 ++ ++/* ++ gcdSHOW_LINE_NUMBER ++ ++ When enabledm each print statement will be preceeded with the current ++ line number. ++*/ ++#define gcdSHOW_LINE_NUMBER 0 ++ ++/* ++ gcdSHOW_PROCESS_ID ++ ++ When enabledm each print statement will be preceeded with the current ++ process ID. ++*/ ++#define gcdSHOW_PROCESS_ID 0 ++ ++/* ++ gcdSHOW_THREAD_ID ++ ++ When enabledm each print statement will be preceeded with the current ++ thread ID. ++*/ ++#define gcdSHOW_THREAD_ID 0 ++ ++/* ++ gcdSHOW_TIME ++ ++ When enabled each print statement will be preceeded with the current ++ high-resolution time. ++*/ ++#define gcdSHOW_TIME 0 ++ ++ ++/******************************************************************************\ ++****************************** Miscellaneous Macros **************************** ++\******************************************************************************/ ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++# define gcmDBGASSERT(Expression, Format, Value) \ ++ if (!(Expression)) \ ++ { \ ++ _DirectPrint( \ ++ "*** gcmDBGASSERT ***************************\n" \ ++ " function : %s\n" \ ++ " line : %d\n" \ ++ " expression : " #Expression "\n" \ ++ " actual value : " Format "\n", \ ++ __FUNCTION__, __LINE__, Value \ ++ ); \ ++ } ++#else ++# define gcmDBGASSERT(Expression, Format, Value) ++#endif ++ ++#define gcmPTRALIGNMENT(Pointer, Alignemnt) \ ++( \ ++ gcmALIGN(gcmPTR2INT32(Pointer), Alignemnt) - gcmPTR2INT32(Pointer) \ ++) ++ ++#if gcdALIGNBYSIZE ++# define gcmISALIGNED(Offset, Alignment) \ ++ (((Offset) & ((Alignment) - 1)) == 0) ++ ++# define gcmkALIGNPTR(Type, Pointer, Alignment) \ ++ Pointer = (Type) gcmINT2PTR(gcmALIGN(gcmPTR2INT32(Pointer), Alignment)) ++#else ++# define gcmISALIGNED(Offset, Alignment) \ ++ gcvTRUE ++ ++# define gcmkALIGNPTR(Type, Pointer, Alignment) ++#endif ++ ++#define gcmALIGNSIZE(Offset, Size) \ ++ ((Size - Offset) + Size) ++ ++#define gcdHAVEPREFIX \ ++( \ ++ gcdSHOW_TIME \ ++ || gcdSHOW_LINE_NUMBER \ ++ || gcdSHOW_PROCESS_ID \ ++ || gcdSHOW_THREAD_ID \ ++) ++ ++#if gcdHAVEPREFIX ++ ++# define gcdOFFSET 0 ++ ++#if gcdSHOW_TIME ++#if gcmISALIGNED(gcdOFFSET, 8) ++# define gcdTIMESIZE gcmSIZEOF(gctUINT64) ++# elif gcdOFFSET == 4 ++# define gcdTIMESIZE gcmALIGNSIZE(4, gcmSIZEOF(gctUINT64)) ++# else ++# error "Unexpected offset value." ++# endif ++# undef gcdOFFSET ++# define gcdOFFSET 8 ++#if !defined(gcdPREFIX_LEADER) ++# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT64) ++# define gcdTIMEFORMAT "0x%016llX" ++# else ++# define gcdTIMEFORMAT ", 0x%016llX" ++# endif ++# else ++# define gcdTIMESIZE 0 ++# define gcdTIMEFORMAT ++# endif ++ ++#if gcdSHOW_LINE_NUMBER ++#if gcmISALIGNED(gcdOFFSET, 8) ++# define gcdNUMSIZE gcmSIZEOF(gctUINT64) ++# elif gcdOFFSET == 4 ++# define gcdNUMSIZE gcmALIGNSIZE(4, gcmSIZEOF(gctUINT64)) ++# else ++# error "Unexpected offset value." ++# endif ++# undef gcdOFFSET ++# define gcdOFFSET 8 ++#if !defined(gcdPREFIX_LEADER) ++# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT64) ++# define gcdNUMFORMAT "%8llu" ++# else ++# define gcdNUMFORMAT ", %8llu" ++# endif ++# else ++# define gcdNUMSIZE 0 ++# define gcdNUMFORMAT ++# endif ++ ++#if gcdSHOW_PROCESS_ID ++#if gcmISALIGNED(gcdOFFSET, 4) ++# define gcdPIDSIZE gcmSIZEOF(gctUINT32) ++# else ++# error "Unexpected offset value." ++# endif ++# undef gcdOFFSET ++# define gcdOFFSET 4 ++#if !defined(gcdPREFIX_LEADER) ++# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32) ++# define gcdPIDFORMAT "pid=%5d" ++# else ++# define gcdPIDFORMAT ", pid=%5d" ++# endif ++# else ++# define gcdPIDSIZE 0 ++# define gcdPIDFORMAT ++# endif ++ ++#if gcdSHOW_THREAD_ID ++#if gcmISALIGNED(gcdOFFSET, 4) ++# define gcdTIDSIZE gcmSIZEOF(gctUINT32) ++# else ++# error "Unexpected offset value." ++# endif ++# undef gcdOFFSET ++# define gcdOFFSET 4 ++#if !defined(gcdPREFIX_LEADER) ++# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32) ++# define gcdTIDFORMAT "tid=%5d" ++# else ++# define gcdTIDFORMAT ", tid=%5d" ++# endif ++# else ++# define gcdTIDSIZE 0 ++# define gcdTIDFORMAT ++# endif ++ ++# define gcdPREFIX_SIZE \ ++ ( \ ++ gcdTIMESIZE \ ++ + gcdNUMSIZE \ ++ + gcdPIDSIZE \ ++ + gcdTIDSIZE \ ++ ) ++ ++ static const char * _prefixFormat = ++ "[" ++ gcdTIMEFORMAT ++ gcdNUMFORMAT ++ gcdPIDFORMAT ++ gcdTIDFORMAT ++ "] "; ++ ++#else ++ ++# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32) ++# define gcdPREFIX_SIZE 0 ++ ++#endif ++ ++/* Assumed largest variable argument leader size. */ ++#define gcdVARARG_LEADER gcmSIZEOF(gctUINT64) ++ ++/* Alignnments. */ ++#if gcdALIGNBYSIZE ++# define gcdPREFIX_ALIGNMENT gcdPREFIX_LEADER ++# define gcdVARARG_ALIGNMENT gcdVARARG_LEADER ++#else ++# define gcdPREFIX_ALIGNMENT 0 ++# define gcdVARARG_ALIGNMENT 0 ++#endif ++ ++#if gcdBUFFERED_OUTPUT ++# define gcdOUTPUTPREFIX _AppendPrefix ++# define gcdOUTPUTSTRING _AppendString ++# define gcdOUTPUTCOPY _AppendCopy ++# define gcdOUTPUTBUFFER _AppendBuffer ++#else ++# define gcdOUTPUTPREFIX _PrintPrefix ++# define gcdOUTPUTSTRING _PrintString ++# define gcdOUTPUTCOPY _PrintString ++# define gcdOUTPUTBUFFER _PrintBuffer ++#endif ++ ++/******************************************************************************\ ++****************************** Private Structures ****************************** ++\******************************************************************************/ ++ ++typedef enum _gceBUFITEM ++{ ++ gceBUFITEM_NONE, ++ gcvBUFITEM_PREFIX, ++ gcvBUFITEM_STRING, ++ gcvBUFITEM_COPY, ++ gcvBUFITEM_BUFFER ++} ++gceBUFITEM; ++ ++/* Common item head/buffer terminator. */ ++typedef struct _gcsBUFITEM_HEAD * gcsBUFITEM_HEAD_PTR; ++typedef struct _gcsBUFITEM_HEAD ++{ ++ gceBUFITEM type; ++} ++gcsBUFITEM_HEAD; ++ ++/* String prefix (for ex. [ 1,tid=0x019A]) */ ++typedef struct _gcsBUFITEM_PREFIX * gcsBUFITEM_PREFIX_PTR; ++typedef struct _gcsBUFITEM_PREFIX ++{ ++ gceBUFITEM type; ++#if gcdHAVEPREFIX ++ gctPOINTER prefixData; ++#endif ++} ++gcsBUFITEM_PREFIX; ++ ++/* Buffered string. */ ++typedef struct _gcsBUFITEM_STRING * gcsBUFITEM_STRING_PTR; ++typedef struct _gcsBUFITEM_STRING ++{ ++ gceBUFITEM type; ++ gctINT indent; ++ gctCONST_STRING message; ++ gctPOINTER messageData; ++ gctUINT messageDataSize; ++} ++gcsBUFITEM_STRING; ++ ++/* Buffered string (copy of the string is included with the record). */ ++typedef struct _gcsBUFITEM_COPY * gcsBUFITEM_COPY_PTR; ++typedef struct _gcsBUFITEM_COPY ++{ ++ gceBUFITEM type; ++ gctINT indent; ++ gctPOINTER messageData; ++ gctUINT messageDataSize; ++} ++gcsBUFITEM_COPY; ++ ++/* Memory buffer. */ ++typedef struct _gcsBUFITEM_BUFFER * gcsBUFITEM_BUFFER_PTR; ++typedef struct _gcsBUFITEM_BUFFER ++{ ++ gceBUFITEM type; ++ gctINT indent; ++ gceDUMP_BUFFER bufferType; ++ ++#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) ++ gctUINT32 dmaAddress; ++#endif ++ ++ gctUINT dataSize; ++ gctUINT32 address; ++#if gcdHAVEPREFIX ++ gctPOINTER prefixData; ++#endif ++} ++gcsBUFITEM_BUFFER; ++ ++typedef struct _gcsBUFFERED_OUTPUT * gcsBUFFERED_OUTPUT_PTR; ++typedef struct _gcsBUFFERED_OUTPUT ++{ ++#if gcdTHREAD_BUFFERS > 1 ++ gctUINT32 threadID; ++#endif ++ ++#if gcdSHOW_LINE_NUMBER ++ gctUINT64 lineNumber; ++#endif ++ ++ gctINT indent; ++ ++#if gcdBUFFERED_OUTPUT ++ gctINT start; ++ gctINT index; ++ gctINT count; ++ gctUINT8 buffer[gcdBUFFERED_SIZE]; ++#endif ++ ++ gcsBUFFERED_OUTPUT_PTR prev; ++ gcsBUFFERED_OUTPUT_PTR next; ++} ++gcsBUFFERED_OUTPUT; ++ ++typedef gctUINT (* gcfPRINTSTRING) ( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gcsBUFITEM_HEAD_PTR Item ++ ); ++ ++typedef gctINT (* gcfGETITEMSIZE) ( ++ IN gcsBUFITEM_HEAD_PTR Item ++ ); ++ ++/******************************************************************************\ ++******************************* Private Variables ****************************** ++\******************************************************************************/ ++ ++static gcsBUFFERED_OUTPUT _outputBuffer[gcdTHREAD_BUFFERS]; ++static gcsBUFFERED_OUTPUT_PTR _outputBufferHead = gcvNULL; ++static gcsBUFFERED_OUTPUT_PTR _outputBufferTail = gcvNULL; ++ ++/******************************************************************************\ ++****************************** Item Size Functions ***************************** ++\******************************************************************************/ ++ ++#if gcdBUFFERED_OUTPUT ++static gctINT ++_GetTerminatorItemSize( ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++ return gcmSIZEOF(gcsBUFITEM_HEAD); ++} ++ ++static gctINT ++_GetPrefixItemSize( ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++#if gcdHAVEPREFIX ++ gcsBUFITEM_PREFIX_PTR item = (gcsBUFITEM_PREFIX_PTR) Item; ++ gctUINT vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); ++ return vlen + gcdPREFIX_SIZE; ++#else ++ return gcmSIZEOF(gcsBUFITEM_PREFIX); ++#endif ++} ++ ++static gctINT ++_GetStringItemSize( ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++ gcsBUFITEM_STRING_PTR item = (gcsBUFITEM_STRING_PTR) Item; ++ gctUINT vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); ++ return vlen + item->messageDataSize; ++} ++ ++static gctINT ++_GetCopyItemSize( ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++ gcsBUFITEM_COPY_PTR item = (gcsBUFITEM_COPY_PTR) Item; ++ gctUINT vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); ++ return vlen + item->messageDataSize; ++} ++ ++static gctINT ++_GetBufferItemSize( ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++#if gcdHAVEPREFIX ++ gcsBUFITEM_BUFFER_PTR item = (gcsBUFITEM_BUFFER_PTR) Item; ++ gctUINT vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); ++ return vlen + gcdPREFIX_SIZE + item->dataSize; ++#else ++ gcsBUFITEM_BUFFER_PTR item = (gcsBUFITEM_BUFFER_PTR) Item; ++ return gcmSIZEOF(gcsBUFITEM_BUFFER) + item->dataSize; ++#endif ++} ++ ++static gcfGETITEMSIZE _itemSize[] = ++{ ++ _GetTerminatorItemSize, ++ _GetPrefixItemSize, ++ _GetStringItemSize, ++ _GetCopyItemSize, ++ _GetBufferItemSize ++}; ++#endif ++ ++/******************************************************************************\ ++******************************* Printing Functions ***************************** ++\******************************************************************************/ ++ ++#if gcdDEBUG || gcdBUFFERED_OUTPUT ++static void ++_DirectPrint( ++ gctCONST_STRING Message, ++ ... ++ ) ++{ ++ gctINT len; ++ char buffer[768]; ++ gctARGUMENTS arguments; ++ ++ gcmkARGUMENTS_START(arguments, Message); ++ len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), Message, &arguments); ++ gcmkARGUMENTS_END(arguments); ++ ++ buffer[len] = '\0'; ++ gcmkOUTPUT_STRING(buffer); ++} ++#endif ++ ++static int ++_AppendIndent( ++ IN gctINT Indent, ++ IN char * Buffer, ++ IN int BufferSize ++ ) ++{ ++ gctINT i; ++ ++ gctINT len = 0; ++ gctINT indent = Indent % 40; ++ ++ for (i = 0; i < indent; i += 1) ++ { ++ Buffer[len++] = ' '; ++ } ++ ++ if (indent != Indent) ++ { ++ len += gcmkSPRINTF( ++ Buffer + len, BufferSize - len, " <%d> ", Indent ++ ); ++ ++ Buffer[len] = '\0'; ++ } ++ ++ return len; ++} ++ ++#if gcdHAVEPREFIX ++static void ++_PrintPrefix( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctPOINTER Data ++ ) ++{ ++ char buffer[768]; ++ gctINT len; ++ ++ /* Format the string. */ ++ len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), _prefixFormat, Data); ++ buffer[len] = '\0'; ++ ++ /* Print the string. */ ++ gcmkOUTPUT_STRING(buffer); ++} ++#endif ++ ++static void ++_PrintString( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctINT Indent, ++ IN gctCONST_STRING Message, ++ IN gctUINT ArgumentSize, ++ IN gctPOINTER Data ++ ) ++{ ++ char buffer[768]; ++ gctINT len; ++ ++ /* Append the indent string. */ ++ len = _AppendIndent(Indent, buffer, gcmSIZEOF(buffer)); ++ ++ /* Format the string. */ ++ len += gcmkVSPRINTF(buffer + len, gcmSIZEOF(buffer) - len, Message, Data); ++ buffer[len] = '\0'; ++ ++ /* Add end-of-line if missing. */ ++ if (buffer[len - 1] != '\n') ++ { ++ buffer[len++] = '\n'; ++ buffer[len] = '\0'; ++ } ++ ++ /* Print the string. */ ++ gcmkOUTPUT_STRING(buffer); ++} ++ ++static void ++_PrintBuffer( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctINT Indent, ++ IN gctPOINTER PrefixData, ++ IN gctPOINTER Data, ++ IN gctUINT Address, ++ IN gctUINT DataSize, ++ IN gceDUMP_BUFFER Type, ++ IN gctUINT32 DmaAddress ++ ) ++{ ++ static gctCONST_STRING _titleString[] = ++ { ++ "CONTEXT BUFFER", ++ "USER COMMAND BUFFER", ++ "KERNEL COMMAND BUFFER", ++ "LINK BUFFER", ++ "WAIT LINK BUFFER", ++ "" ++ }; ++ ++ static const gctINT COLUMN_COUNT = 8; ++ ++ gctUINT i, count, column, address; ++ gctUINT32_PTR data; ++ gctCHAR buffer[768]; ++ gctUINT indent, len; ++ gctBOOL command; ++ ++ /* Append space for the prefix. */ ++#if gcdHAVEPREFIX ++ indent = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), _prefixFormat, PrefixData); ++ buffer[indent] = '\0'; ++#else ++ indent = 0; ++#endif ++ ++ /* Append the indent string. */ ++ indent += _AppendIndent( ++ Indent, buffer + indent, gcmSIZEOF(buffer) - indent ++ ); ++ ++ switch (Type) ++ { ++ case gceDUMP_BUFFER_CONTEXT: ++ case gceDUMP_BUFFER_USER: ++ case gceDUMP_BUFFER_KERNEL: ++ case gceDUMP_BUFFER_LINK: ++ case gceDUMP_BUFFER_WAITLINK: ++ /* Form and print the title string. */ ++ gcmkSPRINTF2( ++ buffer + indent, gcmSIZEOF(buffer) - indent, ++ "%s%s\n", _titleString[Type], ++ ((DmaAddress >= Address) && (DmaAddress < Address + DataSize)) ++ ? " (CURRENT)" : "" ++ ); ++ ++ gcmkOUTPUT_STRING(buffer); ++ ++ /* Terminate the string. */ ++ buffer[indent] = '\0'; ++ ++ /* This is a command buffer. */ ++ command = gcvTRUE; ++ break; ++ ++ case gceDUMP_BUFFER_FROM_USER: ++ /* This is not a command buffer. */ ++ command = gcvFALSE; ++ ++ /* No title. */ ++ break; ++ ++ default: ++ gcmDBGASSERT(gcvFALSE, "%s", "invalid buffer type"); ++ ++ /* This is not a command buffer. */ ++ command = gcvFALSE; ++ } ++ ++ /* Overwrite the prefix with spaces. */ ++ for (i = 0; i < indent; i += 1) ++ { ++ buffer[i] = ' '; ++ } ++ ++ /* Form and print the opening string. */ ++ if (command) ++ { ++ gcmkSPRINTF2( ++ buffer + indent, gcmSIZEOF(buffer) - indent, ++ "@[kernel.command %08X %08X\n", Address, DataSize ++ ); ++ ++ gcmkOUTPUT_STRING(buffer); ++ ++ /* Terminate the string. */ ++ buffer[indent] = '\0'; ++ } ++ ++ /* Get initial address. */ ++ address = Address; ++ ++ /* Cast the data pointer. */ ++ data = (gctUINT32_PTR) Data; ++ ++ /* Compute the number of double words. */ ++ count = DataSize / gcmSIZEOF(gctUINT32); ++ ++ /* Print the buffer. */ ++ for (i = 0, len = indent, column = 0; i < count; i += 1) ++ { ++ /* Append the address. */ ++ if (column == 0) ++ { ++ len += gcmkSPRINTF( ++ buffer + len, gcmSIZEOF(buffer) - len, "0x%08X:", address ++ ); ++ } ++ ++ /* Append the data value. */ ++ len += gcmkSPRINTF2( ++ buffer + len, gcmSIZEOF(buffer) - len, "%c%08X", ++ (address == DmaAddress)? '>' : ' ', data[i] ++ ); ++ ++ buffer[len] = '\0'; ++ ++ /* Update the address. */ ++ address += gcmSIZEOF(gctUINT32); ++ ++ /* Advance column count. */ ++ column += 1; ++ ++ /* End of line? */ ++ if ((column % COLUMN_COUNT) == 0) ++ { ++ /* Append EOL. */ ++ gcmkSTRCAT(buffer + len, gcmSIZEOF(buffer) - len, "\n"); ++ ++ /* Print the string. */ ++ gcmkOUTPUT_STRING(buffer); ++ ++ /* Reset. */ ++ len = indent; ++ column = 0; ++ } ++ } ++ ++ /* Print the last partial string. */ ++ if (column != 0) ++ { ++ /* Append EOL. */ ++ gcmkSTRCAT(buffer + len, gcmSIZEOF(buffer) - len, "\n"); ++ ++ /* Print the string. */ ++ gcmkOUTPUT_STRING(buffer); ++ } ++ ++ /* Form and print the opening string. */ ++ if (command) ++ { ++ buffer[indent] = '\0'; ++ gcmkSTRCAT(buffer, gcmSIZEOF(buffer), "] -- command\n"); ++ gcmkOUTPUT_STRING(buffer); ++ } ++} ++ ++#if gcdBUFFERED_OUTPUT ++static gctUINT ++_PrintNone( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++ /* Return the size of the node. */ ++ return gcmSIZEOF(gcsBUFITEM_HEAD); ++} ++ ++static gctUINT ++_PrintPrefixWrapper( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++#if gcdHAVEPREFIX ++ gcsBUFITEM_PREFIX_PTR item; ++ gctUINT vlen; ++ ++ /* Get access to the data. */ ++ item = (gcsBUFITEM_PREFIX_PTR) Item; ++ ++ /* Print the message. */ ++ _PrintPrefix(OutputBuffer, item->prefixData); ++ ++ /* Compute the size of the variable portion of the structure. */ ++ vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); ++ ++ /* Return the size of the node. */ ++ return vlen + gcdPREFIX_SIZE; ++#else ++ return gcmSIZEOF(gcsBUFITEM_PREFIX); ++#endif ++} ++ ++static gctUINT ++_PrintStringWrapper( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++ gcsBUFITEM_STRING_PTR item; ++ gctUINT vlen; ++ ++ /* Get access to the data. */ ++ item = (gcsBUFITEM_STRING_PTR) Item; ++ ++ /* Print the message. */ ++ _PrintString( ++ OutputBuffer, ++ item->indent, item->message, item->messageDataSize, item->messageData ++ ); ++ ++ /* Compute the size of the variable portion of the structure. */ ++ vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); ++ ++ /* Return the size of the node. */ ++ return vlen + item->messageDataSize; ++} ++ ++static gctUINT ++_PrintCopyWrapper( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++ gcsBUFITEM_COPY_PTR item; ++ gctCONST_STRING message; ++ gctUINT vlen; ++ ++ /* Get access to the data. */ ++ item = (gcsBUFITEM_COPY_PTR) Item; ++ ++ /* Determine the string pointer. */ ++ message = (gctCONST_STRING) (item + 1); ++ ++ /* Print the message. */ ++ _PrintString( ++ OutputBuffer, ++ item->indent, message, item->messageDataSize, item->messageData ++ ); ++ ++ /* Compute the size of the variable portion of the structure. */ ++ vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); ++ ++ /* Return the size of the node. */ ++ return vlen + item->messageDataSize; ++} ++ ++static gctUINT ++_PrintBufferWrapper( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gcsBUFITEM_HEAD_PTR Item ++ ) ++{ ++#if gcdHAVEPREFIX ++ gctUINT32 dmaAddress; ++ gcsBUFITEM_BUFFER_PTR item; ++ gctPOINTER data; ++ gctUINT vlen; ++ ++ /* Get access to the data. */ ++ item = (gcsBUFITEM_BUFFER_PTR) Item; ++ ++#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) ++ dmaAddress = item->dmaAddress; ++#else ++ dmaAddress = 0xFFFFFFFF; ++#endif ++ ++ if (dmaAddress != 0) ++ { ++ /* Compute the data address. */ ++ data = ((gctUINT8_PTR) item->prefixData) + gcdPREFIX_SIZE; ++ ++ /* Print buffer. */ ++ _PrintBuffer( ++ OutputBuffer, ++ item->indent, item->prefixData, ++ data, item->address, item->dataSize, ++ item->bufferType, dmaAddress ++ ); ++ } ++ ++ /* Compute the size of the variable portion of the structure. */ ++ vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); ++ ++ /* Return the size of the node. */ ++ return vlen + gcdPREFIX_SIZE + item->dataSize; ++#else ++ gctUINT32 dmaAddress; ++ gcsBUFITEM_BUFFER_PTR item; ++ ++ /* Get access to the data. */ ++ item = (gcsBUFITEM_BUFFER_PTR) Item; ++ ++#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) ++ dmaAddress = item->dmaAddress; ++#else ++ dmaAddress = 0xFFFFFFFF; ++#endif ++ ++ if (dmaAddress != 0) ++ { ++ /* Print buffer. */ ++ _PrintBuffer( ++ OutputBuffer, ++ item->indent, gcvNULL, ++ item + 1, item->address, item->dataSize, ++ item->bufferType, dmaAddress ++ ); ++ } ++ ++ /* Return the size of the node. */ ++ return gcmSIZEOF(gcsBUFITEM_BUFFER) + item->dataSize; ++#endif ++} ++ ++static gcfPRINTSTRING _printArray[] = ++{ ++ _PrintNone, ++ _PrintPrefixWrapper, ++ _PrintStringWrapper, ++ _PrintCopyWrapper, ++ _PrintBufferWrapper ++}; ++#endif ++ ++/******************************************************************************\ ++******************************* Private Functions ****************************** ++\******************************************************************************/ ++ ++#if gcdBUFFERED_OUTPUT ++ ++#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) ++static gcsBUFITEM_BUFFER_PTR ++_FindCurrentDMABuffer( ++ gctUINT32 DmaAddress ++ ) ++{ ++ gctINT i, skip; ++ gcsBUFITEM_HEAD_PTR item; ++ gcsBUFITEM_BUFFER_PTR dmaCurrent; ++ ++ /* Reset the current buffer. */ ++ dmaCurrent = gcvNULL; ++ ++ /* Get the first stored item. */ ++ item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start]; ++ ++ /* Run through all items. */ ++ for (i = 0; i < _outputBufferHead->count; i += 1) ++ { ++ /* Buffer item? */ ++ if (item->type == gcvBUFITEM_BUFFER) ++ { ++ gcsBUFITEM_BUFFER_PTR buffer = (gcsBUFITEM_BUFFER_PTR) item; ++ ++ if ((DmaAddress >= buffer->address) && ++ (DmaAddress < buffer->address + buffer->dataSize)) ++ { ++ dmaCurrent = buffer; ++ } ++ } ++ ++ /* Get the item size and skip it. */ ++ skip = (* _itemSize[item->type]) (item); ++ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); ++ ++ /* End of the buffer? Wrap around. */ ++ if (item->type == gceBUFITEM_NONE) ++ { ++ item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer; ++ } ++ } ++ ++ /* Return result. */ ++ return dmaCurrent; ++} ++ ++static void ++_EnableAllDMABuffers( ++ void ++ ) ++{ ++ gctINT i, skip; ++ gcsBUFITEM_HEAD_PTR item; ++ ++ /* Get the first stored item. */ ++ item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start]; ++ ++ /* Run through all items. */ ++ for (i = 0; i < _outputBufferHead->count; i += 1) ++ { ++ /* Buffer item? */ ++ if (item->type == gcvBUFITEM_BUFFER) ++ { ++ gcsBUFITEM_BUFFER_PTR buffer = (gcsBUFITEM_BUFFER_PTR) item; ++ ++ /* Enable the buffer. */ ++ buffer->dmaAddress = ~0U; ++ } ++ ++ /* Get the item size and skip it. */ ++ skip = (* _itemSize[item->type]) (item); ++ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); ++ ++ /* End of the buffer? Wrap around. */ ++ if (item->type == gceBUFITEM_NONE) ++ { ++ item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer; ++ } ++ } ++} ++ ++static void ++_EnableDMABuffers( ++ gctUINT32 DmaAddress, ++ gcsBUFITEM_BUFFER_PTR CurrentDMABuffer ++ ) ++{ ++ gctINT i, skip, index; ++ gcsBUFITEM_HEAD_PTR item; ++ gcsBUFITEM_BUFFER_PTR buffers[gcdDMA_BUFFER_COUNT]; ++ ++ /* Reset buffer pointers. */ ++ gckOS_ZeroMemory(buffers, gcmSIZEOF(buffers)); ++ ++ /* Set the current buffer index. */ ++ index = -1; ++ ++ /* Get the first stored item. */ ++ item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start]; ++ ++ /* Run through all items until the current DMA buffer is found. */ ++ for (i = 0; i < _outputBufferHead->count; i += 1) ++ { ++ /* Buffer item? */ ++ if (item->type == gcvBUFITEM_BUFFER) ++ { ++ /* Advance the index. */ ++ index = (index + 1) % gcdDMA_BUFFER_COUNT; ++ ++ /* Add to the buffer array. */ ++ buffers[index] = (gcsBUFITEM_BUFFER_PTR) item; ++ ++ /* Stop if this is the current DMA buffer. */ ++ if ((gcsBUFITEM_BUFFER_PTR) item == CurrentDMABuffer) ++ { ++ break; ++ } ++ } ++ ++ /* Get the item size and skip it. */ ++ skip = (* _itemSize[item->type]) (item); ++ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); ++ ++ /* End of the buffer? Wrap around. */ ++ if (item->type == gceBUFITEM_NONE) ++ { ++ item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer; ++ } ++ } ++ ++ /* Enable the found buffers. */ ++ gcmDBGASSERT(index != -1, "%d", index); ++ ++ for (i = 0; i < gcdDMA_BUFFER_COUNT; i += 1) ++ { ++ if (buffers[index] == gcvNULL) ++ { ++ break; ++ } ++ ++ buffers[index]->dmaAddress = DmaAddress; ++ ++ index -= 1; ++ ++ if (index == -1) ++ { ++ index = gcdDMA_BUFFER_COUNT - 1; ++ } ++ } ++} ++#endif ++ ++static void ++_Flush( ++ gctUINT32 DmaAddress ++ ) ++{ ++ gctINT i, skip; ++ gcsBUFITEM_HEAD_PTR item; ++ ++ gcsBUFFERED_OUTPUT_PTR outputBuffer = _outputBufferHead; ++ ++#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) ++ if ((outputBuffer != gcvNULL) && (outputBuffer->count != 0)) ++ { ++ /* Find the current DMA buffer. */ ++ gcsBUFITEM_BUFFER_PTR dmaCurrent = _FindCurrentDMABuffer(DmaAddress); ++ ++ /* Was the current buffer found? */ ++ if (dmaCurrent == gcvNULL) ++ { ++ /* No, print all buffers. */ ++ _EnableAllDMABuffers(); ++ } ++ else ++ { ++ /* Yes, enable only specified number of buffers. */ ++ _EnableDMABuffers(DmaAddress, dmaCurrent); ++ } ++ } ++#endif ++ ++ while (outputBuffer != gcvNULL) ++ { ++ if (outputBuffer->count != 0) ++ { ++ _DirectPrint("********************************************************************************\n"); ++ _DirectPrint("FLUSHING DEBUG OUTPUT BUFFER (%d elements).\n", outputBuffer->count); ++ _DirectPrint("********************************************************************************\n"); ++ ++ item = (gcsBUFITEM_HEAD_PTR) &outputBuffer->buffer[outputBuffer->start]; ++ ++ for (i = 0; i < outputBuffer->count; i += 1) ++ { ++ skip = (* _printArray[item->type]) (outputBuffer, item); ++ ++ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); ++ ++ if (item->type == gceBUFITEM_NONE) ++ { ++ item = (gcsBUFITEM_HEAD_PTR) outputBuffer->buffer; ++ } ++ } ++ ++ outputBuffer->start = 0; ++ outputBuffer->index = 0; ++ outputBuffer->count = 0; ++ } ++ ++ outputBuffer = outputBuffer->next; ++ } ++} ++ ++static gcsBUFITEM_HEAD_PTR ++_AllocateItem( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctINT Size ++ ) ++{ ++ gctINT skip; ++ gcsBUFITEM_HEAD_PTR item, next; ++ ++#if gcdENABLE_OVERFLOW ++ if ( ++ (OutputBuffer->index + Size >= gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD)) ++ || ++ ( ++ (OutputBuffer->index < OutputBuffer->start) && ++ (OutputBuffer->index + Size >= OutputBuffer->start) ++ ) ++ ) ++ { ++ if (OutputBuffer->index + Size >= gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD)) ++ { ++ if (OutputBuffer->index < OutputBuffer->start) ++ { ++ item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->start]; ++ ++ while (item->type != gceBUFITEM_NONE) ++ { ++ skip = (* _itemSize[item->type]) (item); ++ ++ OutputBuffer->start += skip; ++ OutputBuffer->count -= 1; ++ ++ item->type = gceBUFITEM_NONE; ++ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); ++ } ++ ++ OutputBuffer->start = 0; ++ } ++ ++ OutputBuffer->index = 0; ++ } ++ ++ item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->start]; ++ ++ while (OutputBuffer->start - OutputBuffer->index <= Size) ++ { ++ skip = (* _itemSize[item->type]) (item); ++ ++ OutputBuffer->start += skip; ++ OutputBuffer->count -= 1; ++ ++ item->type = gceBUFITEM_NONE; ++ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); ++ ++ if (item->type == gceBUFITEM_NONE) ++ { ++ OutputBuffer->start = 0; ++ break; ++ } ++ } ++ } ++#else ++ if (OutputBuffer->index + Size > gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD)) ++ { ++ _DirectPrint("\nMessage buffer full; forcing message flush.\n\n"); ++ _Flush(~0U); ++ } ++#endif ++ ++ item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->index]; ++ ++ OutputBuffer->index += Size; ++ OutputBuffer->count += 1; ++ ++ next = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + Size); ++ next->type = gceBUFITEM_NONE; ++ ++ return item; ++} ++ ++#if gcdALIGNBYSIZE ++static void ++_FreeExtraSpace( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctPOINTER Item, ++ IN gctINT ItemSize, ++ IN gctINT FreeSize ++ ) ++{ ++ gcsBUFITEM_HEAD_PTR next; ++ ++ OutputBuffer->index -= FreeSize; ++ ++ next = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) Item + ItemSize); ++ next->type = gceBUFITEM_NONE; ++} ++#endif ++ ++#if gcdHAVEPREFIX ++static void ++_AppendPrefix( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctPOINTER Data ++ ) ++{ ++ gctUINT8_PTR prefixData; ++ gcsBUFITEM_PREFIX_PTR item; ++ gctINT allocSize; ++ ++#if gcdALIGNBYSIZE ++ gctUINT alignment; ++ gctINT size, freeSize; ++#endif ++ ++ gcmDBGASSERT(Data != gcvNULL, "%p", Data); ++ ++ /* Determine the maximum item size. */ ++ allocSize ++ = gcmSIZEOF(gcsBUFITEM_PREFIX) ++ + gcdPREFIX_SIZE ++ + gcdPREFIX_ALIGNMENT; ++ ++ /* Allocate prefix item. */ ++ item = (gcsBUFITEM_PREFIX_PTR) _AllocateItem(OutputBuffer, allocSize); ++ ++ /* Compute the initial prefix data pointer. */ ++ prefixData = (gctUINT8_PTR) (item + 1); ++ ++ /* Align the data pointer as necessary. */ ++#if gcdALIGNBYSIZE ++ alignment = gcmPTRALIGNMENT(prefixData, gcdPREFIX_ALIGNMENT); ++ prefixData += alignment; ++#endif ++ ++ /* Set item data. */ ++ item->type = gcvBUFITEM_PREFIX; ++ item->prefixData = prefixData; ++ ++ /* Copy argument value. */ ++ memcpy(prefixData, Data, gcdPREFIX_SIZE); ++ ++#if gcdALIGNBYSIZE ++ /* Compute the actual node size. */ ++ size = gcmSIZEOF(gcsBUFITEM_PREFIX) + gcdPREFIX_SIZE + alignment; ++ ++ /* Free extra memory if any. */ ++ freeSize = allocSize - size; ++ if (freeSize != 0) ++ { ++ _FreeExtraSpace(OutputBuffer, item, size, freeSize); ++ } ++#endif ++} ++#endif ++ ++static void ++_AppendString( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctINT Indent, ++ IN gctCONST_STRING Message, ++ IN gctUINT ArgumentSize, ++ IN gctPOINTER Data ++ ) ++{ ++ gctUINT8_PTR messageData; ++ gcsBUFITEM_STRING_PTR item; ++ gctINT allocSize; ++ ++#if gcdALIGNBYSIZE ++ gctUINT alignment; ++ gctINT size, freeSize; ++#endif ++ ++ /* Determine the maximum item size. */ ++ allocSize ++ = gcmSIZEOF(gcsBUFITEM_STRING) ++ + ArgumentSize ++ + gcdVARARG_ALIGNMENT; ++ ++ /* Allocate prefix item. */ ++ item = (gcsBUFITEM_STRING_PTR) _AllocateItem(OutputBuffer, allocSize); ++ ++ /* Compute the initial message data pointer. */ ++ messageData = (gctUINT8_PTR) (item + 1); ++ ++ /* Align the data pointer as necessary. */ ++#if gcdALIGNBYSIZE ++ alignment = gcmPTRALIGNMENT(messageData, gcdVARARG_ALIGNMENT); ++ messageData += alignment; ++#endif ++ ++ /* Set item data. */ ++ item->type = gcvBUFITEM_STRING; ++ item->indent = Indent; ++ item->message = Message; ++ item->messageData = messageData; ++ item->messageDataSize = ArgumentSize; ++ ++ /* Copy argument value. */ ++ if (ArgumentSize != 0) ++ { ++ memcpy(messageData, Data, ArgumentSize); ++ } ++ ++#if gcdALIGNBYSIZE ++ /* Compute the actual node size. */ ++ size = gcmSIZEOF(gcsBUFITEM_STRING) + ArgumentSize + alignment; ++ ++ /* Free extra memory if any. */ ++ freeSize = allocSize - size; ++ if (freeSize != 0) ++ { ++ _FreeExtraSpace(OutputBuffer, item, size, freeSize); ++ } ++#endif ++} ++ ++static void ++_AppendCopy( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctINT Indent, ++ IN gctCONST_STRING Message, ++ IN gctUINT ArgumentSize, ++ IN gctPOINTER Data ++ ) ++{ ++ gctUINT8_PTR messageData; ++ gcsBUFITEM_COPY_PTR item; ++ gctINT allocSize; ++ gctINT messageLength; ++ gctCONST_STRING message; ++ ++#if gcdALIGNBYSIZE ++ gctUINT alignment; ++ gctINT size, freeSize; ++#endif ++ ++ /* Get the length of the string. */ ++ messageLength = strlen(Message) + 1; ++ ++ /* Determine the maximum item size. */ ++ allocSize ++ = gcmSIZEOF(gcsBUFITEM_COPY) ++ + messageLength ++ + ArgumentSize ++ + gcdVARARG_ALIGNMENT; ++ ++ /* Allocate prefix item. */ ++ item = (gcsBUFITEM_COPY_PTR) _AllocateItem(OutputBuffer, allocSize); ++ ++ /* Determine the message placement. */ ++ message = (gctCONST_STRING) (item + 1); ++ ++ /* Compute the initial message data pointer. */ ++ messageData = (gctUINT8_PTR) message + messageLength; ++ ++ /* Align the data pointer as necessary. */ ++#if gcdALIGNBYSIZE ++ if (ArgumentSize == 0) ++ { ++ alignment = 0; ++ } ++ else ++ { ++ alignment = gcmPTRALIGNMENT(messageData, gcdVARARG_ALIGNMENT); ++ messageData += alignment; ++ } ++#endif ++ ++ /* Set item data. */ ++ item->type = gcvBUFITEM_COPY; ++ item->indent = Indent; ++ item->messageData = messageData; ++ item->messageDataSize = ArgumentSize; ++ ++ /* Copy the message. */ ++ memcpy((gctPOINTER) message, Message, messageLength); ++ ++ /* Copy argument value. */ ++ if (ArgumentSize != 0) ++ { ++ memcpy(messageData, Data, ArgumentSize); ++ } ++ ++#if gcdALIGNBYSIZE ++ /* Compute the actual node size. */ ++ size ++ = gcmSIZEOF(gcsBUFITEM_COPY) ++ + messageLength ++ + ArgumentSize ++ + alignment; ++ ++ /* Free extra memory if any. */ ++ freeSize = allocSize - size; ++ if (freeSize != 0) ++ { ++ _FreeExtraSpace(OutputBuffer, item, size, freeSize); ++ } ++#endif ++} ++ ++static void ++_AppendBuffer( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctINT Indent, ++ IN gctPOINTER PrefixData, ++ IN gctPOINTER Data, ++ IN gctUINT Address, ++ IN gctUINT DataSize, ++ IN gceDUMP_BUFFER Type, ++ IN gctUINT32 DmaAddress ++ ) ++{ ++#if gcdHAVEPREFIX ++ gctUINT8_PTR prefixData; ++ gcsBUFITEM_BUFFER_PTR item; ++ gctINT allocSize; ++ gctPOINTER data; ++ ++#if gcdALIGNBYSIZE ++ gctUINT alignment; ++ gctINT size, freeSize; ++#endif ++ ++ gcmDBGASSERT(DataSize != 0, "%d", DataSize); ++ gcmDBGASSERT(Data != gcvNULL, "%p", Data); ++ ++ /* Determine the maximum item size. */ ++ allocSize ++ = gcmSIZEOF(gcsBUFITEM_BUFFER) ++ + gcdPREFIX_SIZE ++ + gcdPREFIX_ALIGNMENT ++ + DataSize; ++ ++ /* Allocate prefix item. */ ++ item = (gcsBUFITEM_BUFFER_PTR) _AllocateItem(OutputBuffer, allocSize); ++ ++ /* Compute the initial prefix data pointer. */ ++ prefixData = (gctUINT8_PTR) (item + 1); ++ ++#if gcdALIGNBYSIZE ++ /* Align the data pointer as necessary. */ ++ alignment = gcmPTRALIGNMENT(prefixData, gcdPREFIX_ALIGNMENT); ++ prefixData += alignment; ++#endif ++ ++ /* Set item data. */ ++ item->type = gcvBUFITEM_BUFFER; ++ item->indent = Indent; ++ item->bufferType = Type; ++ item->dataSize = DataSize; ++ item->address = Address; ++ item->prefixData = prefixData; ++ ++#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) ++ item->dmaAddress = DmaAddress; ++#endif ++ ++ /* Copy prefix data. */ ++ memcpy(prefixData, PrefixData, gcdPREFIX_SIZE); ++ ++ /* Compute the data pointer. */ ++ data = prefixData + gcdPREFIX_SIZE; ++ ++ /* Copy argument value. */ ++ memcpy(data, Data, DataSize); ++ ++#if gcdALIGNBYSIZE ++ /* Compute the actual node size. */ ++ size ++ = gcmSIZEOF(gcsBUFITEM_BUFFER) ++ + gcdPREFIX_SIZE ++ + alignment ++ + DataSize; ++ ++ /* Free extra memory if any. */ ++ freeSize = allocSize - size; ++ if (freeSize != 0) ++ { ++ _FreeExtraSpace(OutputBuffer, item, size, freeSize); ++ } ++#endif ++#else ++ gcsBUFITEM_BUFFER_PTR item; ++ gctINT size; ++ ++ gcmDBGASSERT(DataSize != 0, "%d", DataSize); ++ gcmDBGASSERT(Data != gcvNULL, "%p", Data); ++ ++ /* Determine the maximum item size. */ ++ size = gcmSIZEOF(gcsBUFITEM_BUFFER) + DataSize; ++ ++ /* Allocate prefix item. */ ++ item = (gcsBUFITEM_BUFFER_PTR) _AllocateItem(OutputBuffer, size); ++ ++ /* Set item data. */ ++ item->type = gcvBUFITEM_BUFFER; ++ item->indent = Indent; ++ item->dataSize = DataSize; ++ item->address = Address; ++ ++ /* Copy argument value. */ ++ memcpy(item + 1, Data, DataSize); ++#endif ++} ++#endif ++ ++static gcmINLINE void ++_InitBuffers( ++ void ++ ) ++{ ++ int i; ++ ++ if (_outputBufferHead == gcvNULL) ++ { ++ for (i = 0; i < gcdTHREAD_BUFFERS; i += 1) ++ { ++ if (_outputBufferTail == gcvNULL) ++ { ++ _outputBufferHead = &_outputBuffer[i]; ++ } ++ else ++ { ++ _outputBufferTail->next = &_outputBuffer[i]; ++ } ++ ++#if gcdTHREAD_BUFFERS > 1 ++ _outputBuffer[i].threadID = ~0U; ++#endif ++ ++ _outputBuffer[i].prev = _outputBufferTail; ++ _outputBuffer[i].next = gcvNULL; ++ ++ _outputBufferTail = &_outputBuffer[i]; ++ } ++ } ++} ++ ++static gcmINLINE gcsBUFFERED_OUTPUT_PTR ++_GetOutputBuffer( ++ void ++ ) ++{ ++ gcsBUFFERED_OUTPUT_PTR outputBuffer; ++ ++#if gcdTHREAD_BUFFERS > 1 ++ /* Get the current thread ID. */ ++ gctUINT32 ThreadID = gcmkGETTHREADID(); ++ ++ /* Locate the output buffer for the thread. */ ++ outputBuffer = _outputBufferHead; ++ ++ while (outputBuffer != gcvNULL) ++ { ++ if (outputBuffer->threadID == ThreadID) ++ { ++ break; ++ } ++ ++ outputBuffer = outputBuffer->next; ++ } ++ ++ /* No matching buffer found? */ ++ if (outputBuffer == gcvNULL) ++ { ++ /* Get the tail for the buffer. */ ++ outputBuffer = _outputBufferTail; ++ ++ /* Move it to the head. */ ++ _outputBufferTail = _outputBufferTail->prev; ++ _outputBufferTail->next = gcvNULL; ++ ++ outputBuffer->prev = gcvNULL; ++ outputBuffer->next = _outputBufferHead; ++ ++ _outputBufferHead->prev = outputBuffer; ++ _outputBufferHead = outputBuffer; ++ ++ /* Reset the buffer. */ ++ outputBuffer->threadID = ThreadID; ++#if gcdBUFFERED_OUTPUT ++ outputBuffer->start = 0; ++ outputBuffer->index = 0; ++ outputBuffer->count = 0; ++#endif ++#if gcdSHOW_LINE_NUMBER ++ outputBuffer->lineNumber = 0; ++#endif ++ } ++#else ++ outputBuffer = _outputBufferHead; ++#endif ++ ++ return outputBuffer; ++} ++ ++static gcmINLINE int _GetArgumentSize( ++ IN gctCONST_STRING Message ++ ) ++{ ++ int i, count; ++ ++ gcmDBGASSERT(Message != gcvNULL, "%p", Message); ++ ++ for (i = 0, count = 0; Message[i]; i += 1) ++ { ++ if (Message[i] == '%') ++ { ++ count += 1; ++ } ++ } ++ ++ return count * gcmSIZEOF(gctUINT32); ++} ++ ++#if gcdHAVEPREFIX ++static void ++_InitPrefixData( ++ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, ++ IN gctPOINTER Data ++ ) ++{ ++ gctUINT8_PTR data = (gctUINT8_PTR) Data; ++ ++#if gcdSHOW_TIME ++ { ++ gctUINT64 time; ++ gckOS_GetProfileTick(&time); ++ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT64)); ++ * ((gctUINT64_PTR) data) = time; ++ data += gcmSIZEOF(gctUINT64); ++ } ++#endif ++ ++#if gcdSHOW_LINE_NUMBER ++ { ++ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT64)); ++ * ((gctUINT64_PTR) data) = OutputBuffer->lineNumber; ++ data += gcmSIZEOF(gctUINT64); ++ } ++#endif ++ ++#if gcdSHOW_PROCESS_ID ++ { ++ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT32)); ++ * ((gctUINT32_PTR) data) = gcmkGETPROCESSID(); ++ data += gcmSIZEOF(gctUINT32); ++ } ++#endif ++ ++#if gcdSHOW_THREAD_ID ++ { ++ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT32)); ++ * ((gctUINT32_PTR) data) = gcmkGETTHREADID(); ++ } ++#endif ++} ++#endif ++ ++static void ++_Print( ++ IN gctUINT ArgumentSize, ++ IN gctBOOL CopyMessage, ++ IN gctCONST_STRING Message, ++ IN gctARGUMENTS * Arguments ++ ) ++{ ++ gcsBUFFERED_OUTPUT_PTR outputBuffer; ++ gcmkDECLARE_LOCK(lockHandle); ++ ++ gcmkLOCKSECTION(lockHandle); ++ ++ /* Initialize output buffer list. */ ++ _InitBuffers(); ++ ++ /* Locate the proper output buffer. */ ++ outputBuffer = _GetOutputBuffer(); ++ ++ /* Update the line number. */ ++#if gcdSHOW_LINE_NUMBER ++ outputBuffer->lineNumber += 1; ++#endif ++ ++ /* Print prefix. */ ++#if gcdHAVEPREFIX ++ { ++ gctUINT8_PTR alignedPrefixData; ++ gctUINT8 prefixData[gcdPREFIX_SIZE + gcdPREFIX_ALIGNMENT]; ++ ++ /* Compute aligned pointer. */ ++ alignedPrefixData = prefixData; ++ gcmkALIGNPTR(gctUINT8_PTR, alignedPrefixData, gcdPREFIX_ALIGNMENT); ++ ++ /* Initialize the prefix data. */ ++ _InitPrefixData(outputBuffer, alignedPrefixData); ++ ++ /* Print the prefix. */ ++ gcdOUTPUTPREFIX(outputBuffer, alignedPrefixData); ++ } ++#endif ++ ++ /* Form the indent string. */ ++ if (strncmp(Message, "--", 2) == 0) ++ { ++ outputBuffer->indent -= 2; ++ } ++ ++ /* Print the message. */ ++ if (CopyMessage) ++ { ++ gcdOUTPUTCOPY( ++ outputBuffer, outputBuffer->indent, ++ Message, ArgumentSize, (gctPOINTER) Arguments ++ ); ++ } ++ else ++ { ++ gcdOUTPUTSTRING( ++ outputBuffer, outputBuffer->indent, ++ Message, ArgumentSize, ((gctPOINTER) Arguments) ++ ); ++ } ++ ++ /* Check increasing indent. */ ++ if (strncmp(Message, "++", 2) == 0) ++ { ++ outputBuffer->indent += 2; ++ } ++ ++ gcmkUNLOCKSECTION(lockHandle); ++} ++ ++ ++/******************************************************************************\ ++********************************* Debug Macros ********************************* ++\******************************************************************************/ ++ ++#define gcmDEBUGPRINT(ArgumentSize, CopyMessage, Message) \ ++{ \ ++ gctARGUMENTS __arguments__; \ ++ gcmkARGUMENTS_START(__arguments__, Message); \ ++ _Print(ArgumentSize, CopyMessage, Message, &__arguments__); \ ++ gcmkARGUMENTS_END(__arguments__); \ ++} ++ ++ ++/******************************************************************************\ ++********************************** Debug Code ********************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckOS_Print ++** ++** Send a message to the debugger. ++** ++** INPUT: ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_Print( ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); ++} ++ ++/******************************************************************************* ++** ++** gckOS_PrintN ++** ++** Send a message to the debugger. ++** ++** INPUT: ++** ++** gctUINT ArgumentSize ++** The size of the optional arguments in bytes. ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_PrintN( ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message); ++} ++ ++/******************************************************************************* ++** ++** gckOS_CopyPrint ++** ++** Send a message to the debugger. If in buffered output mode, the entire ++** message will be copied into the buffer instead of using the pointer to ++** the string. ++** ++** INPUT: ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_CopyPrint( ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvTRUE, Message); ++} ++ ++/******************************************************************************* ++** ++** gckOS_DumpBuffer ++** ++** Print the contents of the specified buffer. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to gckOS object. ++** ++** gctPOINTER Buffer ++** Pointer to the buffer to print. ++** ++** gctUINT Size ++** Size of the buffer. ++** ++** gceDUMP_BUFFER Type ++** Buffer type. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_DumpBuffer( ++ IN gckOS Os, ++ IN gctPOINTER Buffer, ++ IN gctUINT Size, ++ IN gceDUMP_BUFFER Type, ++ IN gctBOOL CopyMessage ++ ) ++{ ++ gctUINT32 address = 0; ++ gcsBUFFERED_OUTPUT_PTR outputBuffer = gcvNULL; ++ static gctBOOL userLocked; ++ gctCHAR *buffer = (gctCHAR*)Buffer; ++ ++ gcmkDECLARE_LOCK(lockHandle); ++ ++ /* Request lock when not coming from user, ++ or coming from user and not yet locked ++ and message is starting with @[. */ ++ if (Type == gceDUMP_BUFFER_FROM_USER) ++ { ++ if ((Size > 2) ++ && (buffer[0] == '@') ++ && (buffer[1] == '[')) ++ { ++ /* Beginning of a user dump. */ ++ gcmkLOCKSECTION(lockHandle); ++ userLocked = gcvTRUE; ++ } ++ /* Else, let it pass through. */ ++ } ++ else ++ { ++ gcmkLOCKSECTION(lockHandle); ++ userLocked = gcvFALSE; ++ } ++ ++ if (Buffer != gcvNULL) ++ { ++ /* Initialize output buffer list. */ ++ _InitBuffers(); ++ ++ /* Locate the proper output buffer. */ ++ outputBuffer = _GetOutputBuffer(); ++ ++ /* Update the line number. */ ++#if gcdSHOW_LINE_NUMBER ++ outputBuffer->lineNumber += 1; ++#endif ++ ++ /* Get the physical address of the buffer. */ ++ if (Type != gceDUMP_BUFFER_FROM_USER) ++ { ++ gcmkVERIFY_OK(gckOS_GetPhysicalAddress(Os, Buffer, &address)); ++ } ++ else ++ { ++ address = 0; ++ } ++ ++#if gcdHAVEPREFIX ++ { ++ gctUINT8_PTR alignedPrefixData; ++ gctUINT8 prefixData[gcdPREFIX_SIZE + gcdPREFIX_ALIGNMENT]; ++ ++ /* Compute aligned pointer. */ ++ alignedPrefixData = prefixData; ++ gcmkALIGNPTR(gctUINT8_PTR, alignedPrefixData, gcdPREFIX_ALIGNMENT); ++ ++ /* Initialize the prefix data. */ ++ _InitPrefixData(outputBuffer, alignedPrefixData); ++ ++ /* Print/schedule the buffer. */ ++ gcdOUTPUTBUFFER( ++ outputBuffer, outputBuffer->indent, ++ alignedPrefixData, Buffer, address, Size, Type, 0 ++ ); ++ } ++#else ++ /* Print/schedule the buffer. */ ++ if (Type == gceDUMP_BUFFER_FROM_USER) ++ { ++ gcdOUTPUTSTRING( ++ outputBuffer, outputBuffer->indent, ++ Buffer, 0, gcvNULL ++ ); ++ } ++ else ++ { ++ gcdOUTPUTBUFFER( ++ outputBuffer, outputBuffer->indent, ++ gcvNULL, Buffer, address, Size, Type, 0 ++ ); ++ } ++#endif ++ } ++ ++ /* Unlock when not coming from user, ++ or coming from user and not yet locked. */ ++ if (userLocked) ++ { ++ if ((Size > 4) ++ && (buffer[0] == ']') ++ && (buffer[1] == ' ') ++ && (buffer[2] == '-') ++ && (buffer[3] == '-')) ++ { ++ /* End of a user dump. */ ++ gcmkUNLOCKSECTION(lockHandle); ++ userLocked = gcvFALSE; ++ } ++ /* Else, let it pass through, don't unlock. */ ++ } ++ else ++ { ++ gcmkUNLOCKSECTION(lockHandle); ++ } ++} ++ ++/******************************************************************************* ++** ++** gckOS_DebugTrace ++** ++** Send a leveled message to the debugger. ++** ++** INPUT: ++** ++** gctUINT32 Level ++** Debug level of message. ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_DebugTrace( ++ IN gctUINT32 Level, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ if (Level > _debugLevel) ++ { ++ return; ++ } ++ ++ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); ++} ++ ++/******************************************************************************* ++** ++** gckOS_DebugTraceN ++** ++** Send a leveled message to the debugger. ++** ++** INPUT: ++** ++** gctUINT32 Level ++** Debug level of message. ++** ++** gctUINT ArgumentSize ++** The size of the optional arguments in bytes. ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_DebugTraceN( ++ IN gctUINT32 Level, ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ if (Level > _debugLevel) ++ { ++ return; ++ } ++ ++ gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message); ++} ++ ++/******************************************************************************* ++** ++** gckOS_DebugTraceZone ++** ++** Send a leveled and zoned message to the debugger. ++** ++** INPUT: ++** ++** gctUINT32 Level ++** Debug level for message. ++** ++** gctUINT32 Zone ++** Debug zone for message. ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_DebugTraceZone( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ if ((Level > _debugLevel) || !(Zone & _debugZones)) ++ { ++ return; ++ } ++ ++ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); ++} ++ ++/******************************************************************************* ++** ++** gckOS_DebugTraceZoneN ++** ++** Send a leveled and zoned message to the debugger. ++** ++** INPUT: ++** ++** gctUINT32 Level ++** Debug level for message. ++** ++** gctUINT32 Zone ++** Debug zone for message. ++** ++** gctUINT ArgumentSize ++** The size of the optional arguments in bytes. ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_DebugTraceZoneN( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone, ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ if ((Level > _debugLevel) || !(Zone & _debugZones)) ++ { ++ return; ++ } ++ ++ gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message); ++} ++ ++/******************************************************************************* ++** ++** gckOS_DebugBreak ++** ++** Break into the debugger. ++** ++** INPUT: ++** ++** Nothing. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++void ++gckOS_DebugBreak( ++ void ++ ) ++{ ++ gckOS_DebugTrace(gcvLEVEL_ERROR, "%s(%d)", __FUNCTION__, __LINE__); ++} ++ ++/******************************************************************************* ++** ++** gckOS_DebugFatal ++** ++** Send a message to the debugger and break into the debugger. ++** ++** INPUT: ++** ++** gctCONST_STRING Message ++** Pointer to message. ++** ++** ... ++** Optional arguments. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++void ++gckOS_DebugFatal( ++ IN gctCONST_STRING Message, ++ ... ++ ) ++{ ++ gcmkPRINT_VERSION(); ++ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); ++ ++ /* Break into the debugger. */ ++ gckOS_DebugBreak(); ++} ++ ++/******************************************************************************* ++** ++** gckOS_SetDebugLevel ++** ++** Set the debug level. ++** ++** INPUT: ++** ++** gctUINT32 Level ++** New debug level. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_SetDebugLevel( ++ IN gctUINT32 Level ++ ) ++{ ++ _debugLevel = Level; ++} ++ ++/******************************************************************************* ++** ++** gckOS_SetDebugZone ++** ++** Set the debug zone. ++** ++** INPUT: ++** ++** gctUINT32 Zone ++** New debug zone. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++void ++gckOS_SetDebugZone( ++ IN gctUINT32 Zone ++ ) ++{ ++ _debugZones = Zone; ++} ++ ++/******************************************************************************* ++** ++** gckOS_SetDebugLevelZone ++** ++** Set the debug level and zone. ++** ++** INPUT: ++** ++** gctUINT32 Level ++** New debug level. ++** ++** gctUINT32 Zone ++** New debug zone. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_SetDebugLevelZone( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone ++ ) ++{ ++ _debugLevel = Level; ++ _debugZones = Zone; ++} ++ ++/******************************************************************************* ++** ++** gckOS_SetDebugZones ++** ++** Enable or disable debug zones. ++** ++** INPUT: ++** ++** gctUINT32 Zones ++** Debug zones to enable or disable. ++** ++** gctBOOL Enable ++** Set to gcvTRUE to enable the zones (or the Zones with the current ++** zones) or gcvFALSE to disable the specified Zones. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_SetDebugZones( ++ IN gctUINT32 Zones, ++ IN gctBOOL Enable ++ ) ++{ ++ if (Enable) ++ { ++ /* Enable the zones. */ ++ _debugZones |= Zones; ++ } ++ else ++ { ++ /* Disable the zones. */ ++ _debugZones &= ~Zones; ++ } ++} ++ ++/******************************************************************************* ++** ++** gckOS_Verify ++** ++** Called to verify the result of a function call. ++** ++** INPUT: ++** ++** gceSTATUS Status ++** Function call result. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_Verify( ++ IN gceSTATUS status ++ ) ++{ ++ _lastError = status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_DebugFlush ++** ++** Force messages to be flushed out. ++** ++** INPUT: ++** ++** gctCONST_STRING CallerName ++** Name of the caller function. ++** ++** gctUINT LineNumber ++** Line number of the caller. ++** ++** gctUINT32 DmaAddress ++** The current DMA address or ~0U to ignore. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++void ++gckOS_DebugFlush( ++ gctCONST_STRING CallerName, ++ gctUINT LineNumber, ++ gctUINT32 DmaAddress ++ ) ++{ ++#if gcdBUFFERED_OUTPUT ++ _DirectPrint("\nFlush requested by %s(%d).\n\n", CallerName, LineNumber); ++ _Flush(DmaAddress); ++#endif ++} ++gctCONST_STRING ++gckOS_DebugStatus2Name( ++ gceSTATUS status ++ ) ++{ ++ switch (status) ++ { ++ case gcvSTATUS_OK: ++ return "gcvSTATUS_OK"; ++ case gcvSTATUS_TRUE: ++ return "gcvSTATUS_TRUE"; ++ case gcvSTATUS_NO_MORE_DATA: ++ return "gcvSTATUS_NO_MORE_DATA"; ++ case gcvSTATUS_CACHED: ++ return "gcvSTATUS_CACHED"; ++ case gcvSTATUS_MIPMAP_TOO_LARGE: ++ return "gcvSTATUS_MIPMAP_TOO_LARGE"; ++ case gcvSTATUS_NAME_NOT_FOUND: ++ return "gcvSTATUS_NAME_NOT_FOUND"; ++ case gcvSTATUS_NOT_OUR_INTERRUPT: ++ return "gcvSTATUS_NOT_OUR_INTERRUPT"; ++ case gcvSTATUS_MISMATCH: ++ return "gcvSTATUS_MISMATCH"; ++ case gcvSTATUS_MIPMAP_TOO_SMALL: ++ return "gcvSTATUS_MIPMAP_TOO_SMALL"; ++ case gcvSTATUS_LARGER: ++ return "gcvSTATUS_LARGER"; ++ case gcvSTATUS_SMALLER: ++ return "gcvSTATUS_SMALLER"; ++ case gcvSTATUS_CHIP_NOT_READY: ++ return "gcvSTATUS_CHIP_NOT_READY"; ++ case gcvSTATUS_NEED_CONVERSION: ++ return "gcvSTATUS_NEED_CONVERSION"; ++ case gcvSTATUS_SKIP: ++ return "gcvSTATUS_SKIP"; ++ case gcvSTATUS_DATA_TOO_LARGE: ++ return "gcvSTATUS_DATA_TOO_LARGE"; ++ case gcvSTATUS_INVALID_CONFIG: ++ return "gcvSTATUS_INVALID_CONFIG"; ++ case gcvSTATUS_CHANGED: ++ return "gcvSTATUS_CHANGED"; ++ case gcvSTATUS_NOT_SUPPORT_DITHER: ++ return "gcvSTATUS_NOT_SUPPORT_DITHER"; ++ ++ case gcvSTATUS_INVALID_ARGUMENT: ++ return "gcvSTATUS_INVALID_ARGUMENT"; ++ case gcvSTATUS_INVALID_OBJECT: ++ return "gcvSTATUS_INVALID_OBJECT"; ++ case gcvSTATUS_OUT_OF_MEMORY: ++ return "gcvSTATUS_OUT_OF_MEMORY"; ++ case gcvSTATUS_MEMORY_LOCKED: ++ return "gcvSTATUS_MEMORY_LOCKED"; ++ case gcvSTATUS_MEMORY_UNLOCKED: ++ return "gcvSTATUS_MEMORY_UNLOCKED"; ++ case gcvSTATUS_HEAP_CORRUPTED: ++ return "gcvSTATUS_HEAP_CORRUPTED"; ++ case gcvSTATUS_GENERIC_IO: ++ return "gcvSTATUS_GENERIC_IO"; ++ case gcvSTATUS_INVALID_ADDRESS: ++ return "gcvSTATUS_INVALID_ADDRESS"; ++ case gcvSTATUS_CONTEXT_LOSSED: ++ return "gcvSTATUS_CONTEXT_LOSSED"; ++ case gcvSTATUS_TOO_COMPLEX: ++ return "gcvSTATUS_TOO_COMPLEX"; ++ case gcvSTATUS_BUFFER_TOO_SMALL: ++ return "gcvSTATUS_BUFFER_TOO_SMALL"; ++ case gcvSTATUS_INTERFACE_ERROR: ++ return "gcvSTATUS_INTERFACE_ERROR"; ++ case gcvSTATUS_NOT_SUPPORTED: ++ return "gcvSTATUS_NOT_SUPPORTED"; ++ case gcvSTATUS_MORE_DATA: ++ return "gcvSTATUS_MORE_DATA"; ++ case gcvSTATUS_TIMEOUT: ++ return "gcvSTATUS_TIMEOUT"; ++ case gcvSTATUS_OUT_OF_RESOURCES: ++ return "gcvSTATUS_OUT_OF_RESOURCES"; ++ case gcvSTATUS_INVALID_DATA: ++ return "gcvSTATUS_INVALID_DATA"; ++ case gcvSTATUS_INVALID_MIPMAP: ++ return "gcvSTATUS_INVALID_MIPMAP"; ++ case gcvSTATUS_NOT_FOUND: ++ return "gcvSTATUS_NOT_FOUND"; ++ case gcvSTATUS_NOT_ALIGNED: ++ return "gcvSTATUS_NOT_ALIGNED"; ++ case gcvSTATUS_INVALID_REQUEST: ++ return "gcvSTATUS_INVALID_REQUEST"; ++ case gcvSTATUS_GPU_NOT_RESPONDING: ++ return "gcvSTATUS_GPU_NOT_RESPONDING"; ++ case gcvSTATUS_TIMER_OVERFLOW: ++ return "gcvSTATUS_TIMER_OVERFLOW"; ++ case gcvSTATUS_VERSION_MISMATCH: ++ return "gcvSTATUS_VERSION_MISMATCH"; ++ case gcvSTATUS_LOCKED: ++ return "gcvSTATUS_LOCKED"; ++ case gcvSTATUS_INTERRUPTED: ++ return "gcvSTATUS_INTERRUPTED"; ++ case gcvSTATUS_DEVICE: ++ return "gcvSTATUS_DEVICE"; ++ case gcvSTATUS_NOT_MULTI_PIPE_ALIGNED: ++ return "gcvSTATUS_NOT_MULTI_PIPE_ALIGNED"; ++ ++ /* Linker errors. */ ++ case gcvSTATUS_GLOBAL_TYPE_MISMATCH: ++ return "gcvSTATUS_GLOBAL_TYPE_MISMATCH"; ++ case gcvSTATUS_TOO_MANY_ATTRIBUTES: ++ return "gcvSTATUS_TOO_MANY_ATTRIBUTES"; ++ case gcvSTATUS_TOO_MANY_UNIFORMS: ++ return "gcvSTATUS_TOO_MANY_UNIFORMS"; ++ case gcvSTATUS_TOO_MANY_SAMPLER: ++ return "gcvSTATUS_TOO_MANY_SAMPLER"; ++ case gcvSTATUS_TOO_MANY_VARYINGS: ++ return "gcvSTATUS_TOO_MANY_VARYINGS"; ++ case gcvSTATUS_UNDECLARED_VARYING: ++ return "gcvSTATUS_UNDECLARED_VARYING"; ++ case gcvSTATUS_VARYING_TYPE_MISMATCH: ++ return "gcvSTATUS_VARYING_TYPE_MISMATCH"; ++ case gcvSTATUS_MISSING_MAIN: ++ return "gcvSTATUS_MISSING_MAIN"; ++ case gcvSTATUS_NAME_MISMATCH: ++ return "gcvSTATUS_NAME_MISMATCH"; ++ case gcvSTATUS_INVALID_INDEX: ++ return "gcvSTATUS_INVALID_INDEX"; ++ case gcvSTATUS_UNIFORM_MISMATCH: ++ return "gcvSTATUS_UNIFORM_MISMATCH"; ++ case gcvSTATUS_UNSAT_LIB_SYMBOL: ++ return "gcvSTATUS_UNSAT_LIB_SYMBOL"; ++ case gcvSTATUS_TOO_MANY_SHADERS: ++ return "gcvSTATUS_TOO_MANY_SHADERS"; ++ case gcvSTATUS_LINK_INVALID_SHADERS: ++ return "gcvSTATUS_LINK_INVALID_SHADERS"; ++ case gcvSTATUS_CS_NO_WORKGROUP_SIZE: ++ return "gcvSTATUS_CS_NO_WORKGROUP_SIZE"; ++ case gcvSTATUS_LINK_LIB_ERROR: ++ return "gcvSTATUS_LINK_LIB_ERROR"; ++ case gcvSTATUS_SHADER_VERSION_MISMATCH: ++ return "gcvSTATUS_SHADER_VERSION_MISMATCH"; ++ case gcvSTATUS_TOO_MANY_INSTRUCTION: ++ return "gcvSTATUS_TOO_MANY_INSTRUCTION"; ++ case gcvSTATUS_SSBO_MISMATCH: ++ return "gcvSTATUS_SSBO_MISMATCH"; ++ case gcvSTATUS_TOO_MANY_OUTPUT: ++ return "gcvSTATUS_TOO_MANY_OUTPUT"; ++ case gcvSTATUS_TOO_MANY_INPUT: ++ return "gcvSTATUS_TOO_MANY_INPUT"; ++ case gcvSTATUS_NOT_SUPPORT_CL: ++ return "gcvSTATUS_NOT_SUPPORT_CL"; ++ case gcvSTATUS_NOT_SUPPORT_INTEGER: ++ return "gcvSTATUS_NOT_SUPPORT_INTEGER"; ++ ++ /* Compiler errors. */ ++ case gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR: ++ return "gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR"; ++ case gcvSTATUS_COMPILER_FE_PARSER_ERROR: ++ return "gcvSTATUS_COMPILER_FE_PARSER_ERROR"; ++ ++ default: ++ return "nil"; ++ } ++} ++ ++/******************************************************************************* ++***** Binary Trace ************************************************************* ++*******************************************************************************/ ++ ++/******************************************************************************* ++** _VerifyMessage ++** ++** Verify a binary trace message, decode it to human readable string and print ++** it. ++** ++** ARGUMENTS: ++** ++** gctCONST_STRING Buffer ++** Pointer to buffer to store. ++** ++** gctSIZE_T Bytes ++** Buffer length. ++*/ ++void ++_VerifyMessage( ++ IN gctCONST_STRING Buffer, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ char arguments[150] = {0}; ++ char format[100] = {0}; ++ ++ gctSTRING function; ++ gctPOINTER args; ++ gctUINT32 numArguments; ++ int i = 0; ++ gctUINT32 functionBytes; ++ ++ gcsBINARY_TRACE_MESSAGE_PTR message = (gcsBINARY_TRACE_MESSAGE_PTR)Buffer; ++ ++ /* Check signature. */ ++ if (message->signature != 0x7FFFFFFF) ++ { ++ gcmkPRINT("Signature error"); ++ return; ++ } ++ ++ /* Get function name. */ ++ function = (gctSTRING)&message->payload; ++ functionBytes = (gctUINT32)strlen(function) + 1; ++ ++ /* Get arguments number. */ ++ numArguments = message->numArguments; ++ ++ /* Get arguments . */ ++ args = function + functionBytes; ++ ++ /* Prepare format string. */ ++ while (numArguments--) ++ { ++ format[i++] = '%'; ++ format[i++] = 'x'; ++ format[i++] = ' '; ++ } ++ ++ format[i] = '\0'; ++ ++ if (numArguments) ++ { ++ gcmkVSPRINTF(arguments, 150, format, (gctARGUMENTS *) &args); ++ } ++ ++ gcmkPRINT("[%d](%d): %s(%d) %s", ++ message->pid, ++ message->tid, ++ function, ++ message->line, ++ arguments); ++} ++ ++ ++/******************************************************************************* ++** gckOS_WriteToRingBuffer ++** ++** Store a buffer to ring buffer. ++** ++** ARGUMENTS: ++** ++** gctCONST_STRING Buffer ++** Pointer to buffer to store. ++** ++** gctSIZE_T Bytes ++** Buffer length. ++*/ ++void ++gckOS_WriteToRingBuffer( ++ IN gctCONST_STRING Buffer, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ ++} ++ ++/******************************************************************************* ++** gckOS_BinaryTrace ++** ++** Output a binary trace message. ++** ++** ARGUMENTS: ++** ++** gctCONST_STRING Function ++** Pointer to function name. ++** ++** gctINT Line ++** Line number. ++** ++** gctCONST_STRING Text OPTIONAL ++** Optional pointer to a descriptive text. ++** ++** ... ++** Optional arguments to the descriptive text. ++*/ ++void ++gckOS_BinaryTrace( ++ IN gctCONST_STRING Function, ++ IN gctINT Line, ++ IN gctCONST_STRING Text OPTIONAL, ++ ... ++ ) ++{ ++ static gctUINT32 messageSignature = 0x7FFFFFFF; ++ char buffer[gcdBINARY_TRACE_MESSAGE_SIZE]; ++ gctUINT32 numArguments = 0; ++ gctUINT32 functionBytes; ++ gctUINT32 i = 0; ++ gctSTRING payload; ++ gcsBINARY_TRACE_MESSAGE_PTR message = (gcsBINARY_TRACE_MESSAGE_PTR)buffer; ++ ++ /* Calculate arguments number. */ ++ if (Text) ++ { ++ while (Text[i] != '\0') ++ { ++ if (Text[i] == '%') ++ { ++ numArguments++; ++ } ++ i++; ++ } ++ } ++ ++ message->signature = messageSignature; ++ message->pid = gcmkGETPROCESSID(); ++ message->tid = gcmkGETTHREADID(); ++ message->line = Line; ++ message->numArguments = numArguments; ++ ++ payload = (gctSTRING)&message->payload; ++ ++ /* Function name. */ ++ functionBytes = (gctUINT32)gcmkSTRLEN(Function) + 1; ++ gcmkMEMCPY(payload, Function, functionBytes); ++ ++ /* Advance to next payload. */ ++ payload += functionBytes; ++ ++ /* Arguments value. */ ++ if (numArguments) ++ { ++ gctARGUMENTS p; ++ gcmkARGUMENTS_START(p, Text); ++ ++ for (i = 0; i < numArguments; ++i) ++ { ++ gctPOINTER value = gcmkARGUMENTS_ARG(p, gctPOINTER); ++ gcmkMEMCPY(payload, &value, gcmSIZEOF(gctPOINTER)); ++ payload += gcmSIZEOF(gctPOINTER); ++ } ++ ++ gcmkARGUMENTS_END(p); ++ } ++ ++ gcmkASSERT(payload - buffer <= gcdBINARY_TRACE_MESSAGE_SIZE); ++ ++ ++ /* Send buffer to ring buffer. */ ++ gckOS_WriteToRingBuffer(buffer, (gctUINT32)(payload - buffer)); ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debugfs.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debugfs.c 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,1137 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifdef MODULE ++#include ++#endif ++#include ++#include ++#include ++#ifdef MODVERSIONS ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "gc_hal_kernel_linux.h" ++#include "gc_hal_kernel.h" ++ ++/* ++ Prequsite: ++ ++ 1) Debugfs feature must be enabled in the kernel. ++ 1.a) You can enable this, in the compilation of the uImage, all you have to do is, In the "make menuconfig" part, ++ you have to enable the debugfs in the kernel hacking part of the menu. ++ ++ HOW TO USE: ++ 1) insert the driver with the following option logFileSize, Ex: insmod galcore.ko ...... logFileSize=10240 ++ This gives a circular buffer of 10 MB ++ ++ 2)Usually after inserting the driver, the debug file system is mounted under /sys/kernel/debug/ ++ ++ 2.a)If the debugfs is not mounted, you must do "mount -t debugfs none /sys/kernel/debug" ++ ++ 3) To read what is being printed in the debugfs file system: ++ Ex : cat /sys/kernel/debug/gc/galcore_trace ++ ++ 4)To write into the debug file system from user side : ++ Ex: echo "hello" > cat /sys/kernel/debug/gc/galcore_trace ++ ++ 5)To write into debugfs from kernel side, Use the function called gckDEBUGFS_Print ++ ++ How to Get Video Memory Usage: ++ 1) Select a process whose video memory usage can be dump, no need to reset it until is needed to be change. ++ echo > /sys/kernel/debug/gc/vidmem ++ ++ 2) Get video memory usage. ++ cat /sys/kernel/debug/gc/vidmem ++ ++ USECASE Kernel Dump: ++ ++ 1) Go to /hal/inc/gc_hal_options.h, and enable the following flags: ++ - # define gcdDUMP 1 ++ - # define gcdDUMP_IN_KERNEL 1 ++ - # define gcdDUMP_COMMAND 1 ++ ++ 2) Go to /hal/kernel/gc_hal_kernel_command.c and disable the following flag ++ -#define gcdSIMPLE_COMMAND_DUMP 0 ++ ++ 3) Compile the driver ++ 4) insmod it with the logFileSize option ++ 5) Run an application ++ 6) You can get the dump by cat /sys/kernel/debug/gpu/galcore_trace ++ ++ */ ++ ++/**/ ++typedef va_list gctDBGARGS ; ++#define gcmkARGS_START(argument, pointer) va_start(argument, pointer) ++#define gcmkARGS_END(argument) va_end(argument) ++ ++#define gcmkDEBUGFS_PRINT(ArgumentSize, Message) \ ++ { \ ++ gctDBGARGS __arguments__; \ ++ gcmkARGS_START(__arguments__, Message); \ ++ _debugfs_res = _DebugFSPrint(ArgumentSize, Message, &__arguments__);\ ++ gcmkARGS_END(__arguments__); \ ++ } ++ ++/* Debug File System Node Struct. */ ++struct _gcsDEBUGFS_Node ++{ ++ /*wait queues for read and write operations*/ ++#if defined(DECLARE_WAIT_QUEUE_HEAD) ++ wait_queue_head_t read_q , write_q ; ++#else ++ struct wait_queue *read_q , *write_q ; ++#endif ++ struct dentry *parent ; /*parent directory*/ ++ struct dentry *filen ; /*filename*/ ++ struct dentry *vidmem; ++ struct semaphore sem ; /* mutual exclusion semaphore */ ++ char *data ; /* The circular buffer data */ ++ int size ; /* Size of the buffer pointed to by 'data' */ ++ int refcount ; /* Files that have this buffer open */ ++ int read_point ; /* Offset in circ. buffer of oldest data */ ++ int write_point ; /* Offset in circ. buffer of newest data */ ++ int offset ; /* Byte number of read_point in the stream */ ++ struct _gcsDEBUGFS_Node *next ; ++}; ++ ++/* amount of data in the queue */ ++#define gcmkNODE_QLEN(node) ( (node)->write_point >= (node)->read_point ? \ ++ (node)->write_point - (node)->read_point : \ ++ (node)->size - (node)->read_point + (node)->write_point) ++ ++/* byte number of the last byte in the queue */ ++#define gcmkNODE_FIRST_EMPTY_BYTE(node) ((node)->offset + gcmkNODE_QLEN(node)) ++ ++/*Synchronization primitives*/ ++#define gcmkNODE_READQ(node) (&((node)->read_q)) ++#define gcmkNODE_WRITEQ(node) (&((node)->write_q)) ++ ++/*Utilities*/ ++#define gcmkMIN(x, y) ((x) < (y) ? (x) : y) ++ ++/*Debug File System Struct*/ ++typedef struct _gcsDEBUGFS_ ++{ ++ gcsDEBUGFS_Node* linkedlist ; ++ gcsDEBUGFS_Node* currentNode ; ++ int isInited ; ++} gcsDEBUGFS_ ; ++ ++/*debug file system*/ ++static gcsDEBUGFS_ gc_dbgfs ; ++ ++static int gc_debugfs_open(struct inode *inode, struct file *file) ++{ ++ gcsINFO_NODE *node = inode->i_private; ++ ++ return single_open(file, node->info->show, node); ++} ++ ++static const struct file_operations gc_debugfs_operations = { ++ .owner = THIS_MODULE, ++ .open = gc_debugfs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++gceSTATUS ++gckDEBUGFS_DIR_Init( ++ IN gckDEBUGFS_DIR Dir, ++ IN struct dentry *root, ++ IN gctCONST_STRING Name ++ ) ++{ ++ Dir->root = debugfs_create_dir(Name, root); ++ ++ if (!Dir->root) ++ { ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ INIT_LIST_HEAD(&Dir->nodeList); ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckDEBUGFS_DIR_CreateFiles( ++ IN gckDEBUGFS_DIR Dir, ++ IN gcsINFO * List, ++ IN int count, ++ IN gctPOINTER Data ++ ) ++{ ++ int i; ++ gcsINFO_NODE * node; ++ gceSTATUS status; ++ ++ for (i = 0; i < count; i++) ++ { ++ /* Create a node. */ ++ node = (gcsINFO_NODE *)kzalloc(sizeof(gcsINFO_NODE), GFP_KERNEL); ++ ++ node->info = &List[i]; ++ node->device = Data; ++ ++ /* Bind to a file. TODO: clean up when fail. */ ++ node->entry = debugfs_create_file( ++ List[i].name, S_IRUGO|S_IWUSR, Dir->root, node, &gc_debugfs_operations); ++ ++ if (!node->entry) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ list_add(&(node->head), &(Dir->nodeList)); ++ } ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(Dir, List, count)); ++ return status; ++} ++ ++gceSTATUS ++gckDEBUGFS_DIR_RemoveFiles( ++ IN gckDEBUGFS_DIR Dir, ++ IN gcsINFO * List, ++ IN int count ++ ) ++{ ++ int i; ++ gcsINFO_NODE * node; ++ gcsINFO_NODE * temp; ++ ++ for (i = 0; i < count; i++) ++ { ++ list_for_each_entry_safe(node, temp, &Dir->nodeList, head) ++ { ++ if (node->info == &List[i]) ++ { ++ debugfs_remove(node->entry); ++ list_del(&node->head); ++ kfree(node); ++ } ++ } ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++void ++gckDEBUGFS_DIR_Deinit( ++ IN gckDEBUGFS_DIR Dir ++ ) ++{ ++ if (Dir->root != NULL) ++ { ++ debugfs_remove(Dir->root); ++ Dir->root = NULL; ++ } ++} ++ ++/******************************************************************************* ++ ** ++ ** READ & WRITE FUNCTIONS (START) ++ ** ++ *******************************************************************************/ ++ ++/******************************************************************************* ++ ** ++ ** _ReadFromNode ++ ** ++ ** 1) reading bytes out of a circular buffer with wraparound. ++ ** 2)returns caddr_t, pointer to data read, which the caller must free. ++ ** 3) length is (a pointer to) the number of bytes to be read, which will be set by this function to ++ ** be the number of bytes actually returned ++ ** ++ *******************************************************************************/ ++static caddr_t ++_ReadFromNode ( ++ gcsDEBUGFS_Node* Node , ++ size_t *Length , ++ loff_t *Offset ++ ) ++{ ++ caddr_t retval ; ++ int bytes_copied = 0 , n , start_point , remaining ; ++ ++ /* is the user trying to read data that has already scrolled off? */ ++ if ( *Offset < Node->offset ) ++ { ++ *Offset = Node->offset ; ++ } ++ ++ /* is the user trying to read past EOF? */ ++ if ( *Offset >= gcmkNODE_FIRST_EMPTY_BYTE ( Node ) ) ++ { ++ return NULL ; ++ } ++ ++ /* find the smaller of the total bytes we have available and what ++ * the user is asking for */ ++ ++ *Length = gcmkMIN ( *Length , gcmkNODE_FIRST_EMPTY_BYTE ( Node ) - *Offset ) ; ++ ++ remaining = * Length ; ++ ++ /* figure out where to start based on user's Offset */ ++ start_point = Node->read_point + ( *Offset - Node->offset ) ; ++ ++ start_point = start_point % Node->size ; ++ ++ /* allocate memory to return */ ++ if ( ( retval = kmalloc ( sizeof (char ) * remaining , GFP_KERNEL ) ) == NULL ) ++ return NULL ; ++ ++ /* copy the (possibly noncontiguous) data to our buffer */ ++ while ( remaining ) ++ { ++ n = gcmkMIN ( remaining , Node->size - start_point ) ; ++ memcpy ( retval + bytes_copied , Node->data + start_point , n ) ; ++ bytes_copied += n ; ++ remaining -= n ; ++ start_point = ( start_point + n ) % Node->size ; ++ } ++ ++ /* advance user's file pointer */ ++ *Offset += * Length ; ++ ++ return retval ; ++} ++ ++/******************************************************************************* ++ ** ++ ** _WriteToNode ++ ** ++ ** 1) writes to a circular buffer with wraparound. ++ ** 2)in case of an overflow, it overwrites the oldest unread data. ++ ** ++ *********************************************************************************/ ++static void ++_WriteToNode ( ++ gcsDEBUGFS_Node* Node , ++ caddr_t Buf , ++ int Length ++ ) ++{ ++ int bytes_copied = 0 ; ++ int overflow = 0 ; ++ int n ; ++ ++ if ( Length + gcmkNODE_QLEN ( Node ) >= ( Node->size - 1 ) ) ++ { ++ overflow = 1 ; ++ ++ /* in case of overflow, figure out where the new buffer will ++ * begin. we start by figuring out where the current buffer ENDS: ++ * node->parent->offset + gcmkNODE_QLEN. we then advance the end-offset ++ * by the Length of the current write, and work backwards to ++ * figure out what the oldest unoverwritten data will be (i.e., ++ * size of the buffer). */ ++ Node->offset = Node->offset + gcmkNODE_QLEN ( Node ) + Length ++ - Node->size + 1 ; ++ } ++ ++ while ( Length ) ++ { ++ /* how many contiguous bytes are available from the write point to ++ * the end of the circular buffer? */ ++ n = gcmkMIN ( Length , Node->size - Node->write_point ) ; ++ memcpy ( Node->data + Node->write_point , Buf + bytes_copied , n ) ; ++ bytes_copied += n ; ++ Length -= n ; ++ Node->write_point = ( Node->write_point + n ) % Node->size ; ++ } ++ ++ /* if there is an overflow, reset the read point to read whatever is ++ * the oldest data that we have, that has not yet been ++ * overwritten. */ ++ if ( overflow ) ++ { ++ Node->read_point = ( Node->write_point + 1 ) % Node->size ; ++ } ++} ++ ++/******************************************************************************* ++ ** ++ ** PRINTING UTILITY (START) ++ ** ++ *******************************************************************************/ ++ ++/******************************************************************************* ++ ** ++ ** _GetArgumentSize ++ ** ++ ** ++ *******************************************************************************/ ++static gctINT ++_GetArgumentSize ( ++ IN gctCONST_STRING Message ++ ) ++{ ++ gctINT i , count ; ++ ++ for ( i = 0 , count = 0 ; Message[i] ; i += 1 ) ++ { ++ if ( Message[i] == '%' ) ++ { ++ count += 1 ; ++ } ++ } ++ return count * sizeof (unsigned int ) ; ++} ++ ++/******************************************************************************* ++ ** ++ ** _AppendString ++ ** ++ ** ++ *******************************************************************************/ ++static ssize_t ++_AppendString ( ++ IN gcsDEBUGFS_Node* Node , ++ IN gctCONST_STRING String , ++ IN int Length ++ ) ++{ ++ caddr_t message = NULL ; ++ int n ; ++ ++ /* if the message is longer than the buffer, just take the beginning ++ * of it, in hopes that the reader (if any) will have time to read ++ * before we wrap around and obliterate it */ ++ n = gcmkMIN ( Length , Node->size - 1 ) ; ++ ++ /* make sure we have the memory for it */ ++ if ( ( message = kmalloc ( n , GFP_ATOMIC ) ) == NULL ) ++ return - ENOMEM ; ++ ++ /* copy into our temp buffer */ ++ memcpy ( message , String , n ) ; ++ ++ /* now copy it into the circular buffer and free our temp copy */ ++ _WriteToNode ( Node , message , n ) ; ++ kfree ( message ) ; ++ return n ; ++} ++ ++/******************************************************************************* ++ ** ++ ** _DebugFSPrint ++ ** ++ ** ++ *******************************************************************************/ ++static ssize_t ++_DebugFSPrint ( ++ IN unsigned int ArgumentSize , ++ IN const char* Message , ++ IN gctDBGARGS * Arguments ++ ++ ) ++{ ++ char buffer[MAX_LINE_SIZE] ; ++ int len ; ++ ssize_t res=0; ++ ++ if(in_interrupt()) ++ { ++ return - ERESTARTSYS ; ++ } ++ ++ len = vsnprintf ( buffer , sizeof (buffer ) , Message , *( va_list * ) Arguments ) ; ++ buffer[len] = '\0' ; ++ ++ /* Add end-of-line if missing. */ ++ if ( buffer[len - 1] != '\n' ) ++ { ++ buffer[len ++] = '\n' ; ++ buffer[len] = '\0' ; ++ } ++ res = _AppendString ( gc_dbgfs.currentNode , buffer , len ) ; ++ wake_up ( gcmkNODE_READQ ( gc_dbgfs.currentNode ) ) ; /* blocked in read*/ ++ return res; ++} ++ ++/******************************************************************************* ++ ** ++ ** LINUX SYSTEM FUNCTIONS (START) ++ ** ++ *******************************************************************************/ ++ ++/******************************************************************************* ++ ** ++ ** find the vivlog structure associated with an inode. ++ ** returns a pointer to the structure if found, NULL if not found ++ ** ++ *******************************************************************************/ ++static gcsDEBUGFS_Node* ++_GetNodeInfo ( ++ IN struct inode *Inode ++ ) ++{ ++ gcsDEBUGFS_Node* node ; ++ ++ if ( Inode == NULL ) ++ return NULL ; ++ ++ for ( node = gc_dbgfs.linkedlist ; node != NULL ; node = node->next ) ++ if ( node->filen->d_inode->i_ino == Inode->i_ino ) ++ return node ; ++ ++ return NULL ; ++} ++ ++/******************************************************************************* ++ ** ++ ** _DebugFSRead ++ ** ++ *******************************************************************************/ ++static ssize_t ++_DebugFSRead ( ++ struct file *file , ++ char __user * buffer , ++ size_t length , ++ loff_t * offset ++ ) ++{ ++ int retval ; ++ caddr_t data_to_return ; ++ gcsDEBUGFS_Node* node ; ++ /* get the metadata about this emlog */ ++ if ( ( node = _GetNodeInfo ( file->f_path.dentry->d_inode ) ) == NULL ) ++ { ++ printk ( "debugfs_read: record not found\n" ) ; ++ return - EIO ; ++ } ++ ++ /* wait until there's data available (unless we do nonblocking reads) */ ++ while ( *offset >= gcmkNODE_FIRST_EMPTY_BYTE ( node ) ) ++ { ++ if ( file->f_flags & O_NONBLOCK ) ++ { ++ return - EAGAIN ; ++ } ++ if ( wait_event_interruptible ( ( *( gcmkNODE_READQ ( node ) ) ) , ( *offset < gcmkNODE_FIRST_EMPTY_BYTE ( node ) ) ) ) ++ { ++ return - ERESTARTSYS ; /* signal: tell the fs layer to handle it */ ++ } ++ } ++ data_to_return = _ReadFromNode ( node , &length , offset ) ; ++ if ( data_to_return == NULL ) ++ { ++ retval = 0 ; ++ goto unlock ; ++ } ++ if ( copy_to_user ( buffer , data_to_return , length ) > 0 ) ++ { ++ retval = - EFAULT ; ++ } ++ else ++ { ++ retval = length ; ++ } ++ kfree ( data_to_return ) ; ++unlock: ++ wake_up_interruptible ( gcmkNODE_WRITEQ ( node ) ) ; ++ return retval ; ++} ++ ++/******************************************************************************* ++ ** ++ **_DebugFSWrite ++ ** ++ *******************************************************************************/ ++static ssize_t ++_DebugFSWrite ( ++ struct file *file , ++ const char __user * buffer , ++ size_t length , ++ loff_t * offset ++ ) ++{ ++ caddr_t message = NULL ; ++ int n ; ++ gcsDEBUGFS_Node*node ; ++ ++ /* get the metadata about this log */ ++ if ( ( node = _GetNodeInfo ( file->f_path.dentry->d_inode ) ) == NULL ) ++ { ++ return - EIO ; ++ } ++ ++ /* if the message is longer than the buffer, just take the beginning ++ * of it, in hopes that the reader (if any) will have time to read ++ * before we wrap around and obliterate it */ ++ n = gcmkMIN ( length , node->size - 1 ) ; ++ ++ /* make sure we have the memory for it */ ++ if ( ( message = kmalloc ( n , GFP_KERNEL ) ) == NULL ) ++ { ++ return - ENOMEM ; ++ } ++ ++ ++ /* copy into our temp buffer */ ++ if ( copy_from_user ( message , buffer , n ) > 0 ) ++ { ++ kfree ( message ) ; ++ return - EFAULT ; ++ } ++ ++ /* now copy it into the circular buffer and free our temp copy */ ++ _WriteToNode ( node , message , n ) ; ++ ++ kfree ( message ) ; ++ ++ /* wake up any readers that might be waiting for the data. we call ++ * schedule in the vague hope that a reader will run before the ++ * writer's next write, to avoid losing data. */ ++ wake_up_interruptible ( gcmkNODE_READQ ( node ) ) ; ++ ++ return n ; ++} ++ ++int dumpProcess = 0; ++ ++void ++_PrintCounter( ++ struct seq_file *file, ++ gcsDATABASE_COUNTERS * counter, ++ gctCONST_STRING Name ++ ) ++{ ++ seq_printf(file,"Counter: %s\n", Name); ++ ++ seq_printf(file,"%-9s%10s","", "All"); ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Current"); ++ ++ seq_printf(file,"%10lld", counter->bytes); ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Maximum"); ++ ++ seq_printf(file,"%10lld", counter->maxBytes); ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Total"); ++ ++ seq_printf(file,"%10lld", counter->totalBytes); ++ ++ seq_printf(file, "\n"); ++} ++ ++void ++_ShowCounters( ++ struct seq_file *file, ++ gcsDATABASE_PTR database ++ ) ++{ ++ gctUINT i = 0; ++ gcsDATABASE_COUNTERS * counter; ++ gcsDATABASE_COUNTERS * nonPaged; ++ ++ static gctCONST_STRING surfaceTypes[] = { ++ "UNKNOWN", ++ "Index", ++ "Vertex", ++ "Texture", ++ "RT", ++ "Depth", ++ "Bitmap", ++ "TS", ++ "Image", ++ "Mask", ++ "Scissor", ++ "HZDepth", ++ }; ++ ++ /* Get pointer to counters. */ ++ counter = &database->vidMem; ++ ++ nonPaged = &database->nonPaged; ++ ++ seq_printf(file,"Counter: vidMem (for each surface type)\n"); ++ ++ seq_printf(file,"%-9s%10s","", "All"); ++ ++ for (i = 1; i < gcvSURF_NUM_TYPES; i++) ++ { ++ counter = &database->vidMemType[i]; ++ ++ seq_printf(file, "%10s",surfaceTypes[i]); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Current"); ++ ++ seq_printf(file,"%10lld", database->vidMem.bytes); ++ ++ for (i = 1; i < gcvSURF_NUM_TYPES; i++) ++ { ++ counter = &database->vidMemType[i]; ++ ++ seq_printf(file,"%10lld", counter->bytes); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Maximum"); ++ ++ seq_printf(file,"%10lld", database->vidMem.maxBytes); ++ ++ for (i = 1; i < gcvSURF_NUM_TYPES; i++) ++ { ++ counter = &database->vidMemType[i]; ++ ++ seq_printf(file,"%10lld", counter->maxBytes); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Total"); ++ ++ seq_printf(file,"%10lld", database->vidMem.totalBytes); ++ ++ for (i = 1; i < gcvSURF_NUM_TYPES; i++) ++ { ++ counter = &database->vidMemType[i]; ++ ++ seq_printf(file,"%10lld", counter->totalBytes); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"Counter: vidMem (for each pool)\n"); ++ ++ seq_printf(file,"%-9s%10s","", "All"); ++ ++ for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++) ++ { ++ seq_printf(file, "%10d", i); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Current"); ++ ++ seq_printf(file,"%10lld", database->vidMem.bytes); ++ ++ for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++) ++ { ++ counter = &database->vidMemPool[i]; ++ ++ seq_printf(file,"%10lld", counter->bytes); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Maximum"); ++ ++ seq_printf(file,"%10lld", database->vidMem.maxBytes); ++ ++ for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++) ++ { ++ counter = &database->vidMemPool[i]; ++ ++ seq_printf(file,"%10lld", counter->maxBytes); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ seq_printf(file,"%-9s","Total"); ++ ++ seq_printf(file,"%10lld", database->vidMem.totalBytes); ++ ++ for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++) ++ { ++ counter = &database->vidMemPool[i]; ++ ++ seq_printf(file,"%10lld", counter->totalBytes); ++ } ++ ++ seq_printf(file, "\n"); ++ ++ /* Print nonPaged. */ ++ _PrintCounter(file, &database->nonPaged, "nonPaged"); ++ _PrintCounter(file, &database->contiguous, "contiguous"); ++ _PrintCounter(file, &database->mapUserMemory, "mapUserMemory"); ++ _PrintCounter(file, &database->mapMemory, "mapMemory"); ++} ++ ++gckKERNEL ++_GetValidKernel( ++ gckGALDEVICE Device ++); ++static int vidmem_show(struct seq_file *file, void *unused) ++{ ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gckGALDEVICE device = file->private; ++ ++ gckKERNEL kernel = _GetValidKernel(device); ++ if(kernel == gcvNULL) ++ { ++ return 0; ++ } ++ ++ /* Find the database. */ ++ gcmkONERROR( ++ gckKERNEL_FindDatabase(kernel, dumpProcess, gcvFALSE, &database)); ++ ++ seq_printf(file, "VidMem Usage (Process %d):\n", dumpProcess); ++ ++ _ShowCounters(file, database); ++ ++ return 0; ++ ++OnError: ++ return 0; ++} ++ ++static int ++vidmem_open( ++ struct inode *inode, ++ struct file *file ++ ) ++{ ++ return single_open(file, vidmem_show, inode->i_private); ++} ++ ++static ssize_t ++vidmem_write( ++ struct file *file, ++ const char __user *buf, ++ size_t count, ++ loff_t *pos ++ ) ++{ ++ dumpProcess = simple_strtol(buf, NULL, 0); ++ return count; ++} ++ ++/******************************************************************************* ++ ** ++ ** File Operations Table ++ ** ++ *******************************************************************************/ ++static const struct file_operations debugfs_operations = { ++ .owner = THIS_MODULE , ++ .read = _DebugFSRead , ++ .write = _DebugFSWrite , ++} ; ++ ++static const struct file_operations vidmem_operations = { ++ .owner = THIS_MODULE , ++ .open = vidmem_open, ++ .read = seq_read, ++ .write = vidmem_write, ++ .llseek = seq_lseek, ++} ; ++ ++/******************************************************************************* ++ ** ++ ** INTERFACE FUNCTIONS (START) ++ ** ++ *******************************************************************************/ ++ ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_IsEnabled ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ *******************************************************************************/ ++ ++ ++gctINT ++gckDEBUGFS_IsEnabled ( void ) ++{ ++ return gc_dbgfs.isInited ; ++} ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_Initialize ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ *******************************************************************************/ ++ ++gctINT ++gckDEBUGFS_Initialize ( void ) ++{ ++ if ( ! gc_dbgfs.isInited ) ++ { ++ gc_dbgfs.linkedlist = gcvNULL ; ++ gc_dbgfs.currentNode = gcvNULL ; ++ gc_dbgfs.isInited = 1 ; ++ } ++ return gc_dbgfs.isInited ; ++} ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_Terminate ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ *******************************************************************************/ ++ ++gctINT ++gckDEBUGFS_Terminate ( void ) ++{ ++ gcsDEBUGFS_Node * next = gcvNULL ; ++ gcsDEBUGFS_Node * temp = gcvNULL ; ++ if ( gc_dbgfs.isInited ) ++ { ++ temp = gc_dbgfs.linkedlist ; ++ while ( temp != gcvNULL ) ++ { ++ next = temp->next ; ++ gckDEBUGFS_FreeNode ( temp ) ; ++ kfree ( temp ) ; ++ temp = next ; ++ } ++ gc_dbgfs.isInited = 0 ; ++ } ++ return 0 ; ++} ++ ++ ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_CreateNode ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ ** gckDEBUGFS_FreeNode * Device ++ ** Pointer to a variable receiving the gcsDEBUGFS_Node object pointer on ++ ** success. ++ *********************************************************************************/ ++ ++gctINT ++gckDEBUGFS_CreateNode ( ++ IN gctPOINTER Device, ++ IN gctINT SizeInKB , ++ IN struct dentry * Root , ++ IN gctCONST_STRING NodeName , ++ OUT gcsDEBUGFS_Node **Node ++ ) ++{ ++ gcsDEBUGFS_Node*node ; ++ /* allocate space for our metadata and initialize it */ ++ if ( ( node = kmalloc ( sizeof (gcsDEBUGFS_Node ) , GFP_KERNEL ) ) == NULL ) ++ goto struct_malloc_failed ; ++ ++ /*Zero it out*/ ++ memset ( node , 0 , sizeof (gcsDEBUGFS_Node ) ) ; ++ ++ /*Init the sync primitives*/ ++#if defined(DECLARE_WAIT_QUEUE_HEAD) ++ init_waitqueue_head ( gcmkNODE_READQ ( node ) ) ; ++#else ++ init_waitqueue ( gcmkNODE_READQ ( node ) ) ; ++#endif ++ ++#if defined(DECLARE_WAIT_QUEUE_HEAD) ++ init_waitqueue_head ( gcmkNODE_WRITEQ ( node ) ) ; ++#else ++ init_waitqueue ( gcmkNODE_WRITEQ ( node ) ) ; ++#endif ++ /*End the sync primitives*/ ++ ++ /*creating the debug file system*/ ++ node->parent = Root; ++ ++ if (SizeInKB) ++ { ++ /* figure out how much of a buffer this should be and allocate the buffer */ ++ node->size = 1024 * SizeInKB ; ++ if ( ( node->data = ( char * ) vmalloc ( sizeof (char ) * node->size ) ) == NULL ) ++ goto data_malloc_failed ; ++ ++ /*creating the file*/ ++ node->filen = debugfs_create_file(NodeName, S_IRUGO|S_IWUSR, node->parent, NULL, ++ &debugfs_operations); ++ } ++ ++ node->vidmem ++ = debugfs_create_file("vidmem", S_IRUGO|S_IWUSR, node->parent, Device, &vidmem_operations); ++ ++ /* add it to our linked list */ ++ node->next = gc_dbgfs.linkedlist ; ++ gc_dbgfs.linkedlist = node ; ++ ++ ++ /* pass the struct back */ ++ *Node = node ; ++ return 0 ; ++ ++ ++data_malloc_failed: ++ kfree ( node ) ; ++struct_malloc_failed: ++ return - ENOMEM ; ++} ++ ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_FreeNode ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ *******************************************************************************/ ++void ++gckDEBUGFS_FreeNode ( ++ IN gcsDEBUGFS_Node * Node ++ ) ++{ ++ ++ gcsDEBUGFS_Node **ptr ; ++ ++ if ( Node == NULL ) ++ { ++ printk ( "null passed to free_vinfo\n" ) ; ++ return ; ++ } ++ ++ /*free data*/ ++ vfree ( Node->data ) ; ++ ++ /*Close Debug fs*/ ++ if (Node->vidmem) ++ { ++ debugfs_remove(Node->vidmem); ++ } ++ ++ if ( Node->filen ) ++ { ++ debugfs_remove ( Node->filen ) ; ++ } ++ ++ /* now delete the node from the linked list */ ++ ptr = & ( gc_dbgfs.linkedlist ) ; ++ while ( *ptr != Node ) ++ { ++ if ( ! *ptr ) ++ { ++ printk ( "corrupt info list!\n" ) ; ++ break ; ++ } ++ else ++ ptr = & ( ( **ptr ).next ) ; ++ } ++ *ptr = Node->next ; ++} ++ ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_SetCurrentNode ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ *******************************************************************************/ ++void ++gckDEBUGFS_SetCurrentNode ( ++ IN gcsDEBUGFS_Node * Node ++ ) ++{ ++ gc_dbgfs.currentNode = Node ; ++} ++ ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_GetCurrentNode ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ *******************************************************************************/ ++void ++gckDEBUGFS_GetCurrentNode ( ++ OUT gcsDEBUGFS_Node ** Node ++ ) ++{ ++ *Node = gc_dbgfs.currentNode ; ++} ++ ++/******************************************************************************* ++ ** ++ ** gckDEBUGFS_Print ++ ** ++ ** ++ ** INPUT: ++ ** ++ ** OUTPUT: ++ ** ++ *******************************************************************************/ ++ssize_t ++gckDEBUGFS_Print ( ++ IN gctCONST_STRING Message , ++ ... ++ ) ++{ ++ ssize_t _debugfs_res; ++ gcmkDEBUGFS_PRINT ( _GetArgumentSize ( Message ) , Message ) ; ++ return _debugfs_res; ++} +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debugfs.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debugfs.h 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,135 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include ++ ++#ifndef __gc_hal_kernel_debugfs_h_ ++#define __gc_hal_kernel_debugfs_h_ ++ ++ #define MAX_LINE_SIZE 768 /* Max bytes for a line of debug info */ ++ ++ ++ typedef struct _gcsDEBUGFS_Node gcsDEBUGFS_Node; ++ ++typedef struct _gcsDEBUGFS_DIR *gckDEBUGFS_DIR; ++typedef struct _gcsDEBUGFS_DIR ++{ ++ struct dentry * root; ++ struct list_head nodeList; ++} ++gcsDEBUGFS_DIR; ++ ++typedef struct _gcsINFO ++{ ++ const char * name; ++ int (*show)(struct seq_file*, void*); ++} ++gcsINFO; ++ ++typedef struct _gcsINFO_NODE ++{ ++ gcsINFO * info; ++ gctPOINTER device; ++ struct dentry * entry; ++ struct list_head head; ++} ++gcsINFO_NODE; ++ ++gceSTATUS ++gckDEBUGFS_DIR_Init( ++ IN gckDEBUGFS_DIR Dir, ++ IN struct dentry *root, ++ IN gctCONST_STRING Name ++ ); ++ ++gceSTATUS ++gckDEBUGFS_DIR_CreateFiles( ++ IN gckDEBUGFS_DIR Dir, ++ IN gcsINFO * List, ++ IN int count, ++ IN gctPOINTER Data ++ ); ++ ++gceSTATUS ++gckDEBUGFS_DIR_RemoveFiles( ++ IN gckDEBUGFS_DIR Dir, ++ IN gcsINFO * List, ++ IN int count ++ ); ++ ++void ++gckDEBUGFS_DIR_Deinit( ++ IN gckDEBUGFS_DIR Dir ++ ); ++ ++/******************************************************************************* ++ ** ++ ** System Related ++ ** ++ *******************************************************************************/ ++ ++gctINT gckDEBUGFS_IsEnabled(void); ++ ++gctINT gckDEBUGFS_Initialize(void); ++ ++gctINT gckDEBUGFS_Terminate(void); ++ ++ ++/******************************************************************************* ++ ** ++ ** Node Related ++ ** ++ *******************************************************************************/ ++ ++gctINT ++gckDEBUGFS_CreateNode( ++ IN gctPOINTER Device, ++ IN gctINT SizeInKB, ++ IN struct dentry * Root, ++ IN gctCONST_STRING NodeName, ++ OUT gcsDEBUGFS_Node **Node ++ ); ++ ++void gckDEBUGFS_FreeNode( ++ IN gcsDEBUGFS_Node * Node ++ ); ++ ++ ++ ++void gckDEBUGFS_SetCurrentNode( ++ IN gcsDEBUGFS_Node * Node ++ ); ++ ++ ++ ++void gckDEBUGFS_GetCurrentNode( ++ OUT gcsDEBUGFS_Node ** Node ++ ); ++ ++ ++ssize_t gckDEBUGFS_Print( ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++#endif ++ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debug.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debug.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_debug.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_debug.h 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,103 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_debug_h_ ++#define __gc_hal_kernel_debug_h_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++****************************** OS-dependent Macros ***************************** ++\******************************************************************************/ ++ ++typedef va_list gctARGUMENTS; ++ ++#define gcmkARGUMENTS_START(Arguments, Pointer) \ ++ va_start(Arguments, Pointer) ++ ++#define gcmkARGUMENTS_END(Arguments) \ ++ va_end(Arguments) ++ ++#define gcmkARGUMENTS_ARG(Arguments, Type) \ ++ va_arg(Arguments, Type) ++ ++#define gcmkDECLARE_LOCK(__spinLock__) \ ++ static DEFINE_SPINLOCK(__spinLock__); \ ++ unsigned long __spinLock__##flags = 0; ++ ++#define gcmkLOCKSECTION(__spinLock__) \ ++ spin_lock_irqsave(&__spinLock__, __spinLock__##flags) ++ ++#define gcmkUNLOCKSECTION(__spinLock__) \ ++ spin_unlock_irqrestore(&__spinLock__, __spinLock__##flags) ++ ++# define gcmkGETPROCESSID() \ ++ task_tgid_vnr(current) ++ ++# define gcmkGETTHREADID() \ ++ task_pid_vnr(current) ++ ++#define gcmkOUTPUT_STRING(String) \ ++ if(gckDEBUGFS_IsEnabled()) {\ ++ while(-ERESTARTSYS == gckDEBUGFS_Print(String));\ ++ }else{\ ++ printk(String); \ ++ }\ ++ touch_softlockup_watchdog() ++ ++ ++#define gcmkSPRINTF(Destination, Size, Message, Value) \ ++ snprintf(Destination, Size, Message, Value) ++ ++#define gcmkSPRINTF2(Destination, Size, Message, Value1, Value2) \ ++ snprintf(Destination, Size, Message, Value1, Value2) ++ ++#define gcmkSPRINTF3(Destination, Size, Message, Value1, Value2, Value3) \ ++ snprintf(Destination, Size, Message, Value1, Value2, Value3) ++ ++#define gcmkVSPRINTF(Destination, Size, Message, Arguments) \ ++ vsnprintf(Destination, Size, Message, *((va_list*)Arguments)) ++ ++#define gcmkSTRCAT(Destination, Size, String) \ ++ strncat(Destination, String, Size) ++ ++#define gcmkMEMCPY(Destination, Source, Size) \ ++ memcpy(Destination, Source, Size) ++ ++#define gcmkSTRLEN(String) \ ++ strlen(String) ++ ++/* If not zero, forces data alignment in the variable argument list ++ by its individual size. */ ++#define gcdALIGNBYSIZE 1 ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_kernel_debug_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_device.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_device.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_device.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_device.c 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,1941 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++#include ++#include ++#include ++#include ++ ++#define _GC_OBJ_ZONE gcvZONE_DEVICE ++ ++#define DEBUG_FILE "galcore_trace" ++#define PARENT_FILE "gpu" ++ ++gckKERNEL ++_GetValidKernel( ++ gckGALDEVICE Device ++ ) ++{ ++ if (Device->kernels[gcvCORE_MAJOR]) ++ { ++ return Device->kernels[gcvCORE_MAJOR]; ++ } ++ else ++ if (Device->kernels[gcvCORE_2D]) ++ { ++ return Device->kernels[gcvCORE_2D]; ++ } ++ else ++ if (Device->kernels[gcvCORE_VG]) ++ { ++ return Device->kernels[gcvCORE_VG]; ++ } ++ else ++ { ++ return gcvNULL; ++ } ++} ++ ++/******************************************************************************\ ++******************************** Debugfs Support ******************************* ++\******************************************************************************/ ++ ++/******************************************************************************\ ++***************************** DEBUG SHOW FUNCTIONS ***************************** ++\******************************************************************************/ ++ ++int gc_info_show(struct seq_file* m, void* data) ++{ ++ gcsINFO_NODE *node = m->private; ++ gckGALDEVICE device = node->device; ++ int i = 0; ++ gceCHIPMODEL chipModel; ++ gctUINT32 chipRevision; ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (device->irqLines[i] != -1) ++ { ++#if gcdENABLE_VG ++ if (i == gcvCORE_VG) ++ { ++ chipModel = device->kernels[i]->vg->hardware->chipModel; ++ chipRevision = device->kernels[i]->vg->hardware->chipRevision; ++ } ++ else ++#endif ++ { ++ chipModel = device->kernels[i]->hardware->identity.chipModel; ++ chipRevision = device->kernels[i]->hardware->identity.chipRevision; ++ } ++ ++ seq_printf(m, "gpu : %d\n", i); ++ seq_printf(m, "model : %4x\n", chipModel); ++ seq_printf(m, "revision : %4x\n", chipRevision); ++ seq_printf(m, "\n"); ++ } ++ } ++ ++ return 0; ++} ++ ++int gc_clients_show(struct seq_file* m, void* data) ++{ ++ gcsINFO_NODE *node = m->private; ++ gckGALDEVICE device = node->device; ++ ++ gckKERNEL kernel = _GetValidKernel(device); ++ ++ gcsDATABASE_PTR database; ++ gctINT i, pid; ++ gctUINT8 name[24]; ++ ++ seq_printf(m, "%-8s%s\n", "PID", "NAME"); ++ seq_printf(m, "------------------------\n"); ++ ++ /* Acquire the database mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE)); ++ ++ /* Walk the databases. */ ++ for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i) ++ { ++ for (database = kernel->db->db[i]; ++ database != gcvNULL; ++ database = database->next) ++ { ++ pid = database->processID; ++ ++ gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name))); ++ ++ gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name)); ++ ++ seq_printf(m, "%-8d%s\n", pid, name); ++ } ++ } ++ ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex)); ++ ++ /* Success. */ ++ return 0; ++} ++ ++static void ++_CounterAdd( ++ gcsDATABASE_COUNTERS * Dest, ++ gcsDATABASE_COUNTERS * Src ++ ) ++{ ++ Dest->bytes += Src->bytes; ++ Dest->maxBytes += Src->maxBytes; ++ Dest->totalBytes += Src->totalBytes; ++} ++ ++static void ++_CounterPrint( ++ gcsDATABASE_COUNTERS * Counter, ++ gctCONST_STRING Name, ++ struct seq_file* m ++ ) ++{ ++ seq_printf(m, " %s:\n", Name); ++ seq_printf(m, " Used : %10llu B\n", Counter->bytes); ++} ++ ++int gc_meminfo_show(struct seq_file* m, void* data) ++{ ++ gcsINFO_NODE *node = m->private; ++ gckGALDEVICE device = node->device; ++ gckKERNEL kernel = _GetValidKernel(device); ++ gckVIDMEM memory; ++ gceSTATUS status; ++ gcsDATABASE_PTR database; ++ gctUINT32 i; ++ ++ gctUINT32 free = 0, used = 0, total = 0; ++ ++ gcsDATABASE_COUNTERS contiguousCounter = {0, 0, 0}; ++ gcsDATABASE_COUNTERS virtualCounter = {0, 0, 0}; ++ gcsDATABASE_COUNTERS nonPagedCounter = {0, 0, 0}; ++ ++ status = gckKERNEL_GetVideoMemoryPool(kernel, gcvPOOL_SYSTEM, &memory); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ gcmkVERIFY_OK( ++ gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE)); ++ ++ free = memory->freeBytes; ++ used = memory->bytes - memory->freeBytes; ++ total = memory->bytes; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex)); ++ } ++ ++ seq_printf(m, "VIDEO MEMORY:\n"); ++ seq_printf(m, " gcvPOOL_SYSTEM:\n"); ++ seq_printf(m, " Free : %10u B\n", free); ++ seq_printf(m, " Used : %10u B\n", used); ++ seq_printf(m, " Total : %10u B\n", total); ++ ++ /* Acquire the database mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE)); ++ ++ /* Walk the databases. */ ++ for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i) ++ { ++ for (database = kernel->db->db[i]; ++ database != gcvNULL; ++ database = database->next) ++ { ++ gcsDATABASE_COUNTERS * counter = &database->vidMemPool[gcvPOOL_CONTIGUOUS]; ++ _CounterAdd(&contiguousCounter, counter); ++ ++ counter = &database->vidMemPool[gcvPOOL_VIRTUAL]; ++ _CounterAdd(&virtualCounter, counter); ++ ++ ++ counter = &database->nonPaged; ++ _CounterAdd(&nonPagedCounter, counter); ++ } ++ } ++ ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex)); ++ ++ _CounterPrint(&contiguousCounter, "gcvPOOL_CONTIGUOUS", m); ++ _CounterPrint(&virtualCounter, "gcvPOOL_VIRTUAL", m); ++ ++ seq_printf(m, "\n"); ++ ++ seq_printf(m, "NON PAGED MEMORY:\n"); ++ seq_printf(m, " Used : %10llu B\n", nonPagedCounter.bytes); ++ ++ return 0; ++} ++ ++static int ++_ShowRecord( ++ IN struct seq_file *file, ++ IN gcsDATABASE_RECORD_PTR record ++ ) ++{ ++ seq_printf(file, "%4d%8d%16p%16p%16zu\n", ++ record->type, ++ record->kernel->core, ++ record->data, ++ record->physical, ++ record->bytes ++ ); ++ ++ return 0; ++} ++ ++static int ++_ShowRecords( ++ IN struct seq_file *File, ++ IN gcsDATABASE_PTR Database ++ ) ++{ ++ gctUINT i; ++ ++ seq_printf(File, "Records:\n"); ++ ++ seq_printf(File, "%s%8s%16s%16s%16s\n", ++ "Type", "GPU", "Data", "Physical", "Bytes"); ++ ++ for (i = 0; i < gcmCOUNTOF(Database->list); i++) ++ { ++ gcsDATABASE_RECORD_PTR record = Database->list[i]; ++ ++ while (record != NULL) ++ { ++ _ShowRecord(File, record); ++ record = record->next; ++ } ++ } ++ ++ return 0; ++} ++ ++void ++_ShowCounters( ++ struct seq_file *File, ++ gcsDATABASE_PTR Database ++ ); ++ ++static void ++_ShowProcess( ++ IN struct seq_file *File, ++ IN gcsDATABASE_PTR Database ++ ) ++{ ++ gctINT pid; ++ gctUINT8 name[24]; ++ ++ /* Process ID and name */ ++ pid = Database->processID; ++ gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name))); ++ gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name)); ++ ++ seq_printf(File, "--------------------------------------------------------------------------------\n"); ++ seq_printf(File, "Process: %-8d %s\n", pid, name); ++ ++ /* Detailed records */ ++ _ShowRecords(File, Database); ++ ++ seq_printf(File, "Counters:\n"); ++ ++ _ShowCounters(File, Database); ++} ++ ++static void ++_ShowProcesses( ++ IN struct seq_file * file, ++ IN gckKERNEL Kernel ++ ) ++{ ++ gcsDATABASE_PTR database; ++ gctINT i; ++ ++ /* Acquire the database mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); ++ ++ /* Idle time since last call */ ++ seq_printf(file, "GPU Idle: %llu ns\n", Kernel->db->idleTime); ++ Kernel->db->idleTime = 0; ++ ++ /* Walk the databases. */ ++ for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i) ++ { ++ for (database = Kernel->db->db[i]; ++ database != gcvNULL; ++ database = database->next) ++ { ++ _ShowProcess(file, database); ++ } ++ } ++ ++ /* Release the database mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); ++} ++ ++static int ++gc_db_show(struct seq_file *m, void *data) ++{ ++ gcsINFO_NODE *node = m->private; ++ gckGALDEVICE device = node->device; ++ gckKERNEL kernel = _GetValidKernel(device); ++ _ShowProcesses(m, kernel); ++ return 0 ; ++} ++ ++static int ++gc_version_show(struct seq_file *m, void *data) ++{ ++ seq_printf(m, "%s\n", gcvVERSION_STRING); ++ ++ return 0 ; ++} ++ ++int gc_idle_show(struct seq_file* m, void* data) ++{ ++ gcsINFO_NODE *node = m->private; ++ gckGALDEVICE device = node->device; ++ gckKERNEL kernel = _GetValidKernel(device); ++ gcuDATABASE_INFO info; ++ ++ gckKERNEL_QueryProcessDB(kernel, 0, gcvFALSE, gcvDB_IDLE, &info); ++ ++ seq_printf(m, "GPU idle time since last query: %llu ns\n", info.time); ++ ++ return 0; ++} ++ ++static gcsINFO InfoList[] = ++{ ++ {"info", gc_info_show}, ++ {"clients", gc_clients_show}, ++ {"meminfo", gc_meminfo_show}, ++ {"idle", gc_idle_show}, ++ {"database", gc_db_show}, ++ {"version", gc_version_show}, ++}; ++ ++static gceSTATUS ++_DebugfsInit( ++ IN gckGALDEVICE Device ++ ) ++{ ++ gceSTATUS status; ++ ++ gckDEBUGFS_DIR dir = &Device->debugfsDir; ++ ++ gcmkONERROR(gckDEBUGFS_DIR_Init(dir, gcvNULL, "gc")); ++ ++ gcmkONERROR(gckDEBUGFS_DIR_CreateFiles(dir, InfoList, gcmCOUNTOF(InfoList), Device)); ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++static void ++_DebugfsCleanup( ++ IN gckGALDEVICE Device ++ ) ++{ ++ gckDEBUGFS_DIR dir = &Device->debugfsDir; ++ ++ if (Device->debugfsDir.root) ++ { ++ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(dir, InfoList, gcmCOUNTOF(InfoList))); ++ ++ gckDEBUGFS_DIR_Deinit(dir); ++ } ++} ++ ++ ++/******************************************************************************\ ++*************************** Memory Allocation Wrappers ************************* ++\******************************************************************************/ ++ ++static gceSTATUS ++_AllocateMemory( ++ IN gckGALDEVICE Device, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER *Logical, ++ OUT gctPHYS_ADDR *Physical, ++ OUT gctUINT32 *PhysAddr ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Device=0x%x Bytes=%lu", Device, Bytes); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ gcmkVERIFY_ARGUMENT(Logical != NULL); ++ gcmkVERIFY_ARGUMENT(Physical != NULL); ++ gcmkVERIFY_ARGUMENT(PhysAddr != NULL); ++ ++ gcmkONERROR(gckOS_AllocateContiguous( ++ Device->os, gcvFALSE, &Bytes, Physical, Logical ++ )); ++ ++ *PhysAddr = ((PLINUX_MDL)*Physical)->dmaHandle; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG( ++ "*Logical=0x%x *Physical=0x%x *PhysAddr=0x%08x", ++ *Logical, *Physical, *PhysAddr ++ ); ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++_FreeMemory( ++ IN gckGALDEVICE Device, ++ IN gctPOINTER Logical, ++ IN gctPHYS_ADDR Physical) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Device=0x%x Logical=0x%x Physical=0x%x", ++ Device, Logical, Physical); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ status = gckOS_FreeContiguous( ++ Device->os, Physical, Logical, ++ ((PLINUX_MDL) Physical)->numPages * PAGE_SIZE ++ ); ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++ ++ ++/******************************************************************************\ ++******************************* Interrupt Handler ****************************** ++\******************************************************************************/ ++static irqreturn_t isrRoutine(int irq, void *ctxt) ++{ ++ gceSTATUS status; ++ gckGALDEVICE device; ++ ++ device = (gckGALDEVICE) ctxt; ++ ++ /* Call kernel interrupt notification. */ ++ status = gckKERNEL_Notify(device->kernels[gcvCORE_MAJOR], gcvNOTIFY_INTERRUPT, gcvTRUE); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ up(&device->semas[gcvCORE_MAJOR]); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static int threadRoutine(void *ctxt) ++{ ++ gckGALDEVICE device = (gckGALDEVICE) ctxt; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, ++ "Starting isr Thread with extension=%p", ++ device); ++ ++ for (;;) ++ { ++ static int down; ++ ++ down = down_interruptible(&device->semas[gcvCORE_MAJOR]); ++ if (down); /*To make gcc 4.6 happye*/ ++ ++ if (device->killThread == gcvTRUE) ++ { ++ /* The daemon exits. */ ++ while (!kthread_should_stop()) ++ { ++ gckOS_Delay(device->os, 1); ++ } ++ ++ return 0; ++ } ++ ++ gckKERNEL_Notify(device->kernels[gcvCORE_MAJOR], ++ gcvNOTIFY_INTERRUPT, ++ gcvFALSE); ++ } ++} ++ ++static irqreturn_t isrRoutine2D(int irq, void *ctxt) ++{ ++ gceSTATUS status; ++ gckGALDEVICE device; ++ ++ device = (gckGALDEVICE) ctxt; ++ ++ /* Call kernel interrupt notification. */ ++ status = gckKERNEL_Notify(device->kernels[gcvCORE_2D], ++ gcvNOTIFY_INTERRUPT, ++ gcvTRUE); ++ if (gcmIS_SUCCESS(status)) ++ { ++ up(&device->semas[gcvCORE_2D]); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static int threadRoutine2D(void *ctxt) ++{ ++ gckGALDEVICE device = (gckGALDEVICE) ctxt; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, ++ "Starting isr Thread with extension=%p", ++ device); ++ ++ for (;;) ++ { ++ static int down; ++ ++ down = down_interruptible(&device->semas[gcvCORE_2D]); ++ if (down); /*To make gcc 4.6 happye*/ ++ ++ if (device->killThread == gcvTRUE) ++ { ++ /* The daemon exits. */ ++ while (!kthread_should_stop()) ++ { ++ gckOS_Delay(device->os, 1); ++ } ++ ++ return 0; ++ } ++ gckKERNEL_Notify(device->kernels[gcvCORE_2D], ++ gcvNOTIFY_INTERRUPT, ++ gcvFALSE); ++ } ++} ++ ++static irqreturn_t isrRoutineVG(int irq, void *ctxt) ++{ ++#if gcdENABLE_VG ++ gceSTATUS status; ++ gckGALDEVICE device; ++ ++ device = (gckGALDEVICE) ctxt; ++ ++ /* Serve the interrupt. */ ++ status = gckVGINTERRUPT_Enque(device->kernels[gcvCORE_VG]->vg->interrupt); ++ ++ /* Determine the return value. */ ++ return (status == gcvSTATUS_NOT_OUR_INTERRUPT) ++ ? IRQ_RETVAL(0) ++ : IRQ_RETVAL(1); ++#else ++ return IRQ_NONE; ++#endif ++} ++ ++static int threadRoutineVG(void *ctxt) ++{ ++ gckGALDEVICE device = (gckGALDEVICE) ctxt; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, ++ "Starting isr Thread with extension=%p", ++ device); ++ ++ for (;;) ++ { ++ static int down; ++ ++ down = down_interruptible(&device->semas[gcvCORE_VG]); ++ if (down); /*To make gcc 4.6 happye*/ ++ ++ if (device->killThread == gcvTRUE) ++ { ++ /* The daemon exits. */ ++ while (!kthread_should_stop()) ++ { ++ gckOS_Delay(device->os, 1); ++ } ++ ++ return 0; ++ } ++ gckKERNEL_Notify(device->kernels[gcvCORE_VG], ++ gcvNOTIFY_INTERRUPT, ++ gcvFALSE); ++ } ++} ++ ++/******************************************************************************\ ++******************************* gckGALDEVICE Code ****************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Construct ++** ++** Constructor. ++** ++** INPUT: ++** ++** OUTPUT: ++** ++** gckGALDEVICE * Device ++** Pointer to a variable receiving the gckGALDEVICE object pointer on ++** success. ++*/ ++gceSTATUS ++gckGALDEVICE_Construct( ++ IN gctINT IrqLine, ++ IN gctUINT32 RegisterMemBase, ++ IN gctSIZE_T RegisterMemSize, ++ IN gctINT IrqLine2D, ++ IN gctUINT32 RegisterMemBase2D, ++ IN gctSIZE_T RegisterMemSize2D, ++ IN gctINT IrqLineVG, ++ IN gctUINT32 RegisterMemBaseVG, ++ IN gctSIZE_T RegisterMemSizeVG, ++ IN gctUINT32 ContiguousBase, ++ IN gctSIZE_T ContiguousSize, ++ IN gctSIZE_T BankSize, ++ IN gctINT FastClear, ++ IN gctINT Compression, ++ IN gctUINT32 PhysBaseAddr, ++ IN gctUINT32 PhysSize, ++ IN gctINT Signal, ++ IN gctUINT LogFileSize, ++ IN gctINT PowerManagement, ++ IN gctINT GpuProfiler, ++ IN gcsDEVICE_CONSTRUCT_ARGS * Args, ++ IN struct device *dev, ++ OUT gckGALDEVICE *Device ++ ) ++{ ++ gctUINT32 internalBaseAddress = 0, internalAlignment = 0; ++ gctUINT32 externalBaseAddress = 0, externalAlignment = 0; ++ gctUINT32 horizontalTileSize, verticalTileSize; ++ struct resource* mem_region; ++ gctUINT32 physAddr; ++ gctUINT32 physical; ++ gckGALDEVICE device; ++ gceSTATUS status; ++ gctINT32 i; ++ gceHARDWARE_TYPE type; ++ gckDB sharedDB = gcvNULL; ++ gckKERNEL kernel = gcvNULL; ++ ++ gcmkHEADER_ARG("IrqLine=%d RegisterMemBase=0x%08x RegisterMemSize=%u " ++ "IrqLine2D=%d RegisterMemBase2D=0x%08x RegisterMemSize2D=%u " ++ "IrqLineVG=%d RegisterMemBaseVG=0x%08x RegisterMemSizeVG=%u " ++ "ContiguousBase=0x%08x ContiguousSize=%lu BankSize=%lu " ++ "FastClear=%d Compression=%d PhysBaseAddr=0x%x PhysSize=%d Signal=%d", ++ IrqLine, RegisterMemBase, RegisterMemSize, ++ IrqLine2D, RegisterMemBase2D, RegisterMemSize2D, ++ IrqLineVG, RegisterMemBaseVG, RegisterMemSizeVG, ++ ContiguousBase, ContiguousSize, BankSize, FastClear, Compression, ++ PhysBaseAddr, PhysSize, Signal); ++ ++#if gcdDISABLE_CORES_2D3D ++ IrqLine = -1; ++ IrqLine2D = -1; ++#endif ++ ++ /* Allocate device structure. */ ++ device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL | __GFP_NOWARN); ++ ++ if (!device) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ memset(device, 0, sizeof(struct _gckGALDEVICE)); ++ ++ device->dbgNode = gcvNULL; ++ ++ device->platform = Args->platform; ++ ++ device->dev = dev; ++ ++ gcmkONERROR(_DebugfsInit(device)); ++ ++ if (gckDEBUGFS_CreateNode( ++ device, LogFileSize, device->debugfsDir.root ,DEBUG_FILE, &(device->dbgNode))) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Failed to create the debug file system %s/%s \n", ++ __FUNCTION__, __LINE__, ++ PARENT_FILE, DEBUG_FILE ++ ); ++ } ++ else if (LogFileSize) ++ { ++ gckDEBUGFS_SetCurrentNode(device->dbgNode); ++ } ++ ++ if (IrqLine != -1) ++ { ++ device->requestedRegisterMemBases[gcvCORE_MAJOR] = RegisterMemBase; ++ device->requestedRegisterMemSizes[gcvCORE_MAJOR] = RegisterMemSize; ++ } ++ ++ if (IrqLine2D != -1) ++ { ++ device->requestedRegisterMemBases[gcvCORE_2D] = RegisterMemBase2D; ++ device->requestedRegisterMemSizes[gcvCORE_2D] = RegisterMemSize2D; ++ } ++ ++ if (IrqLineVG != -1) ++ { ++ device->requestedRegisterMemBases[gcvCORE_VG] = RegisterMemBaseVG; ++ device->requestedRegisterMemSizes[gcvCORE_VG] = RegisterMemSizeVG; ++ } ++ ++ device->requestedContiguousBase = 0; ++ device->requestedContiguousSize = 0; ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ physical = device->requestedRegisterMemBases[i]; ++ ++ /* Set up register memory region. */ ++ if (physical != 0) ++ { ++ mem_region = request_mem_region(physical, ++ device->requestedRegisterMemSizes[i], ++ "galcore register region"); ++ ++ if (mem_region == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Failed to claim %lu bytes @ 0x%08X\n", ++ __FUNCTION__, __LINE__, ++ physical, device->requestedRegisterMemSizes[i] ++ ); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ device->registerBases[i] = (gctPOINTER) ioremap_nocache( ++ physical, device->requestedRegisterMemSizes[i]); ++ ++ if (device->registerBases[i] == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Unable to map %ld bytes @ 0x%08X\n", ++ __FUNCTION__, __LINE__, ++ physical, device->requestedRegisterMemSizes[i] ++ ); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ physical += device->requestedRegisterMemSizes[i]; ++ } ++ } ++ ++ /* Set the base address */ ++ device->baseAddress = device->physBase = PhysBaseAddr; ++ device->physSize = PhysSize; ++ device->mmu = Args->mmu; ++ ++ /* Construct the gckOS object. */ ++ gcmkONERROR(gckOS_Construct(device, &device->os)); ++ ++ if (IrqLine != -1) ++ { ++ /* Construct the gckKERNEL object. */ ++ gcmkONERROR(gckKERNEL_Construct( ++ device->os, gcvCORE_MAJOR, device, ++ gcvNULL, &device->kernels[gcvCORE_MAJOR])); ++ ++ sharedDB = device->kernels[gcvCORE_MAJOR]->db; ++ ++ /* Initialize core mapping */ ++ for (i = 0; i < 8; i++) ++ { ++ device->coreMapping[i] = gcvCORE_MAJOR; ++ } ++ ++ /* Setup the ISR manager. */ ++ gcmkONERROR(gckHARDWARE_SetIsrManager( ++ device->kernels[gcvCORE_MAJOR]->hardware, ++ (gctISRMANAGERFUNC) gckGALDEVICE_Enable_ISR, ++ (gctISRMANAGERFUNC) gckGALDEVICE_Disable_ISR, ++ device ++ )); ++ ++ gcmkONERROR(gckHARDWARE_SetFastClear( ++ device->kernels[gcvCORE_MAJOR]->hardware, FastClear, Compression ++ )); ++ ++ if(PowerManagement != -1) ++ { ++ gcmkONERROR(gckHARDWARE_SetPowerManagementLock( ++ device->kernels[gcvCORE_MAJOR]->hardware, gcvFALSE ++ )); ++ gcmkONERROR(gckHARDWARE_SetPowerManagement( ++ device->kernels[gcvCORE_MAJOR]->hardware, PowerManagement ++ )); ++ gcmkONERROR(gckHARDWARE_SetPowerManagementLock( ++ device->kernels[gcvCORE_MAJOR]->hardware, gcvTRUE ++ )); ++ } ++ else ++ { ++ gcmkONERROR(gckHARDWARE_SetPowerManagementLock( ++ device->kernels[gcvCORE_MAJOR]->hardware, gcvFALSE ++ )); ++ gcmkONERROR(gckHARDWARE_SetPowerManagement( ++ device->kernels[gcvCORE_MAJOR]->hardware, gcvTRUE ++ )); ++ } ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ gcmkONERROR(gckHARDWARE_SetMinFscaleValue( ++ device->kernels[gcvCORE_MAJOR]->hardware, Args->gpu3DMinClock ++ )); ++#endif ++ ++ gcmkONERROR(gckHARDWARE_SetGpuProfiler( ++ device->kernels[gcvCORE_MAJOR]->hardware, GpuProfiler ++ )); ++ ++ gcmkVERIFY_OK(gckKERNEL_SetRecovery( ++ device->kernels[gcvCORE_MAJOR], Args->recovery, Args->stuckDump ++ )); ++ ++ /* Start the command queue. */ ++ gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_MAJOR]->command)); ++ } ++ else ++ { ++ device->kernels[gcvCORE_MAJOR] = gcvNULL; ++ } ++ ++ if (IrqLine2D != -1) ++ { ++ gcmkONERROR(gckKERNEL_Construct( ++ device->os, gcvCORE_2D, device, ++ sharedDB, &device->kernels[gcvCORE_2D])); ++ ++ if (sharedDB == gcvNULL) sharedDB = device->kernels[gcvCORE_2D]->db; ++ ++ /* Verify the hardware type */ ++ gcmkONERROR(gckHARDWARE_GetType(device->kernels[gcvCORE_2D]->hardware, &type)); ++ ++ if (type != gcvHARDWARE_2D) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Unexpected hardware type: %d\n", ++ __FUNCTION__, __LINE__, ++ type ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Initialize core mapping */ ++ if (device->kernels[gcvCORE_MAJOR] == gcvNULL) ++ { ++ for (i = 0; i < 8; i++) ++ { ++ device->coreMapping[i] = gcvCORE_2D; ++ } ++ } ++ else ++ { ++ device->coreMapping[gcvHARDWARE_2D] = gcvCORE_2D; ++ } ++ ++ /* Setup the ISR manager. */ ++ gcmkONERROR(gckHARDWARE_SetIsrManager( ++ device->kernels[gcvCORE_2D]->hardware, ++ (gctISRMANAGERFUNC) gckGALDEVICE_Enable_ISR, ++ (gctISRMANAGERFUNC) gckGALDEVICE_Disable_ISR, ++ device ++ )); ++ ++ if(PowerManagement != -1) ++ { ++ gcmkONERROR(gckHARDWARE_SetPowerManagementLock( ++ device->kernels[gcvCORE_2D]->hardware, gcvFALSE ++ )); ++ gcmkONERROR(gckHARDWARE_SetPowerManagement( ++ device->kernels[gcvCORE_2D]->hardware, PowerManagement ++ )); ++ gcmkONERROR(gckHARDWARE_SetPowerManagementLock( ++ device->kernels[gcvCORE_2D]->hardware, gcvTRUE ++ )); ++ } ++ else ++ { ++ gcmkONERROR(gckHARDWARE_SetPowerManagementLock( ++ device->kernels[gcvCORE_2D]->hardware, gcvFALSE ++ )); ++ gcmkONERROR(gckHARDWARE_SetPowerManagement( ++ device->kernels[gcvCORE_2D]->hardware, gcvTRUE ++ )); ++ } ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ gcmkONERROR(gckHARDWARE_SetMinFscaleValue( ++ device->kernels[gcvCORE_2D]->hardware, 1 ++ )); ++#endif ++ ++ gcmkVERIFY_OK(gckKERNEL_SetRecovery( ++ device->kernels[gcvCORE_2D], Args->recovery, Args->stuckDump ++ )); ++ ++ /* Start the command queue. */ ++ gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_2D]->command)); ++ } ++ else ++ { ++ device->kernels[gcvCORE_2D] = gcvNULL; ++ } ++ ++ if (IrqLineVG != -1) ++ { ++#if gcdENABLE_VG ++ gcmkONERROR(gckKERNEL_Construct( ++ device->os, gcvCORE_VG, device, ++ sharedDB, &device->kernels[gcvCORE_VG])); ++ /* Initialize core mapping */ ++ if (device->kernels[gcvCORE_MAJOR] == gcvNULL ++ && device->kernels[gcvCORE_2D] == gcvNULL ++ ) ++ { ++ for (i = 0; i < 8; i++) ++ { ++ device->coreMapping[i] = gcvCORE_VG; ++ } ++ } ++ else ++ { ++ device->coreMapping[gcvHARDWARE_VG] = gcvCORE_VG; ++ } ++ ++ if(PowerManagement != -1) ++ { ++ gcmkONERROR(gckVGHARDWARE_SetPowerManagement( ++ device->kernels[gcvCORE_VG]->vg->hardware, ++ PowerManagement ++ )); ++ } ++ else ++ { ++ gcmkONERROR(gckVGHARDWARE_SetPowerManagement( ++ device->kernels[gcvCORE_VG]->vg->hardware, ++ gcvTRUE ++ )); ++ } ++#endif ++ } ++ else ++ { ++ device->kernels[gcvCORE_VG] = gcvNULL; ++ } ++ ++ /* Initialize the ISR. */ ++ device->irqLines[gcvCORE_MAJOR] = IrqLine; ++ device->irqLines[gcvCORE_2D] = IrqLine2D; ++ device->irqLines[gcvCORE_VG] = IrqLineVG; ++ ++ /* Initialize the kernel thread semaphores. */ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (device->irqLines[i] != -1) sema_init(&device->semas[i], 0); ++ } ++ ++ device->signal = Signal; ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (device->kernels[i] != gcvNULL) break; ++ } ++ ++ if (i == gcdMAX_GPU_COUNT) ++ { ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++#if gcdENABLE_VG ++ if (i == gcvCORE_VG) ++ { ++ /* Query the ceiling of the system memory. */ ++ gcmkONERROR(gckVGHARDWARE_QuerySystemMemory( ++ device->kernels[i]->vg->hardware, ++ &device->systemMemorySize, ++ &device->systemMemoryBaseAddress ++ )); ++ /* query the amount of video memory */ ++ gcmkONERROR(gckVGHARDWARE_QueryMemory( ++ device->kernels[i]->vg->hardware, ++ &device->internalSize, &internalBaseAddress, &internalAlignment, ++ &device->externalSize, &externalBaseAddress, &externalAlignment, ++ &horizontalTileSize, &verticalTileSize ++ )); ++ } ++ else ++#endif ++ { ++ /* Query the ceiling of the system memory. */ ++ gcmkONERROR(gckHARDWARE_QuerySystemMemory( ++ device->kernels[i]->hardware, ++ &device->systemMemorySize, ++ &device->systemMemoryBaseAddress ++ )); ++ ++ /* query the amount of video memory */ ++ gcmkONERROR(gckHARDWARE_QueryMemory( ++ device->kernels[i]->hardware, ++ &device->internalSize, &internalBaseAddress, &internalAlignment, ++ &device->externalSize, &externalBaseAddress, &externalAlignment, ++ &horizontalTileSize, &verticalTileSize ++ )); ++ } ++ ++ ++ /* Grab the first availiable kernel */ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (device->irqLines[i] != -1) ++ { ++ kernel = device->kernels[i]; ++ break; ++ } ++ } ++ ++ /* Set up the internal memory region. */ ++ if (device->internalSize > 0) ++ { ++ status = gckVIDMEM_Construct( ++ device->os, ++ internalBaseAddress, device->internalSize, internalAlignment, ++ 0, &device->internalVidMem ++ ); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Error, disable internal heap. */ ++ device->internalSize = 0; ++ } ++ else ++ { ++ /* Map internal memory. */ ++ device->internalLogical ++ = (gctPOINTER) ioremap_nocache(physical, device->internalSize); ++ ++ if (device->internalLogical == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ device->internalPhysical = (gctPHYS_ADDR)(gctUINTPTR_T) physical; ++ device->internalPhysicalName = gcmPTR_TO_NAME(device->internalPhysical); ++ physical += device->internalSize; ++ } ++ } ++ ++ if (device->externalSize > 0) ++ { ++ /* create the external memory heap */ ++ status = gckVIDMEM_Construct( ++ device->os, ++ externalBaseAddress, device->externalSize, externalAlignment, ++ 0, &device->externalVidMem ++ ); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Error, disable internal heap. */ ++ device->externalSize = 0; ++ } ++ else ++ { ++ /* Map external memory. */ ++ device->externalLogical ++ = (gctPOINTER) ioremap_nocache(physical, device->externalSize); ++ ++ if (device->externalLogical == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ device->externalPhysical = (gctPHYS_ADDR)(gctUINTPTR_T) physical; ++ device->externalPhysicalName = gcmPTR_TO_NAME(device->externalPhysical); ++ physical += device->externalSize; ++ } ++ } ++ ++ /* set up the contiguous memory */ ++ device->contiguousSize = ContiguousSize; ++ ++ if (ContiguousSize > 0) ++ { ++ if (ContiguousBase == 0) ++ { ++ while (device->contiguousSize > 0) ++ { ++ /* Allocate contiguous memory. */ ++ status = _AllocateMemory( ++ device, ++ device->contiguousSize, ++ &device->contiguousBase, ++ &device->contiguousPhysical, ++ &physAddr ++ ); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ device->contiguousPhysicalName = gcmPTR_TO_NAME(device->contiguousPhysical); ++ status = gckVIDMEM_Construct( ++ device->os, ++ physAddr | device->systemMemoryBaseAddress, ++ device->contiguousSize, ++ 64, ++ BankSize, ++ &device->contiguousVidMem ++ ); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ break; ++ } ++ ++ gcmkONERROR(_FreeMemory( ++ device, ++ device->contiguousBase, ++ device->contiguousPhysical ++ )); ++ ++ gcmRELEASE_NAME(device->contiguousPhysicalName); ++ device->contiguousBase = gcvNULL; ++ device->contiguousPhysical = gcvNULL; ++ } ++ ++ if (device->contiguousSize <= (4 << 20)) ++ { ++ device->contiguousSize = 0; ++ } ++ else ++ { ++ device->contiguousSize -= (4 << 20); ++ } ++ } ++ } ++ else ++ { ++ /* Create the contiguous memory heap. */ ++ status = gckVIDMEM_Construct( ++ device->os, ++ ContiguousBase | device->systemMemoryBaseAddress, ++ ContiguousSize, ++ 64, BankSize, ++ &device->contiguousVidMem ++ ); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Error, disable contiguous memory pool. */ ++ device->contiguousVidMem = gcvNULL; ++ device->contiguousSize = 0; ++ } ++ else ++ { ++ if (Args->contiguousRequested == gcvFALSE) ++ { ++ mem_region = request_mem_region( ++ ContiguousBase, ContiguousSize, "galcore managed memory" ++ ); ++ ++ if (mem_region == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Failed to claim %ld bytes @ 0x%08X\n", ++ __FUNCTION__, __LINE__, ++ ContiguousSize, ContiguousBase ++ ); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ } ++ ++ device->requestedContiguousBase = ContiguousBase; ++ device->requestedContiguousSize = ContiguousSize; ++ device->contiguousRequested = Args->contiguousRequested; ++ ++ device->contiguousPhysical = gcvNULL; ++ device->contiguousPhysicalName = 0; ++ device->contiguousSize = ContiguousSize; ++ device->contiguousMapped = gcvTRUE; ++ } ++ } ++ } ++ ++ /* Return pointer to the device. */ ++ *Device = device; ++ ++ gcmkFOOTER_ARG("*Device=0x%x", * Device); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ gcmkVERIFY_OK(gckGALDEVICE_Destroy(device)); ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Destroy ++** ++** Class destructor. ++** ++** INPUT: ++** ++** Nothing. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckGALDEVICE_Destroy( ++ gckGALDEVICE Device) ++{ ++ gctINT i; ++ gckKERNEL kernel = gcvNULL; ++ ++ gcmkHEADER_ARG("Device=0x%x", Device); ++ ++ if (Device != gcvNULL) ++ { ++ /* Grab the first availiable kernel */ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (Device->irqLines[i] != -1) ++ { ++ kernel = Device->kernels[i]; ++ break; ++ } ++ } ++ ++ if (Device->internalPhysicalName != 0) ++ { ++ gcmRELEASE_NAME(Device->internalPhysicalName); ++ Device->internalPhysicalName = 0; ++ } ++ if (Device->externalPhysicalName != 0) ++ { ++ gcmRELEASE_NAME(Device->externalPhysicalName); ++ Device->externalPhysicalName = 0; ++ } ++ if (Device->contiguousPhysicalName != 0) ++ { ++ gcmRELEASE_NAME(Device->contiguousPhysicalName); ++ Device->contiguousPhysicalName = 0; ++ } ++ ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (Device->kernels[i] != gcvNULL) ++ { ++ /* Destroy the gckKERNEL object. */ ++ gcmkVERIFY_OK(gckKERNEL_Destroy(Device->kernels[i])); ++ Device->kernels[i] = gcvNULL; ++ } ++ } ++ ++ if (Device->internalLogical != gcvNULL) ++ { ++ /* Unmap the internal memory. */ ++ iounmap(Device->internalLogical); ++ Device->internalLogical = gcvNULL; ++ } ++ ++ if (Device->internalVidMem != gcvNULL) ++ { ++ /* Destroy the internal heap. */ ++ gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->internalVidMem)); ++ Device->internalVidMem = gcvNULL; ++ } ++ ++ if (Device->externalLogical != gcvNULL) ++ { ++ /* Unmap the external memory. */ ++ iounmap(Device->externalLogical); ++ Device->externalLogical = gcvNULL; ++ } ++ ++ if (Device->externalVidMem != gcvNULL) ++ { ++ /* destroy the external heap */ ++ gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->externalVidMem)); ++ Device->externalVidMem = gcvNULL; ++ } ++ ++ if (Device->contiguousBase != gcvNULL) ++ { ++ if (Device->contiguousMapped == gcvFALSE) ++ { ++ gcmkVERIFY_OK(_FreeMemory( ++ Device, ++ Device->contiguousBase, ++ Device->contiguousPhysical ++ )); ++ } ++ ++ Device->contiguousBase = gcvNULL; ++ Device->contiguousPhysical = gcvNULL; ++ } ++ ++ if (Device->requestedContiguousBase != 0 ++ && Device->contiguousRequested == gcvFALSE ++ ) ++ { ++ release_mem_region(Device->requestedContiguousBase, Device->requestedContiguousSize); ++ Device->requestedContiguousBase = 0; ++ Device->requestedContiguousSize = 0; ++ } ++ ++ if (Device->contiguousVidMem != gcvNULL) ++ { ++ /* Destroy the contiguous heap. */ ++ gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->contiguousVidMem)); ++ Device->contiguousVidMem = gcvNULL; ++ } ++ ++ if (Device->dbgNode) ++ { ++ gckDEBUGFS_FreeNode(Device->dbgNode); ++ ++ if(Device->dbgNode != gcvNULL) ++ { ++ kfree(Device->dbgNode); ++ Device->dbgNode = gcvNULL; ++ } ++ } ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (Device->registerBases[i] != gcvNULL) ++ { ++ /* Unmap register memory. */ ++ iounmap(Device->registerBases[i]); ++ if (Device->requestedRegisterMemBases[i] != 0) ++ { ++ release_mem_region(Device->requestedRegisterMemBases[i], ++ Device->requestedRegisterMemSizes[i]); ++ } ++ ++ Device->registerBases[i] = gcvNULL; ++ Device->requestedRegisterMemBases[i] = 0; ++ Device->requestedRegisterMemSizes[i] = 0; ++ } ++ } ++ ++ /* Destroy the gckOS object. */ ++ if (Device->os != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_Destroy(Device->os)); ++ Device->os = gcvNULL; ++ } ++ ++ _DebugfsCleanup(Device); ++ ++ /* Free the device. */ ++ kfree(Device); ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Setup_ISR ++** ++** Start the ISR routine. ++** ++** INPUT: ++** ++** gckGALDEVICE Device ++** Pointer to an gckGALDEVICE object. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** gcvSTATUS_OK ++** Setup successfully. ++** gcvSTATUS_GENERIC_IO ++** Setup failed. ++*/ ++gceSTATUS ++gckGALDEVICE_Setup_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ) ++{ ++ gceSTATUS status; ++ gctINT ret = 0; ++ ++ gcmkHEADER_ARG("Device=0x%x Core=%d", Device, Core); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ if (Device->irqLines[Core] < 0) ++ { ++ gcmkONERROR(gcvSTATUS_GENERIC_IO); ++ } ++ ++ /* Hook up the isr based on the irq line. */ ++ switch (Core) { ++ case gcvCORE_MAJOR: ++ ret = request_irq( ++ Device->irqLines[Core], isrRoutine, 0, ++ "galcore interrupt service", Device ++ ); ++ break; ++ case gcvCORE_2D: ++ ret = request_irq( ++ Device->irqLines[Core], isrRoutine2D, 0, ++ "galcore 2D interrupt service", Device ++ ); ++ break; ++ case gcvCORE_VG: ++ ret = request_irq( ++ Device->irqLines[Core], isrRoutineVG, 0, ++ "galcore VG interrupt service", Device ++ ); ++ break; ++ default: ++ break; ++ } ++ ++ if (ret != 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Could not register irq line %d (error=%d)\n", ++ __FUNCTION__, __LINE__, ++ Device->irqLines[gcvCORE_MAJOR], ret ++ ); ++ ++ gcmkONERROR(gcvSTATUS_GENERIC_IO); ++ } ++ ++ Device->isrEnabled[Core] = 1; ++ ++ /* Mark ISR as initialized. */ ++ Device->isrInitializeds[Core] = gcvTRUE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckGALDEVICE_Enable_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Device=0x%x Core=%d", Device, Core); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ if (Device->irqLines[Core] < 0) ++ { ++ gcmkONERROR(gcvSTATUS_GENERIC_IO); ++ } ++ ++ spin_lock(&Device->kernels[Core]->irq_lock); ++ if (Device->isrEnabled[Core] == 0) ++ { ++ enable_irq(Device->irqLines[Core]); ++ /* Mark ISR as initialized. */ ++ Device->isrEnabled[Core] = gcvTRUE; ++ } ++ Device->isrEnabled[Core]++; ++ spin_unlock(&Device->kernels[Core]->irq_lock); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Release_ISR ++** ++** Release the irq line. ++** ++** INPUT: ++** ++** gckGALDEVICE Device ++** Pointer to an gckGALDEVICE object. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckGALDEVICE_Release_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ) ++{ ++ gcmkHEADER_ARG("Device=0x%x Core=%d", Device, Core); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ /* release the irq */ ++ if (Device->isrInitializeds[Core]) ++ { ++ free_irq(Device->irqLines[Core], Device); ++ Device->isrInitializeds[Core] = gcvFALSE; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckGALDEVICE_Disable_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ) ++{ ++ gcmkHEADER_ARG("Device=0x%x Core=%d", Device, Core); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ /* disable the irq */ ++ spin_lock(&Device->kernels[Core]->irq_lock); ++ if (Device->isrEnabled[Core] > 0) ++ { ++ Device->isrEnabled[Core]--; ++ if (Device->isrEnabled[Core] == 0) ++ disable_irq(Device->irqLines[Core]); ++ } ++ spin_unlock(&Device->kernels[Core]->irq_lock); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Start_Threads ++** ++** Start the daemon threads. ++** ++** INPUT: ++** ++** gckGALDEVICE Device ++** Pointer to an gckGALDEVICE object. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** gcvSTATUS_OK ++** Start successfully. ++** gcvSTATUS_GENERIC_IO ++** Start failed. ++*/ ++gceSTATUS ++gckGALDEVICE_Start_Threads( ++ IN gckGALDEVICE Device ++ ) ++{ ++ gceSTATUS status; ++ struct task_struct * task; ++ ++ gcmkHEADER_ARG("Device=0x%x", Device); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ if (Device->kernels[gcvCORE_MAJOR] != gcvNULL) ++ { ++ /* Start the kernel thread. */ ++ task = kthread_run(threadRoutine, Device, "galcore daemon thread"); ++ ++ if (IS_ERR(task)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Could not start the kernel thread.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_GENERIC_IO); ++ } ++ ++ Device->threadCtxts[gcvCORE_MAJOR] = task; ++ Device->threadInitializeds[gcvCORE_MAJOR] = gcvTRUE; ++ } ++ ++ if (Device->kernels[gcvCORE_2D] != gcvNULL) ++ { ++ /* Start the kernel thread. */ ++ task = kthread_run(threadRoutine2D, Device, "galcore daemon thread for 2D"); ++ ++ if (IS_ERR(task)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Could not start the kernel thread.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_GENERIC_IO); ++ } ++ ++ Device->threadCtxts[gcvCORE_2D] = task; ++ Device->threadInitializeds[gcvCORE_2D] = gcvTRUE; ++ } ++ else ++ { ++ Device->threadInitializeds[gcvCORE_2D] = gcvFALSE; ++ } ++ ++ if (Device->kernels[gcvCORE_VG] != gcvNULL) ++ { ++ /* Start the kernel thread. */ ++ task = kthread_run(threadRoutineVG, Device, "galcore daemon thread for VG"); ++ ++ if (IS_ERR(task)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Could not start the kernel thread.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_GENERIC_IO); ++ } ++ ++ Device->threadCtxts[gcvCORE_VG] = task; ++ Device->threadInitializeds[gcvCORE_VG] = gcvTRUE; ++ } ++ else ++ { ++ Device->threadInitializeds[gcvCORE_VG] = gcvFALSE; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Stop_Threads ++** ++** Stop the gal device, including the following actions: stop the daemon ++** thread, release the irq. ++** ++** INPUT: ++** ++** gckGALDEVICE Device ++** Pointer to an gckGALDEVICE object. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckGALDEVICE_Stop_Threads( ++ gckGALDEVICE Device ++ ) ++{ ++ gctINT i; ++ ++ gcmkHEADER_ARG("Device=0x%x", Device); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ /* Stop the kernel threads. */ ++ if (Device->threadInitializeds[i]) ++ { ++ Device->killThread = gcvTRUE; ++ up(&Device->semas[i]); ++ ++ kthread_stop(Device->threadCtxts[i]); ++ Device->threadCtxts[i] = gcvNULL; ++ Device->threadInitializeds[i] = gcvFALSE; ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Start ++** ++** Start the gal device, including the following actions: setup the isr routine ++** and start the daemoni thread. ++** ++** INPUT: ++** ++** gckGALDEVICE Device ++** Pointer to an gckGALDEVICE object. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** gcvSTATUS_OK ++** Start successfully. ++*/ ++gceSTATUS ++gckGALDEVICE_Start( ++ IN gckGALDEVICE Device ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Device=0x%x", Device); ++ ++ /* Start the kernel thread. */ ++ gcmkONERROR(gckGALDEVICE_Start_Threads(Device)); ++ ++ if (Device->kernels[gcvCORE_MAJOR] != gcvNULL) ++ { ++ /* Setup the ISR routine. */ ++ gcmkONERROR(gckGALDEVICE_Setup_ISR(Device, gcvCORE_MAJOR)); ++ ++ /* Switch to SUSPEND power state. */ ++ gcmkONERROR(gckHARDWARE_SetPowerManagementState( ++ Device->kernels[gcvCORE_MAJOR]->hardware, gcvPOWER_OFF_ATPOWERON ++ )); ++ } ++ ++ if (Device->kernels[gcvCORE_2D] != gcvNULL) ++ { ++ /* Setup the ISR routine. */ ++ gcmkONERROR(gckGALDEVICE_Setup_ISR(Device, gcvCORE_2D)); ++ ++ /* Switch to SUSPEND power state. */ ++ gcmkONERROR(gckHARDWARE_SetPowerManagementState( ++ Device->kernels[gcvCORE_2D]->hardware, gcvPOWER_OFF_ATPOWERON ++ )); ++ } ++ ++ if (Device->kernels[gcvCORE_VG] != gcvNULL) ++ { ++ /* Setup the ISR routine. */ ++ gcmkONERROR(gckGALDEVICE_Setup_ISR(Device, gcvCORE_VG)); ++ ++#if gcdENABLE_VG ++ /* Switch to SUSPEND power state. */ ++ gcmkONERROR(gckVGHARDWARE_SetPowerManagementState( ++ Device->kernels[gcvCORE_VG]->vg->hardware, gcvPOWER_OFF_ATPOWERON ++ )); ++#endif ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckGALDEVICE_Stop ++** ++** Stop the gal device, including the following actions: stop the daemon ++** thread, release the irq. ++** ++** INPUT: ++** ++** gckGALDEVICE Device ++** Pointer to an gckGALDEVICE object. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckGALDEVICE_Stop( ++ gckGALDEVICE Device ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Device=0x%x", Device); ++ ++ gcmkVERIFY_ARGUMENT(Device != NULL); ++ ++ if (Device->kernels[gcvCORE_MAJOR] != gcvNULL) ++ { ++ /* Switch to OFF power state. */ ++ gcmkONERROR(gckHARDWARE_SetPowerManagementState( ++ Device->kernels[gcvCORE_MAJOR]->hardware, gcvPOWER_OFF ++ )); ++ ++ /* Remove the ISR routine. */ ++ gcmkONERROR(gckGALDEVICE_Release_ISR(Device, gcvCORE_MAJOR)); ++ } ++ ++ if (Device->kernels[gcvCORE_2D] != gcvNULL) ++ { ++ /* Setup the ISR routine. */ ++ gcmkONERROR(gckGALDEVICE_Release_ISR(Device, gcvCORE_2D)); ++ ++ /* Switch to OFF power state. */ ++ gcmkONERROR(gckHARDWARE_SetPowerManagementState( ++ Device->kernels[gcvCORE_2D]->hardware, gcvPOWER_OFF ++ )); ++ } ++ ++ if (Device->kernels[gcvCORE_VG] != gcvNULL) ++ { ++ /* Setup the ISR routine. */ ++ gcmkONERROR(gckGALDEVICE_Release_ISR(Device, gcvCORE_VG)); ++ ++#if gcdENABLE_VG ++ /* Switch to OFF power state. */ ++ gcmkONERROR(gckVGHARDWARE_SetPowerManagementState( ++ Device->kernels[gcvCORE_VG]->vg->hardware, gcvPOWER_OFF ++ )); ++#endif ++ } ++ ++ /* Stop the kernel thread. */ ++ gcmkONERROR(gckGALDEVICE_Stop_Threads(Device)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_device.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_device.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_device.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_device.h 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,188 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_device_h_ ++#define __gc_hal_kernel_device_h_ ++ ++#include "gc_hal_kernel_debugfs.h" ++ ++/******************************************************************************\ ++******************************* gckGALDEVICE Structure ******************************* ++\******************************************************************************/ ++ ++typedef struct _gckGALDEVICE ++{ ++ struct device *dev; ++ ++ /* Objects. */ ++ gckOS os; ++ gckKERNEL kernels[gcdMAX_GPU_COUNT]; ++ ++ gcsPLATFORM* platform; ++ ++ /* Attributes. */ ++ gctSIZE_T internalSize; ++ gctPHYS_ADDR internalPhysical; ++ gctUINT32 internalPhysicalName; ++ gctPOINTER internalLogical; ++ gckVIDMEM internalVidMem; ++ gctSIZE_T externalSize; ++ gctPHYS_ADDR externalPhysical; ++ gctUINT32 externalPhysicalName; ++ gctPOINTER externalLogical; ++ gckVIDMEM externalVidMem; ++ gckVIDMEM contiguousVidMem; ++ gctPOINTER contiguousBase; ++ gctPHYS_ADDR contiguousPhysical; ++ gctUINT32 contiguousPhysicalName; ++ gctSIZE_T contiguousSize; ++ gctBOOL contiguousMapped; ++ gctPOINTER contiguousMappedUser; ++ gctBOOL contiguousRequested; ++ gctSIZE_T systemMemorySize; ++ gctUINT32 systemMemoryBaseAddress; ++ gctPOINTER registerBases[gcdMAX_GPU_COUNT]; ++ gctSIZE_T registerSizes[gcdMAX_GPU_COUNT]; ++ gctUINT32 baseAddress; ++ gctUINT32 physBase; ++ gctUINT32 physSize; ++ gctBOOL mmu; ++ gctUINT32 requestedRegisterMemBases[gcdMAX_GPU_COUNT]; ++ gctSIZE_T requestedRegisterMemSizes[gcdMAX_GPU_COUNT]; ++ gctUINT32 requestedContiguousBase; ++ gctSIZE_T requestedContiguousSize; ++ ++ /* IRQ management. */ ++ gctINT irqLines[gcdMAX_GPU_COUNT]; ++ gctBOOL isrInitializeds[gcdMAX_GPU_COUNT]; ++ gctINT isrEnabled[gcdMAX_GPU_COUNT]; ++ ++ /* Thread management. */ ++ struct task_struct *threadCtxts[gcdMAX_GPU_COUNT]; ++ struct semaphore semas[gcdMAX_GPU_COUNT]; ++ gctBOOL threadInitializeds[gcdMAX_GPU_COUNT]; ++ gctBOOL killThread; ++ ++ /* Signal management. */ ++ gctINT signal; ++ ++ /* Core mapping */ ++ gceCORE coreMapping[8]; ++ ++ /* States before suspend. */ ++ gceCHIPPOWERSTATE statesStored[gcdMAX_GPU_COUNT]; ++ ++ /* Device Debug File System Entry in kernel. */ ++ struct _gcsDEBUGFS_Node * dbgNode; ++ ++ gcsDEBUGFS_DIR debugfsDir; ++} ++* gckGALDEVICE; ++ ++typedef struct _gcsHAL_PRIVATE_DATA ++{ ++ gckGALDEVICE device; ++ gctPOINTER mappedMemory; ++ gctPOINTER contiguousLogical; ++ /* The process opening the device may not be the same as the one that closes it. */ ++ gctUINT32 pidOpen; ++} ++gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR; ++ ++typedef struct _gcsDEVICE_CONSTRUCT_ARGS ++{ ++ gctBOOL recovery; ++ gctUINT stuckDump; ++ gctUINT gpu3DMinClock; ++ ++ gctBOOL contiguousRequested; ++ gcsPLATFORM* platform; ++ gctBOOL mmu; ++} ++gcsDEVICE_CONSTRUCT_ARGS; ++ ++gceSTATUS gckGALDEVICE_Enable_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS gckGALDEVICE_Disable_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS gckGALDEVICE_Setup_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS gckGALDEVICE_Release_ISR( ++ IN gckGALDEVICE Device, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS gckGALDEVICE_Start_Threads( ++ IN gckGALDEVICE Device ++ ); ++ ++gceSTATUS gckGALDEVICE_Stop_Threads( ++ gckGALDEVICE Device ++ ); ++ ++gceSTATUS gckGALDEVICE_Start( ++ IN gckGALDEVICE Device ++ ); ++ ++gceSTATUS gckGALDEVICE_Stop( ++ gckGALDEVICE Device ++ ); ++ ++gceSTATUS gckGALDEVICE_Construct( ++ IN gctINT IrqLine, ++ IN gctUINT32 RegisterMemBase, ++ IN gctSIZE_T RegisterMemSize, ++ IN gctINT IrqLine2D, ++ IN gctUINT32 RegisterMemBase2D, ++ IN gctSIZE_T RegisterMemSize2D, ++ IN gctINT IrqLineVG, ++ IN gctUINT32 RegisterMemBaseVG, ++ IN gctSIZE_T RegisterMemSizeVG, ++ IN gctUINT32 ContiguousBase, ++ IN gctSIZE_T ContiguousSize, ++ IN gctSIZE_T BankSize, ++ IN gctINT FastClear, ++ IN gctINT Compression, ++ IN gctUINT32 PhysBaseAddr, ++ IN gctUINT32 PhysSize, ++ IN gctINT Signal, ++ IN gctUINT LogFileSize, ++ IN gctINT PowerManagement, ++ IN gctINT GpuProfiler, ++ IN gcsDEVICE_CONSTRUCT_ARGS * Args, ++ IN struct device *dev, ++ OUT gckGALDEVICE *Device ++ ); ++ ++gceSTATUS gckGALDEVICE_Destroy( ++ IN gckGALDEVICE Device ++ ); ++ ++#endif /* __gc_hal_kernel_device_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_event.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_event.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_event.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_event.c 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,2847 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++#include "gc_hal_kernel_buffer.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_EVENT ++ ++#define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsHAL_INTERFACE)) ++#define gcdEVENT_MIN_THRESHOLD 4 ++ ++/******************************************************************************\ ++********************************* Support Code ********************************* ++\******************************************************************************/ ++ ++static gceSTATUS ++gckEVENT_AllocateQueue( ++ IN gckEVENT Event, ++ OUT gcsEVENT_QUEUE_PTR * Queue ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Event=0x%x", Event); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Queue != gcvNULL); ++ ++ /* Do we have free queues? */ ++ if (Event->freeList == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ /* Move one free queue from the free list. */ ++ * Queue = Event->freeList; ++ Event->freeList = Event->freeList->next; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++gckEVENT_FreeQueue( ++ IN gckEVENT Event, ++ OUT gcsEVENT_QUEUE_PTR Queue ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ ++ gcmkHEADER_ARG("Event=0x%x", Event); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Queue != gcvNULL); ++ ++ /* Move one free queue from the free list. */ ++ Queue->next = Event->freeList; ++ Event->freeList = Queue; ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++gckEVENT_FreeRecord( ++ IN gckEVENT Event, ++ IN gcsEVENT_PTR Record ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Record != gcvNULL); ++ ++ /* Acquire the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Event->os, ++ Event->freeEventMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Push the record on the free list. */ ++ Record->next = Event->freeEventList; ++ Event->freeEventList = Record; ++ Event->freeEventCount += 1; ++ ++ /* Release the mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_OK; ++} ++ ++static gceSTATUS ++gckEVENT_IsEmpty( ++ IN gckEVENT Event, ++ OUT gctBOOL_PTR IsEmpty ++ ) ++{ ++ gceSTATUS status; ++ gctSIZE_T i; ++ ++ gcmkHEADER_ARG("Event=0x%x", Event); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL); ++ ++ /* Assume the event queue is empty. */ ++ *IsEmpty = gcvTRUE; ++ ++ /* Try acquiring the mutex. */ ++ status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0); ++ if (status == gcvSTATUS_TIMEOUT) ++ { ++ /* Timeout - queue is no longer empty. */ ++ *IsEmpty = gcvFALSE; ++ } ++ else ++ { ++ /* Bail out on error. */ ++ gcmkONERROR(status); ++ ++ /* Walk the event queue. */ ++ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) ++ { ++ /* Check whether this event is in use. */ ++ if (Event->queues[i].head != gcvNULL) ++ { ++ /* The event is in use, hence the queue is not empty. */ ++ *IsEmpty = gcvFALSE; ++ break; ++ } ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++_TryToIdleGPU( ++ IN gckEVENT Event ++) ++{ ++ gceSTATUS status; ++ gctBOOL empty = gcvFALSE; ++ gckHARDWARE hardware; ++ ++ gcmkHEADER_ARG("Event=0x%x", Event); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ /* Grab gckHARDWARE object. */ ++ hardware = Event->kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ /* Check whether the event queue is empty. */ ++ gcmkONERROR(gckEVENT_IsEmpty(Event, &empty)); ++ ++ if (empty) ++ { ++ /* Inform the system of idle GPU. */ ++ gcmkONERROR(gckOS_Broadcast(Event->os, ++ Event->kernel->hardware, ++ gcvBROADCAST_GPU_IDLE)); ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++__RemoveRecordFromProcessDB( ++ IN gckEVENT Event, ++ IN gcsEVENT_PTR Record ++ ) ++{ ++ gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record); ++ gcmkVERIFY_ARGUMENT(Record != gcvNULL); ++ ++ while (Record != gcvNULL) ++ { ++ if (Record->info.command == gcvHAL_SIGNAL) ++ { ++ /* TODO: Find a better place to bind signal to hardware.*/ ++ gcmkVERIFY_OK(gckOS_SignalSetHardware(Event->os, ++ gcmUINT64_TO_PTR(Record->info.u.Signal.signal), ++ Event->kernel->hardware)); ++ } ++ ++ if (Record->fromKernel) ++ { ++ /* No need to check db if event is from kernel. */ ++ Record = Record->next; ++ continue; ++ } ++ ++ switch (Record->info.command) ++ { ++ case gcvHAL_FREE_NON_PAGED_MEMORY: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Event->kernel, ++ Record->processID, ++ gcvDB_NON_PAGED, ++ gcmUINT64_TO_PTR(Record->info.u.FreeNonPagedMemory.logical))); ++ break; ++ ++ case gcvHAL_FREE_CONTIGUOUS_MEMORY: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Event->kernel, ++ Record->processID, ++ gcvDB_CONTIGUOUS, ++ gcmUINT64_TO_PTR(Record->info.u.FreeContiguousMemory.logical))); ++ break; ++ ++ case gcvHAL_UNLOCK_VIDEO_MEMORY: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Event->kernel, ++ Record->processID, ++ gcvDB_VIDEO_MEMORY_LOCKED, ++ gcmUINT64_TO_PTR(Record->info.u.UnlockVideoMemory.node))); ++ break; ++ ++ case gcvHAL_UNMAP_USER_MEMORY: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Event->kernel, ++ Record->processID, ++ gcvDB_MAP_USER_MEMORY, ++ gcmINT2PTR(Record->info.u.UnmapUserMemory.info))); ++ break; ++ ++ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Event->kernel, ++ Record->processID, ++ gcvDB_COMMAND_BUFFER, ++ gcmUINT64_TO_PTR(Record->info.u.FreeVirtualCommandBuffer.logical))); ++ break; ++ ++ default: ++ break; ++ } ++ ++ Record = Record->next; ++ } ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_ReleaseVideoMemoryHandle( ++ IN gckKERNEL Kernel, ++ IN OUT gcsEVENT_PTR Record, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE nodeObject; ++ gctUINT32 handle; ++ ++ switch(Interface->command) ++ { ++ case gcvHAL_UNLOCK_VIDEO_MEMORY: ++ handle = (gctUINT32)Interface->u.UnlockVideoMemory.node; ++ ++ gcmkONERROR(gckVIDMEM_HANDLE_Lookup( ++ Kernel, Record->processID, handle, &nodeObject)); ++ ++ Record->info.u.UnlockVideoMemory.node = gcmPTR_TO_UINT64(nodeObject); ++ ++ gckVIDMEM_HANDLE_Dereference(Kernel, Record->processID, handle); ++ break; ++ ++ default: ++ break; ++ } ++ ++ return gcvSTATUS_OK; ++OnError: ++ return status; ++} ++ ++/******************************************************************************* ++** ++** _QueryFlush ++** ++** Check the type of surfaces which will be released by current event and ++** determine the cache needed to flush. ++** ++*/ ++static gceSTATUS ++_QueryFlush( ++ IN gckEVENT Event, ++ IN gcsEVENT_PTR Record, ++ OUT gceKERNEL_FLUSH *Flush ++ ) ++{ ++ gceKERNEL_FLUSH flush = 0; ++ gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record); ++ gcmkVERIFY_ARGUMENT(Record != gcvNULL); ++ ++ while (Record != gcvNULL) ++ { ++ switch (Record->info.command) ++ { ++ case gcvHAL_UNLOCK_VIDEO_MEMORY: ++ switch(Record->info.u.UnlockVideoMemory.type) ++ { ++ case gcvSURF_TILE_STATUS: ++ flush |= gcvFLUSH_TILE_STATUS; ++ break; ++ case gcvSURF_RENDER_TARGET: ++ flush |= gcvFLUSH_COLOR; ++ break; ++ case gcvSURF_DEPTH: ++ flush |= gcvFLUSH_DEPTH; ++ break; ++ case gcvSURF_TEXTURE: ++ flush |= gcvFLUSH_TEXTURE; ++ break; ++ case gcvSURF_TYPE_UNKNOWN: ++ gcmkASSERT(0); ++ break; ++ default: ++ break; ++ } ++ break; ++ case gcvHAL_UNMAP_USER_MEMORY: ++ *Flush = gcvFLUSH_ALL; ++ return gcvSTATUS_OK; ++ ++ default: ++ break; ++ } ++ ++ Record = Record->next; ++ } ++ ++ *Flush = flush; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++void ++_SubmitTimerFunction( ++ gctPOINTER Data ++ ) ++{ ++ gckEVENT event = (gckEVENT)Data; ++ gcmkVERIFY_OK(gckEVENT_Submit(event, gcvTRUE, gcvFALSE, gcvFALSE)); ++} ++ ++/******************************************************************************\ ++******************************* gckEVENT API Code ******************************* ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckEVENT_Construct ++** ++** Construct a new gckEVENT object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** OUTPUT: ++** ++** gckEVENT * Event ++** Pointer to a variable that receives the gckEVENT object pointer. ++*/ ++gceSTATUS ++gckEVENT_Construct( ++ IN gckKERNEL Kernel, ++ OUT gckEVENT * Event ++ ) ++{ ++ gckOS os; ++ gceSTATUS status; ++ gckEVENT eventObj = gcvNULL; ++ int i; ++ gcsEVENT_PTR record; ++ gctPOINTER pointer = gcvNULL; ++ ++ gcmkHEADER_ARG("Kernel=0x%x", Kernel); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Event != gcvNULL); ++ ++ /* Extract the pointer to the gckOS object. */ ++ os = Kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Allocate the gckEVENT object. */ ++ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer)); ++ ++ eventObj = pointer; ++ ++ /* Reset the object. */ ++ gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT))); ++ ++ /* Initialize the gckEVENT object. */ ++ eventObj->object.type = gcvOBJ_EVENT; ++ eventObj->kernel = Kernel; ++ eventObj->os = os; ++ ++ /* Create the mutexes. */ ++ gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventQueueMutex)); ++ gcmkONERROR(gckOS_CreateMutex(os, &eventObj->freeEventMutex)); ++ gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventListMutex)); ++ ++ /* Create a bunch of event reccords. */ ++ for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1) ++ { ++ /* Allocate an event record. */ ++ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer)); ++ ++ record = pointer; ++ ++ /* Push it on the free list. */ ++ record->next = eventObj->freeEventList; ++ eventObj->freeEventList = record; ++ eventObj->freeEventCount += 1; ++ } ++ ++ /* Initialize the free list of event queues. */ ++ for (i = 0; i < gcdREPO_LIST_COUNT; i += 1) ++ { ++ eventObj->repoList[i].next = eventObj->freeList; ++ eventObj->freeList = &eventObj->repoList[i]; ++ } ++ ++ /* Construct the atom. */ ++ gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->freeAtom)); ++ gcmkONERROR(gckOS_AtomSet(os, ++ eventObj->freeAtom, ++ gcmCOUNTOF(eventObj->queues))); ++ ++#if gcdSMP ++ gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->pending)); ++#endif ++ ++ gcmkVERIFY_OK(gckOS_CreateTimer(os, ++ _SubmitTimerFunction, ++ (gctPOINTER)eventObj, ++ &eventObj->submitTimer)); ++ ++#if gcdINTERRUPT_STATISTIC ++ gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->interruptCount)); ++ gcmkONERROR(gckOS_AtomSet(os,eventObj->interruptCount, 0)); ++#endif ++ ++ /* Return pointer to the gckEVENT object. */ ++ *Event = eventObj; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Event=0x%x", *Event); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (eventObj != gcvNULL) ++ { ++ if (eventObj->eventQueueMutex != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex)); ++ } ++ ++ if (eventObj->freeEventMutex != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex)); ++ } ++ ++ if (eventObj->eventListMutex != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex)); ++ } ++ ++ while (eventObj->freeEventList != gcvNULL) ++ { ++ record = eventObj->freeEventList; ++ eventObj->freeEventList = record->next; ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record)); ++ } ++ ++ if (eventObj->freeAtom != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->freeAtom)); ++ } ++ ++#if gcdSMP ++ if (eventObj->pending != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->pending)); ++ } ++#endif ++ ++#if gcdINTERRUPT_STATISTIC ++ if (eventObj->interruptCount) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->interruptCount)); ++ } ++#endif ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_Destroy ++** ++** Destroy an gckEVENT object. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Destroy( ++ IN gckEVENT Event ++ ) ++{ ++ gcsEVENT_PTR record; ++ gcsEVENT_QUEUE_PTR queue; ++ ++ gcmkHEADER_ARG("Event=0x%x", Event); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ if (Event->submitTimer != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_StopTimer(Event->os, Event->submitTimer)); ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Event->os, Event->submitTimer)); ++ } ++ ++ /* Delete the queue mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex)); ++ ++ /* Free all free events. */ ++ while (Event->freeEventList != gcvNULL) ++ { ++ record = Event->freeEventList; ++ Event->freeEventList = record->next; ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record)); ++ } ++ ++ /* Delete the free mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex)); ++ ++ /* Free all pending queues. */ ++ while (Event->queueHead != gcvNULL) ++ { ++ /* Get the current queue. */ ++ queue = Event->queueHead; ++ ++ /* Free all pending events. */ ++ while (queue->head != gcvNULL) ++ { ++ record = queue->head; ++ queue->head = record->next; ++ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_WARNING, gcvZONE_EVENT, ++ gcmSIZEOF(record) + gcmSIZEOF(queue->source), ++ "Event record 0x%x is still pending for %d.", ++ record, queue->source ++ ); ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record)); ++ } ++ ++ /* Remove the top queue from the list. */ ++ if (Event->queueHead == Event->queueTail) ++ { ++ Event->queueHead = ++ Event->queueTail = gcvNULL; ++ } ++ else ++ { ++ Event->queueHead = Event->queueHead->next; ++ } ++ ++ /* Free the queue. */ ++ gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue)); ++ } ++ ++ /* Delete the list mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex)); ++ ++ /* Delete the atom. */ ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->freeAtom)); ++ ++#if gcdSMP ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->pending)); ++#endif ++ ++#if gcdINTERRUPT_STATISTIC ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->interruptCount)); ++#endif ++ ++ /* Mark the gckEVENT object as unknown. */ ++ Event->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckEVENT object. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_GetEvent ++** ++** Reserve the next available hardware event. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctBOOL Wait ++** Set to gcvTRUE to force the function to wait if no events are ++** immediately available. ++** ++** gceKERNEL_WHERE Source ++** Source of the event. ++** ++** OUTPUT: ++** ++** gctUINT8 * EventID ++** Reserved event ID. ++*/ ++#define gcdINVALID_EVENT_PTR ((gcsEVENT_PTR)gcvMAXUINTPTR_T) ++ ++static gceSTATUS ++gckEVENT_GetEvent( ++ IN gckEVENT Event, ++ IN gctBOOL Wait, ++ OUT gctUINT8 * EventID, ++ IN gcsEVENT_PTR Head, ++ IN gceKERNEL_WHERE Source ++ ) ++{ ++ gctINT i, id; ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gctINT32 free; ++ ++ gcmkHEADER_ARG("Event=0x%x Head=%p Source=%d", Event, Head, Source); ++ ++ while (gcvTRUE) ++ { ++ /* Grab the queue mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Event->os, ++ Event->eventQueueMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Walk through all events. */ ++ id = Event->lastID; ++ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) ++ { ++ gctINT nextID = gckMATH_ModuloInt((id + 1), ++ gcmCOUNTOF(Event->queues)); ++ ++ if (Event->queues[id].head == gcvNULL) ++ { ++ *EventID = (gctUINT8) id; ++ ++ Event->lastID = (gctUINT8) nextID; ++ ++ /* Save time stamp of event. */ ++ Event->queues[id].head = gcdINVALID_EVENT_PTR; ++ Event->queues[id].stamp = ++(Event->stamp); ++ Event->queues[id].head = Head; ++ Event->queues[id].source = Source; ++ ++ gcmkONERROR(gckOS_AtomDecrement(Event->os, ++ Event->freeAtom, ++ &free)); ++#if gcdDYNAMIC_SPEED ++ if (free <= gcdDYNAMIC_EVENT_THRESHOLD) ++ { ++ gcmkONERROR(gckOS_BroadcastHurry( ++ Event->os, ++ Event->kernel->hardware, ++ gcdDYNAMIC_EVENT_THRESHOLD - free)); ++ } ++#endif ++ ++ /* Release the queue mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, ++ Event->eventQueueMutex)); ++ ++ /* Success. */ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_INFO, gcvZONE_EVENT, ++ gcmSIZEOF(id), ++ "Using id=%d", ++ id ++ ); ++ ++ gcmkFOOTER_ARG("*EventID=%u", *EventID); ++ return gcvSTATUS_OK; ++ } ++ ++ id = nextID; ++ } ++ ++#if gcdDYNAMIC_SPEED ++ /* No free events, speed up the GPU right now! */ ++ gcmkONERROR(gckOS_BroadcastHurry(Event->os, ++ Event->kernel->hardware, ++ gcdDYNAMIC_EVENT_THRESHOLD)); ++#endif ++ ++ /* Release the queue mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ acquired = gcvFALSE; ++ ++ /* Fail if wait is not requested. */ ++ if (!Wait) ++ { ++ /* Out of resources. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ /* Delay a while. */ ++ gcmkONERROR(gckOS_Delay(Event->os, 1)); ++ } ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the queue mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_AllocateRecord ++** ++** Allocate a record for the new event. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctBOOL AllocateAllowed ++** State for allocation if out of free events. ++** ++** OUTPUT: ++** ++** gcsEVENT_PTR * Record ++** Allocated event record. ++*/ ++gceSTATUS ++gckEVENT_AllocateRecord( ++ IN gckEVENT Event, ++ IN gctBOOL AllocateAllowed, ++ OUT gcsEVENT_PTR * Record ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gctINT i; ++ gcsEVENT_PTR record; ++ gctPOINTER pointer = gcvNULL; ++ ++ gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Record != gcvNULL); ++ ++ /* Acquire the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Test if we are below the allocation threshold. */ ++ if ( (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD)) || ++ (Event->freeEventCount == 0) ) ++ { ++ /* Allocate a bunch of records. */ ++ for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1) ++ { ++ /* Allocate an event record. */ ++ gcmkONERROR(gckOS_Allocate(Event->os, ++ gcmSIZEOF(gcsEVENT), ++ &pointer)); ++ ++ record = pointer; ++ ++ /* Push it on the free list. */ ++ record->next = Event->freeEventList; ++ Event->freeEventList = record; ++ Event->freeEventCount += 1; ++ } ++ } ++ ++ *Record = Event->freeEventList; ++ Event->freeEventList = Event->freeEventList->next; ++ Event->freeEventCount -= 1; ++ ++ /* Release the mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_AddList ++** ++** Add a new event to the list of events. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gcsHAL_INTERFACE_PTR Interface ++** Pointer to the interface for the event to be added. ++** ++** gceKERNEL_WHERE FromWhere ++** Place in the pipe where the event needs to be generated. ++** ++** gctBOOL AllocateAllowed ++** State for allocation if out of free events. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_AddList( ++ IN gckEVENT Event, ++ IN gcsHAL_INTERFACE_PTR Interface, ++ IN gceKERNEL_WHERE FromWhere, ++ IN gctBOOL AllocateAllowed, ++ IN gctBOOL FromKernel ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gcsEVENT_PTR record = gcvNULL; ++ gcsEVENT_QUEUE_PTR queue; ++ gckVIRTUAL_COMMAND_BUFFER_PTR buffer; ++ gckKERNEL kernel = Event->kernel; ++ ++ gcmkHEADER_ARG("Event=0x%x Interface=0x%x", ++ Event, Interface); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, _GC_OBJ_ZONE, ++ "FromWhere=%d AllocateAllowed=%d", ++ FromWhere, AllocateAllowed); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Interface != gcvNULL); ++ ++ /* Verify the event command. */ ++ gcmkASSERT ++ ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY) ++ || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY) ++ || (Interface->command == gcvHAL_WRITE_DATA) ++ || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY) ++ || (Interface->command == gcvHAL_SIGNAL) ++ || (Interface->command == gcvHAL_UNMAP_USER_MEMORY) ++ || (Interface->command == gcvHAL_TIMESTAMP) ++ || (Interface->command == gcvHAL_COMMIT_DONE) ++ || (Interface->command == gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER) ++ || (Interface->command == gcvHAL_SYNC_POINT) ++ || (Interface->command == gcvHAL_DESTROY_MMU) ++ ); ++ ++ /* Validate the source. */ ++ if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL)) ++ { ++ /* Invalid argument. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Allocate a free record. */ ++ gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record)); ++ ++ /* Termninate the record. */ ++ record->next = gcvNULL; ++ ++ /* Record the committer. */ ++ record->fromKernel = FromKernel; ++ ++ /* Copy the event interface into the record. */ ++ gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info)); ++ ++ /* Get process ID. */ ++ gcmkONERROR(gckOS_GetProcessID(&record->processID)); ++ ++ gcmkONERROR(__RemoveRecordFromProcessDB(Event, record)); ++ ++ /* Handle is belonged to current process, it must be released now. */ ++ if (FromKernel == gcvFALSE) ++ { ++ status = _ReleaseVideoMemoryHandle(Event->kernel, record, Interface); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Ingore error because there are other events in the queue. */ ++ status = gcvSTATUS_OK; ++ goto OnError; ++ } ++ } ++ ++ /* Acquire the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Do we need to allocate a new queue? */ ++ if ((Event->queueTail == gcvNULL) || (Event->queueTail->source < FromWhere)) ++ { ++ /* Allocate a new queue. */ ++ gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue)); ++ ++ /* Initialize the queue. */ ++ queue->source = FromWhere; ++ queue->head = gcvNULL; ++ queue->next = gcvNULL; ++ ++ /* Attach it to the list of allocated queues. */ ++ if (Event->queueTail == gcvNULL) ++ { ++ Event->queueHead = ++ Event->queueTail = queue; ++ } ++ else ++ { ++ Event->queueTail->next = queue; ++ Event->queueTail = queue; ++ } ++ } ++ else ++ { ++ queue = Event->queueTail; ++ } ++ ++ /* Attach the record to the queue. */ ++ if (queue->head == gcvNULL) ++ { ++ queue->head = record; ++ queue->tail = record; ++ } ++ else ++ { ++ queue->tail->next = record; ++ queue->tail = record; ++ } ++ ++ /* Unmap user space logical address. ++ * Linux kernel does not support unmap the memory of other process any more since 3.5. ++ * Let's unmap memory of self process before submit the event to gpu. ++ * */ ++ switch(Interface->command) ++ { ++ case gcvHAL_FREE_NON_PAGED_MEMORY: ++ gcmkONERROR(gckOS_UnmapUserLogical( ++ Event->os, ++ gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical), ++ (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes, ++ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical))); ++ break; ++ case gcvHAL_FREE_CONTIGUOUS_MEMORY: ++ gcmkONERROR(gckOS_UnmapUserLogical( ++ Event->os, ++ gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical), ++ (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes, ++ gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical))); ++ break; ++ ++ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER: ++ buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)gcmNAME_TO_PTR(Interface->u.FreeVirtualCommandBuffer.physical); ++ if (buffer->userLogical) ++ { ++ gcmkONERROR(gckOS_DestroyUserVirtualMapping( ++ Event->os, ++ buffer->physical, ++ (gctSIZE_T) Interface->u.FreeVirtualCommandBuffer.bytes, ++ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical))); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Release the mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); ++ } ++ ++ if (record != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_Unlock ++** ++** Schedule an event to unlock virtual memory. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gceKERNEL_WHERE FromWhere ++** Place in the pipe where the event needs to be generated. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory ++** to unlock. ++** ++** gceSURF_TYPE Type ++** Type of surface to unlock. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Unlock( ++ IN gckEVENT Event, ++ IN gceKERNEL_WHERE FromWhere, ++ IN gctPOINTER Node, ++ IN gceSURF_TYPE Type ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ ++ gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d", ++ Event, FromWhere, Node, Type); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Node != gcvNULL); ++ ++ /* Mark the event as an unlock. */ ++ iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY; ++ iface.u.UnlockVideoMemory.node = gcmPTR_TO_UINT64(Node); ++ iface.u.UnlockVideoMemory.type = Type; ++ iface.u.UnlockVideoMemory.asynchroneous = 0; ++ ++ /* Append it to the queue. */ ++ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_FreeNonPagedMemory ++** ++** Schedule an event to free non-paged memory. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctSIZE_T Bytes ++** Number of bytes of non-paged memory to free. ++** ++** gctPHYS_ADDR Physical ++** Physical address of non-paged memory to free. ++** ++** gctPOINTER Logical ++** Logical address of non-paged memory to free. ++** ++** gceKERNEL_WHERE FromWhere ++** Place in the pipe where the event needs to be generated. ++*/ ++gceSTATUS ++gckEVENT_FreeNonPagedMemory( ++ IN gckEVENT Event, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gceKERNEL_WHERE FromWhere ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ gckKERNEL kernel = Event->kernel; ++ ++ gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " ++ "FromWhere=%d", ++ Event, Bytes, Physical, Logical, FromWhere); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ /* Create an event. */ ++ iface.command = gcvHAL_FREE_NON_PAGED_MEMORY; ++ iface.u.FreeNonPagedMemory.bytes = Bytes; ++ iface.u.FreeNonPagedMemory.physical = gcmPTR_TO_NAME(Physical); ++ iface.u.FreeNonPagedMemory.logical = gcmPTR_TO_UINT64(Logical); ++ ++ /* Append it to the queue. */ ++ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckEVENT_DestroyVirtualCommandBuffer( ++ IN gckEVENT Event, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gceKERNEL_WHERE FromWhere ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ gckKERNEL kernel = Event->kernel; ++ ++ gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " ++ "FromWhere=%d", ++ Event, Bytes, Physical, Logical, FromWhere); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ /* Create an event. */ ++ iface.command = gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER; ++ iface.u.FreeVirtualCommandBuffer.bytes = Bytes; ++ iface.u.FreeVirtualCommandBuffer.physical = gcmPTR_TO_NAME(Physical); ++ iface.u.FreeVirtualCommandBuffer.logical = gcmPTR_TO_UINT64(Logical); ++ ++ /* Append it to the queue. */ ++ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_FreeContigiuousMemory ++** ++** Schedule an event to free contiguous memory. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctSIZE_T Bytes ++** Number of bytes of contiguous memory to free. ++** ++** gctPHYS_ADDR Physical ++** Physical address of contiguous memory to free. ++** ++** gctPOINTER Logical ++** Logical address of contiguous memory to free. ++** ++** gceKERNEL_WHERE FromWhere ++** Place in the pipe where the event needs to be generated. ++*/ ++gceSTATUS ++gckEVENT_FreeContiguousMemory( ++ IN gckEVENT Event, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gceKERNEL_WHERE FromWhere ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ gckKERNEL kernel = Event->kernel; ++ ++ gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " ++ "FromWhere=%d", ++ Event, Bytes, Physical, Logical, FromWhere); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ /* Create an event. */ ++ iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY; ++ iface.u.FreeContiguousMemory.bytes = Bytes; ++ iface.u.FreeContiguousMemory.physical = gcmPTR_TO_NAME(Physical); ++ iface.u.FreeContiguousMemory.logical = gcmPTR_TO_UINT64(Logical); ++ ++ /* Append it to the queue. */ ++ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_Signal ++** ++** Schedule an event to trigger a signal. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctSIGNAL Signal ++** Pointer to the signal to trigger. ++** ++** gceKERNEL_WHERE FromWhere ++** Place in the pipe where the event needs to be generated. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Signal( ++ IN gckEVENT Event, ++ IN gctSIGNAL Signal, ++ IN gceKERNEL_WHERE FromWhere ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ ++ gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d", ++ Event, Signal, FromWhere); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ /* Mark the event as a signal. */ ++ iface.command = gcvHAL_SIGNAL; ++ iface.u.Signal.signal = gcmPTR_TO_UINT64(Signal); ++ iface.u.Signal.auxSignal = 0; ++ iface.u.Signal.process = 0; ++ ++ /* Append it to the queue. */ ++ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_CommitDone ++** ++** Schedule an event to wake up work thread when commit is done by GPU. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gceKERNEL_WHERE FromWhere ++** Place in the pipe where the event needs to be generated. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_CommitDone( ++ IN gckEVENT Event, ++ IN gceKERNEL_WHERE FromWhere ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ ++ gcmkHEADER_ARG("Event=0x%x FromWhere=%d", Event, FromWhere); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ iface.command = gcvHAL_COMMIT_DONE; ++ ++ /* Append it to the queue. */ ++ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gceSTATUS ++gckEVENT_DestroyMmu( ++ IN gckEVENT Event, ++ IN gckMMU Mmu, ++ IN gceKERNEL_WHERE FromWhere ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ ++ gcmkHEADER_ARG("Event=0x%x FromWhere=%d", Event, FromWhere); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ iface.command = gcvHAL_DESTROY_MMU; ++ iface.u.DestroyMmu.mmu = gcmPTR_TO_UINT64(Mmu); ++ ++ /* Append it to the queue. */ ++ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckEVENT_Submit ++** ++** Submit the current event queue to the GPU. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctBOOL Wait ++** Submit requires one vacant event; if Wait is set to not zero, ++** and there are no vacant events at this time, the function will ++** wait until an event becomes vacant so that submission of the ++** queue is successful. ++** ++** gctBOOL FromPower ++** Determines whether the call originates from inside the power ++** management or not. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Submit( ++ IN gckEVENT Event, ++ IN gctBOOL Wait, ++ IN gctBOOL FromPower, ++ IN gctBOOL FromCommand ++ ) ++{ ++ gceSTATUS status; ++ gctUINT8 id = 0xFF; ++ gcsEVENT_QUEUE_PTR queue; ++ gctBOOL acquired = gcvFALSE; ++ gckCOMMAND command = gcvNULL; ++ gctBOOL commitEntered = gcvFALSE; ++#if !gcdNULL_DRIVER ++ gctUINT32 bytes; ++ gctPOINTER buffer; ++#endif ++ ++#if gcdINTERRUPT_STATISTIC ++ gctINT32 oldValue; ++#endif ++ ++ gctUINT32 flushBytes; ++ gctUINT32 executeBytes; ++ gckHARDWARE hardware; ++ ++ gceKERNEL_FLUSH flush = gcvFALSE; ++ ++ gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait); ++ ++ /* Get gckCOMMAND object. */ ++ command = Event->kernel->command; ++ hardware = Event->kernel->hardware; ++ ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ gckOS_GetTicks(&Event->lastCommitStamp); ++ ++ /* Are there event queues? */ ++ if (Event->queueHead != gcvNULL) ++ { ++ /* Acquire the command queue. */ ++ gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower)); ++ commitEntered = gcvTRUE; ++ ++ /* Process all queues. */ ++ while (Event->queueHead != gcvNULL) ++ { ++ /* Acquire the list mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Event->os, ++ Event->eventListMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Get the current queue. */ ++ queue = Event->queueHead; ++ ++ /* Allocate an event ID. */ ++ gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->head, queue->source)); ++ ++ /* Copy event list to event ID queue. */ ++ Event->queues[id].head = queue->head; ++ ++ /* Remove the top queue from the list. */ ++ if (Event->queueHead == Event->queueTail) ++ { ++ Event->queueHead = gcvNULL; ++ Event->queueTail = gcvNULL; ++ } ++ else ++ { ++ Event->queueHead = Event->queueHead->next; ++ } ++ ++ /* Free the queue. */ ++ gcmkONERROR(gckEVENT_FreeQueue(Event, queue)); ++ ++ /* Release the list mutex. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); ++ acquired = gcvFALSE; ++ ++ /* Determine cache needed to flush. */ ++ gcmkVERIFY_OK(_QueryFlush(Event, Event->queues[id].head, &flush)); ++ ++#if gcdINTERRUPT_STATISTIC ++ gcmkVERIFY_OK(gckOS_AtomIncrement( ++ Event->os, ++ Event->interruptCount, ++ &oldValue ++ )); ++#endif ++ ++#if gcdNULL_DRIVER ++ /* Notify immediately on infinite hardware. */ ++ gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id)); ++ ++ gcmkONERROR(gckEVENT_Notify(Event, 0)); ++#else ++ /* Get the size of the hardware event. */ ++ gcmkONERROR(gckHARDWARE_Event( ++ hardware, ++ gcvNULL, ++ id, ++ Event->queues[id].source, ++ &bytes ++ )); ++ ++ /* Get the size of flush command. */ ++ gcmkONERROR(gckHARDWARE_Flush( ++ hardware, ++ flush, ++ gcvNULL, ++ &flushBytes ++ )); ++ ++ bytes += flushBytes; ++ ++ /* Total bytes need to execute. */ ++ executeBytes = bytes; ++ ++ /* Reserve space in the command queue. */ ++ gcmkONERROR(gckCOMMAND_Reserve(command, bytes, &buffer, &bytes)); ++ ++ /* Set the flush in the command queue. */ ++ gcmkONERROR(gckHARDWARE_Flush( ++ hardware, ++ flush, ++ buffer, ++ &flushBytes ++ )); ++ ++ /* Advance to next command. */ ++ buffer = (gctUINT8_PTR)buffer + flushBytes; ++ ++ /* Set the hardware event in the command queue. */ ++ gcmkONERROR(gckHARDWARE_Event( ++ hardware, ++ buffer, ++ id, ++ Event->queues[id].source, ++ &bytes ++ )); ++ ++ /* Advance to next command. */ ++ buffer = (gctUINT8_PTR)buffer + bytes; ++ ++ /* Execute the hardware event. */ ++ gcmkONERROR(gckCOMMAND_Execute(command, executeBytes)); ++#endif ++ } ++ ++ /* Release the command queue. */ ++ gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower)); ++ ++#if !gcdNULL_DRIVER ++ if (!FromCommand) ++ gcmkVERIFY_OK(_TryToIdleGPU(Event)); ++#endif ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Need to unroll the mutex acquire. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); ++ } ++ ++ if (commitEntered) ++ { ++ /* Release the command queue mutex. */ ++ gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower)); ++ } ++ ++ if (id != 0xFF) ++ { ++ /* Need to unroll the event allocation. */ ++ Event->queues[id].head = gcvNULL; ++ } ++ ++ if (status == gcvSTATUS_GPU_NOT_RESPONDING) ++ { ++ /* Broadcast GPU stuck. */ ++ status = gckOS_Broadcast(Event->os, ++ Event->kernel->hardware, ++ gcvBROADCAST_GPU_STUCK); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_Commit ++** ++** Commit an event queue from the user. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gcsQUEUE_PTR Queue ++** User event queue. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Commit( ++ IN gckEVENT Event, ++ IN gcsQUEUE_PTR Queue ++ ) ++{ ++ gceSTATUS status; ++ gcsQUEUE_PTR record = gcvNULL, next; ++ gctUINT32 processID; ++ gctBOOL needCopy = gcvFALSE; ++ ++ gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ /* Get the current process ID. */ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ /* Query if we need to copy the client data. */ ++ gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy)); ++ ++ /* Loop while there are records in the queue. */ ++ while (Queue != gcvNULL) ++ { ++ gcsQUEUE queue; ++ ++ if (needCopy) ++ { ++ /* Point to stack record. */ ++ record = &queue; ++ ++ /* Copy the data from the client. */ ++ gcmkONERROR(gckOS_CopyFromUserData(Event->os, ++ record, ++ Queue, ++ gcmSIZEOF(gcsQUEUE))); ++ } ++ else ++ { ++ gctPOINTER pointer = gcvNULL; ++ ++ /* Map record into kernel memory. */ ++ gcmkONERROR(gckOS_MapUserPointer(Event->os, ++ Queue, ++ gcmSIZEOF(gcsQUEUE), ++ &pointer)); ++ ++ record = pointer; ++ } ++ ++ /* Append event record to event queue. */ ++ gcmkONERROR( ++ gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE, gcvFALSE)); ++ ++ /* Next record in the queue. */ ++ next = gcmUINT64_TO_PTR(record->next); ++ ++ if (!needCopy) ++ { ++ /* Unmap record from kernel memory. */ ++ gcmkONERROR( ++ gckOS_UnmapUserPointer(Event->os, ++ Queue, ++ gcmSIZEOF(gcsQUEUE), ++ (gctPOINTER *) record)); ++ record = gcvNULL; ++ } ++ ++ Queue = next; ++ } ++ ++ /* Submit the event list. */ ++ gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE, gcvFALSE)); ++ ++ /* Success */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if ((record != gcvNULL) && !needCopy) ++ { ++ /* Roll back. */ ++ gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os, ++ Queue, ++ gcmSIZEOF(gcsQUEUE), ++ (gctPOINTER *) record)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_Compose ++** ++** Schedule a composition event and start a composition. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gcsHAL_COMPOSE_PTR Info ++** Pointer to the composition structure. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Compose( ++ IN gckEVENT Event, ++ IN gcsHAL_COMPOSE_PTR Info ++ ) ++{ ++ gceSTATUS status; ++ gcsEVENT_PTR headRecord; ++ gcsEVENT_PTR tailRecord; ++ gcsEVENT_PTR tempRecord; ++ gctUINT8 id = 0xFF; ++ gctUINT32 processID; ++ ++ gcmkHEADER_ARG("Event=0x%x Info=0x%x", Event, Info); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ gcmkVERIFY_ARGUMENT(Info != gcvNULL); ++ ++ /* Get process ID. */ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ /* Allocate a record. */ ++ gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord)); ++ headRecord = tailRecord = tempRecord; ++ ++ /* Initialize the record. */ ++ tempRecord->info.command = gcvHAL_SIGNAL; ++ tempRecord->info.u.Signal.process = Info->process; ++ tempRecord->info.u.Signal.signal = Info->signal; ++ tempRecord->info.u.Signal.auxSignal = 0; ++ tempRecord->next = gcvNULL; ++ tempRecord->processID = processID; ++ ++ /* Allocate another record for user signal #1. */ ++ if (gcmUINT64_TO_PTR(Info->userSignal1) != gcvNULL) ++ { ++ /* Allocate a record. */ ++ gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord)); ++ tailRecord->next = tempRecord; ++ tailRecord = tempRecord; ++ ++ /* Initialize the record. */ ++ tempRecord->info.command = gcvHAL_SIGNAL; ++ tempRecord->info.u.Signal.process = Info->userProcess; ++ tempRecord->info.u.Signal.signal = Info->userSignal1; ++ tempRecord->info.u.Signal.auxSignal = 0; ++ tempRecord->next = gcvNULL; ++ tempRecord->processID = processID; ++ } ++ ++ /* Allocate another record for user signal #2. */ ++ if (gcmUINT64_TO_PTR(Info->userSignal2) != gcvNULL) ++ { ++ /* Allocate a record. */ ++ gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord)); ++ tailRecord->next = tempRecord; ++ ++ /* Initialize the record. */ ++ tempRecord->info.command = gcvHAL_SIGNAL; ++ tempRecord->info.u.Signal.process = Info->userProcess; ++ tempRecord->info.u.Signal.signal = Info->userSignal2; ++ tempRecord->info.u.Signal.auxSignal = 0; ++ tempRecord->next = gcvNULL; ++ tempRecord->processID = processID; ++ } ++ ++ /* Allocate an event ID. */ ++ gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, headRecord, gcvKERNEL_PIXEL)); ++ ++ /* Start composition. */ ++ gcmkONERROR(gckHARDWARE_Compose( ++ Event->kernel->hardware, processID, ++ gcmUINT64_TO_PTR(Info->physical), gcmUINT64_TO_PTR(Info->logical), Info->offset, Info->size, id ++ )); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_Interrupt ++** ++** Called by the interrupt service routine to store the triggered interrupt ++** mask to be later processed by gckEVENT_Notify. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctUINT32 Data ++** Mask for the 32 interrupts. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Interrupt( ++ IN gckEVENT Event, ++ IN gctUINT32 Data ++ ) ++{ ++ unsigned long flags; ++ gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event, Data); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ if (Data & 0x20000000) ++ { ++ gckENTRYDATA data; ++ gctUINT32 idle; ++ Data &= ~0x20000000; ++ ++ /* Get first entry information. */ ++ gcmkVERIFY_OK( ++ gckENTRYQUEUE_Dequeue(&Event->kernel->command->queue, &data)); ++ ++ /* Make sure FE is idle. */ ++ do ++ { ++ gcmkVERIFY_OK(gckOS_ReadRegisterEx( ++ Event->os, ++ Event->kernel->core, ++ 0x4, ++ &idle)); ++ } ++ while (idle != 0x7FFFFFFF); ++ ++ /* Start Command Parser. */ ++ gcmkVERIFY_OK(gckHARDWARE_Execute( ++ Event->kernel->hardware, ++ data->physical, ++ data->bytes ++ )); ++ } ++ ++ /* Combine current interrupt status with pending flags. */ ++ spin_lock_irqsave(&Event->kernel->irq_lock, flags); ++#if gcdSMP ++ gckOS_AtomSetMask(Event->pending, Data); ++#else ++ Event->pending |= Data; ++#endif ++ spin_unlock_irqrestore(&Event->kernel->irq_lock, flags); ++ ++#if gcdINTERRUPT_STATISTIC ++ { ++ gctINT j = 0; ++ gctINT32 oldValue; ++ ++ for (j = 0; j < gcmCOUNTOF(Event->queues); j++) ++ { ++ if ((Data & (1 << j))) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDecrement(Event->os, ++ Event->interruptCount, ++ &oldValue)); ++ } ++ } ++ } ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckEVENT_Notify ++** ++** Process all triggered interrupts. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Notify( ++ IN gckEVENT Event, ++ IN gctUINT32 IDs ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gctINT i; ++ gcsEVENT_QUEUE * queue; ++ gctUINT mask = 0; ++ gctBOOL acquired = gcvFALSE; ++ gctPOINTER info; ++ gctSIGNAL signal; ++ gctUINT pending = 0; ++ gckKERNEL kernel = Event->kernel; ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gctINT eventNumber = 0; ++#endif ++ gctINT32 free; ++ gckVIDMEM_NODE nodeObject; ++ gcuVIDMEM_NODE_PTR node; ++ unsigned long flags; ++ ++ gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ gcmDEBUG_ONLY( ++ if (IDs != 0) ++ { ++ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) ++ { ++ if (Event->queues[i].head != gcvNULL) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "Queue(%d): stamp=%llu source=%d", ++ i, ++ Event->queues[i].stamp, ++ Event->queues[i].source); ++ } ++ } ++ } ++ ); ++ ++ for (;;) ++ { ++ gcsEVENT_PTR record; ++ ++ spin_lock_irqsave(&Event->kernel->irq_lock, flags); ++#if gcdSMP ++ gckOS_AtomGet(Event->os, Event->pending, (gctINT32_PTR)&pending); ++#else ++ pending = Event->pending; ++#endif ++ spin_unlock_irqrestore(&Event->kernel->irq_lock, flags); ++ ++ if (pending & 0x80000000) ++ { ++ gctUINT32 AQAxiStatus = 0; ++ gckOS_ReadRegisterEx(Event->os, Event->kernel->hardware->core, 0xC, &AQAxiStatus); ++ ++ gcmkPRINT("GPU[%d]: AXI BUS ERROR, AQAxiStatus=0x%x\n", Event->kernel->hardware->core, AQAxiStatus); ++ pending &= 0x7FFFFFFF; ++ } ++ ++ if (pending & 0x40000000) ++ { ++ gckHARDWARE_DumpMMUException(Event->kernel->hardware); ++ ++ pending &= 0xBFFFFFFF; ++ } ++ ++ if (pending == 0) ++ { ++ /* No more pending interrupts - done. */ ++ break; ++ } ++ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_INFO, gcvZONE_EVENT, ++ gcmSIZEOF(pending), ++ "Pending interrupts 0x%x", ++ pending ++ ); ++ ++ queue = gcvNULL; ++ ++ /* Grab the mutex queue. */ ++ gcmkONERROR(gckOS_AcquireMutex(Event->os, ++ Event->eventQueueMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ gcmDEBUG_ONLY( ++ if (IDs == 0) ++ { ++ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) ++ { ++ if (Event->queues[i].head != gcvNULL) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "Queue(%d): stamp=%llu source=%d", ++ i, ++ Event->queues[i].stamp, ++ Event->queues[i].source); ++ } ++ } ++ } ++ ); ++ ++ /* Find the oldest pending interrupt. */ ++ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) ++ { ++ if ((Event->queues[i].head != gcvNULL) ++ && (pending & (1 << i)) ++ ) ++ { ++ if ((queue == gcvNULL) ++ || (Event->queues[i].stamp < queue->stamp) ++ ) ++ { ++ queue = &Event->queues[i]; ++ mask = 1 << i; ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ eventNumber = i; ++#endif ++ } ++ } ++ } ++ ++ if (queue == gcvNULL) ++ { ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_ERROR, gcvZONE_EVENT, ++ gcmSIZEOF(pending), ++ "Interrupts 0x%x are not pending.", ++ pending ++ ); ++ ++ spin_lock_irqsave(&Event->kernel->irq_lock, flags); ++#if gcdSMP ++ gckOS_AtomClearMask(Event->pending, pending); ++#else ++ Event->pending &= ~pending; ++#endif ++ spin_unlock_irqrestore(&Event->kernel->irq_lock, flags); ++ ++ /* Release the mutex queue. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ acquired = gcvFALSE; ++ break; ++ } ++ ++ /* Check whether there is a missed interrupt. */ ++ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) ++ { ++ if ((Event->queues[i].head != gcvNULL) ++ && (Event->queues[i].stamp < queue->stamp) ++ && (Event->queues[i].source <= queue->source) ++ ) ++ { ++ gcmkTRACE_N( ++ gcvLEVEL_ERROR, ++ gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp), ++ "Event %d lost (stamp %llu)", ++ i, Event->queues[i].stamp ++ ); ++ ++ /* Use this event instead. */ ++ queue = &Event->queues[i]; ++ mask = 0; ++ } ++ } ++ ++ if (mask != 0) ++ { ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_INFO, gcvZONE_EVENT, ++ gcmSIZEOF(eventNumber), ++ "Processing interrupt %d", ++ eventNumber ++ ); ++#endif ++ } ++ ++ spin_lock_irqsave(&Event->kernel->irq_lock, flags); ++#if gcdSMP ++ gckOS_AtomClearMask(Event->pending, mask); ++#else ++ Event->pending &= ~mask; ++#endif ++ spin_unlock_irqrestore(&Event->kernel->irq_lock, flags); ++ ++ /* Grab the event head. */ ++ record = queue->head; ++ ++ /* Now quickly clear its event list. */ ++ queue->head = gcvNULL; ++ ++ /* Release the mutex queue. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ acquired = gcvFALSE; ++ ++ /* Increase the number of free events. */ ++ gcmkONERROR(gckOS_AtomIncrement(Event->os, Event->freeAtom, &free)); ++ ++ /* Walk all events for this interrupt. */ ++ while (record != gcvNULL) ++ { ++ gcsEVENT_PTR recordNext; ++ gctPOINTER logical; ++ ++ /* Grab next record. */ ++ recordNext = record->next; ++ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_INFO, gcvZONE_EVENT, ++ gcmSIZEOF(record->info.command), ++ "Processing event type: %d", ++ record->info.command ++ ); ++ ++ switch (record->info.command) ++ { ++ case gcvHAL_FREE_NON_PAGED_MEMORY: ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "gcvHAL_FREE_NON_PAGED_MEMORY: 0x%x", ++ gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical)); ++ ++ /* Free non-paged memory. */ ++ status = gckOS_FreeNonPagedMemory( ++ Event->os, ++ (gctSIZE_T) record->info.u.FreeNonPagedMemory.bytes, ++ gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical), ++ gcmUINT64_TO_PTR(record->info.u.FreeNonPagedMemory.logical)); ++ ++ gcmRELEASE_NAME(record->info.u.FreeNonPagedMemory.physical); ++ break; ++ ++ case gcvHAL_FREE_CONTIGUOUS_MEMORY: ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x", ++ gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical)); ++ ++ /* Unmap the user memory. */ ++ status = gckOS_FreeContiguous( ++ Event->os, ++ gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical), ++ gcmUINT64_TO_PTR(record->info.u.FreeContiguousMemory.logical), ++ (gctSIZE_T) record->info.u.FreeContiguousMemory.bytes); ++ ++ gcmRELEASE_NAME(record->info.u.FreeContiguousMemory.physical); ++ break; ++ ++ case gcvHAL_WRITE_DATA: ++ /* Convert physical into logical address. */ ++ gcmkERR_BREAK( ++ gckOS_MapPhysical(Event->os, ++ record->info.u.WriteData.address, ++ gcmSIZEOF(gctUINT32), ++ &logical)); ++ ++ /* Write data. */ ++ gcmkERR_BREAK( ++ gckOS_WriteMemory(Event->os, ++ logical, ++ record->info.u.WriteData.data)); ++ ++ /* Unmap the physical memory. */ ++ gcmkERR_BREAK( ++ gckOS_UnmapPhysical(Event->os, ++ logical, ++ gcmSIZEOF(gctUINT32))); ++ break; ++ ++ case gcvHAL_UNLOCK_VIDEO_MEMORY: ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x", ++ record->info.u.UnlockVideoMemory.node); ++ ++ nodeObject = gcmUINT64_TO_PTR(record->info.u.UnlockVideoMemory.node); ++ ++ node = nodeObject->node; ++ ++ /* Unlock. */ ++ status = gckVIDMEM_Unlock( ++ Event->kernel, ++ nodeObject, ++ record->info.u.UnlockVideoMemory.type, ++ gcvNULL); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock( ++ Event->kernel, ++ nodeObject, ++ record->processID ++ )); ++#endif ++ ++ status = gckVIDMEM_NODE_Dereference(Event->kernel, nodeObject); ++ break; ++ ++ case gcvHAL_SIGNAL: ++ signal = gcmUINT64_TO_PTR(record->info.u.Signal.signal); ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "gcvHAL_SIGNAL: 0x%x", ++ signal); ++ ++ /* User signal. */ ++ gcmkERR_BREAK( ++ gckOS_UserSignal(Event->os, ++ signal, ++ gcmUINT64_TO_PTR(record->info.u.Signal.process))); ++ ++ gcmkASSERT(record->info.u.Signal.auxSignal == 0); ++ break; ++ ++ case gcvHAL_UNMAP_USER_MEMORY: ++ info = gcmNAME_TO_PTR(record->info.u.UnmapUserMemory.info); ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "gcvHAL_UNMAP_USER_MEMORY: 0x%x", ++ info); ++ ++ /* Unmap the user memory. */ ++ status = gckOS_UnmapUserMemory( ++ Event->os, ++ Event->kernel->core, ++ gcmUINT64_TO_PTR(record->info.u.UnmapUserMemory.memory), ++ (gctSIZE_T) record->info.u.UnmapUserMemory.size, ++ info, ++ record->info.u.UnmapUserMemory.address); ++ ++ gcmRELEASE_NAME(record->info.u.UnmapUserMemory.info); ++ break; ++ ++ case gcvHAL_TIMESTAMP: ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "gcvHAL_TIMESTAMP: %d %d", ++ record->info.u.TimeStamp.timer, ++ record->info.u.TimeStamp.request); ++ ++ /* Process the timestamp. */ ++ switch (record->info.u.TimeStamp.request) ++ { ++ case 0: ++ status = gckOS_GetTime(&Event->kernel->timers[ ++ record->info.u.TimeStamp.timer]. ++ stopTime); ++ break; ++ ++ case 1: ++ status = gckOS_GetTime(&Event->kernel->timers[ ++ record->info.u.TimeStamp.timer]. ++ startTime); ++ break; ++ ++ default: ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_ERROR, gcvZONE_EVENT, ++ gcmSIZEOF(record->info.u.TimeStamp.request), ++ "Invalid timestamp request: %d", ++ record->info.u.TimeStamp.request ++ ); ++ ++ status = gcvSTATUS_INVALID_ARGUMENT; ++ break; ++ } ++ break; ++ ++ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER: ++ gcmkVERIFY_OK( ++ gckKERNEL_DestroyVirtualCommandBuffer(Event->kernel, ++ (gctSIZE_T) record->info.u.FreeVirtualCommandBuffer.bytes, ++ gcmNAME_TO_PTR(record->info.u.FreeVirtualCommandBuffer.physical), ++ gcmUINT64_TO_PTR(record->info.u.FreeVirtualCommandBuffer.logical) ++ )); ++ gcmRELEASE_NAME(record->info.u.FreeVirtualCommandBuffer.physical); ++ break; ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ case gcvHAL_SYNC_POINT: ++ { ++ gctSYNC_POINT syncPoint; ++ ++ syncPoint = gcmUINT64_TO_PTR(record->info.u.SyncPoint.syncPoint); ++ status = gckOS_SignalSyncPoint(Event->os, syncPoint); ++ } ++ break; ++#endif ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ case gcvHAL_DESTROY_MMU: ++ status = gckMMU_Destroy(gcmUINT64_TO_PTR(record->info.u.DestroyMmu.mmu)); ++ break; ++#endif ++ ++ case gcvHAL_COMMIT_DONE: ++ break; ++ ++ default: ++ /* Invalid argument. */ ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_ERROR, gcvZONE_EVENT, ++ gcmSIZEOF(record->info.command), ++ "Unknown event type: %d", ++ record->info.command ++ ); ++ ++ status = gcvSTATUS_INVALID_ARGUMENT; ++ break; ++ } ++ ++ /* Make sure there are no errors generated. */ ++ if (gcmIS_ERROR(status)) ++ { ++ gcmkTRACE_ZONE_N( ++ gcvLEVEL_WARNING, gcvZONE_EVENT, ++ gcmSIZEOF(status), ++ "Event produced status: %d(%s)", ++ status, gckOS_DebugStatus2Name(status)); ++ } ++ ++ /* Free the event. */ ++ gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record)); ++ ++ /* Advance to next record. */ ++ record = recordNext; ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, ++ "Handled interrupt 0x%x", mask); ++ } ++ ++ if (IDs == 0) ++ { ++ gcmkONERROR(_TryToIdleGPU(Event)); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckEVENT_FreeProcess ++** ++** Free all events owned by a particular process ID. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctUINT32 ProcessID ++** Process ID of the process to be freed up. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_FreeProcess( ++ IN gckEVENT Event, ++ IN gctUINT32 ProcessID ++ ) ++{ ++ gctSIZE_T i; ++ gctBOOL acquired = gcvFALSE; ++ gcsEVENT_PTR record, next; ++ gceSTATUS status; ++ gcsEVENT_PTR deleteHead, deleteTail; ++ ++ gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ /* Walk through all queues. */ ++ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) ++ { ++ if (Event->queues[i].head != gcvNULL) ++ { ++ /* Grab the event queue mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Event->os, ++ Event->eventQueueMutex, ++ gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Grab the mutex head. */ ++ record = Event->queues[i].head; ++ Event->queues[i].head = gcvNULL; ++ Event->queues[i].tail = gcvNULL; ++ deleteHead = gcvNULL; ++ deleteTail = gcvNULL; ++ ++ while (record != gcvNULL) ++ { ++ next = record->next; ++ if (record->processID == ProcessID) ++ { ++ if (deleteHead == gcvNULL) ++ { ++ deleteHead = record; ++ } ++ else ++ { ++ deleteTail->next = record; ++ } ++ ++ deleteTail = record; ++ } ++ else ++ { ++ if (Event->queues[i].head == gcvNULL) ++ { ++ Event->queues[i].head = record; ++ } ++ else ++ { ++ Event->queues[i].tail->next = record; ++ } ++ ++ Event->queues[i].tail = record; ++ } ++ ++ record->next = gcvNULL; ++ record = next; ++ } ++ ++ /* Release the mutex queue. */ ++ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ acquired = gcvFALSE; ++ ++ /* Loop through the entire list of events. */ ++ for (record = deleteHead; record != gcvNULL; record = next) ++ { ++ /* Get the next event record. */ ++ next = record->next; ++ ++ /* Free the event record. */ ++ gcmkONERROR(gckEVENT_FreeRecord(Event, record)); ++ } ++ } ++ } ++ ++ gcmkONERROR(_TryToIdleGPU(Event)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Release the event queue mutex. */ ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** gckEVENT_Stop ++** ++** Stop the hardware using the End event mechanism. ++** ++** INPUT: ++** ++** gckEVENT Event ++** Pointer to an gckEVENT object. ++** ++** gctUINT32 ProcessID ++** Process ID Logical belongs. ++** ++** gctPHYS_ADDR Handle ++** Physical address handle. If gcvNULL it is video memory. ++** ++** gctPOINTER Logical ++** Logical address to flush. ++** ++** gctSIGNAL Signal ++** Pointer to the signal to trigger. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckEVENT_Stop( ++ IN gckEVENT Event, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Handle, ++ IN gctPOINTER Logical, ++ IN gctSIGNAL Signal, ++ IN OUT gctUINT32 * waitSize ++ ) ++{ ++ gceSTATUS status; ++ /* gctSIZE_T waitSize;*/ ++ gcsEVENT_PTR record; ++ gctUINT8 id = 0xFF; ++ ++ gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x " ++ "Signal=0x%x", ++ Event, ProcessID, Handle, Logical, Signal); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); ++ ++ /* Submit the current event queue. */ ++ gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE, gcvFALSE)); ++ ++ /* Allocate a record. */ ++ gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &record)); ++ ++ /* Initialize the record. */ ++ record->next = gcvNULL; ++ record->processID = ProcessID; ++ record->info.command = gcvHAL_SIGNAL; ++ record->info.u.Signal.signal = gcmPTR_TO_UINT64(Signal); ++ record->info.u.Signal.auxSignal = 0; ++ record->info.u.Signal.process = 0; ++ ++ ++ gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, record, gcvKERNEL_PIXEL)); ++ ++ /* Replace last WAIT with END. */ ++ gcmkONERROR(gckHARDWARE_End( ++ Event->kernel->hardware, Logical, waitSize ++ )); ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Flush the cache for the END. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Event->os, ++ ProcessID, ++ gcvNULL, ++ (gctUINT32)Handle, ++ Logical, ++ *waitSize ++ )); ++#endif ++ ++ /* Wait for the signal. */ ++ gcmkONERROR(gckOS_WaitSignal(Event->os, Signal, gcvINFINITE)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static void ++_PrintRecord( ++ gcsEVENT_PTR record ++ ) ++{ ++ switch (record->info.command) ++ { ++ case gcvHAL_FREE_NON_PAGED_MEMORY: ++ gcmkPRINT(" gcvHAL_FREE_NON_PAGED_MEMORY"); ++ break; ++ ++ case gcvHAL_FREE_CONTIGUOUS_MEMORY: ++ gcmkPRINT(" gcvHAL_FREE_CONTIGUOUS_MEMORY"); ++ break; ++ ++ case gcvHAL_WRITE_DATA: ++ gcmkPRINT(" gcvHAL_WRITE_DATA"); ++ break; ++ ++ case gcvHAL_UNLOCK_VIDEO_MEMORY: ++ gcmkPRINT(" gcvHAL_UNLOCK_VIDEO_MEMORY"); ++ break; ++ ++ case gcvHAL_SIGNAL: ++ gcmkPRINT(" gcvHAL_SIGNAL process=%d signal=0x%x", ++ record->info.u.Signal.process, ++ record->info.u.Signal.signal); ++ break; ++ ++ case gcvHAL_UNMAP_USER_MEMORY: ++ gcmkPRINT(" gcvHAL_UNMAP_USER_MEMORY"); ++ break; ++ ++ case gcvHAL_TIMESTAMP: ++ gcmkPRINT(" gcvHAL_TIMESTAMP"); ++ break; ++ ++ case gcvHAL_COMMIT_DONE: ++ gcmkPRINT(" gcvHAL_COMMIT_DONE"); ++ break; ++ ++ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER: ++ gcmkPRINT(" gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER logical=0x%08x", ++ record->info.u.FreeVirtualCommandBuffer.logical); ++ break; ++ ++ case gcvHAL_SYNC_POINT: ++ gcmkPRINT(" gcvHAL_SYNC_POINT syncPoint=0x%08x", ++ gcmUINT64_TO_PTR(record->info.u.SyncPoint.syncPoint)); ++ ++ break; ++ ++ case gcvHAL_DESTROY_MMU: ++ gcmkPRINT(" gcvHAL_DESTORY_MMU mmu=0x%08x", ++ gcmUINT64_TO_PTR(record->info.u.DestroyMmu.mmu)); ++ ++ break; ++ default: ++ gcmkPRINT(" Illegal Event %d", record->info.command); ++ break; ++ } ++} ++ ++/******************************************************************************* ++** gckEVENT_Dump ++** ++** Dump record in event queue when stuck happens. ++** No protection for the event queue. ++**/ ++gceSTATUS ++gckEVENT_Dump( ++ IN gckEVENT Event ++ ) ++{ ++ gcsEVENT_QUEUE_PTR queueHead = Event->queueHead; ++ gcsEVENT_QUEUE_PTR queue; ++ gcsEVENT_PTR record = gcvNULL; ++ gctINT i; ++#if gcdINTERRUPT_STATISTIC ++ gctINT32 pendingInterrupt; ++ gctUINT32 intrAcknowledge; ++#endif ++ ++ gcmkHEADER_ARG("Event=0x%x", Event); ++ ++ gcmkPRINT("**************************\n"); ++ gcmkPRINT("*** EVENT STATE DUMP ***\n"); ++ gcmkPRINT("**************************\n"); ++ ++ gcmkPRINT(" Unsumbitted Event:"); ++ while(queueHead) ++ { ++ queue = queueHead; ++ record = queueHead->head; ++ ++ gcmkPRINT(" [%x]:", queue); ++ while(record) ++ { ++ _PrintRecord(record); ++ record = record->next; ++ } ++ ++ if (queueHead == Event->queueTail) ++ { ++ queueHead = gcvNULL; ++ } ++ else ++ { ++ queueHead = queueHead->next; ++ } ++ } ++ ++ gcmkPRINT(" Untriggered Event:"); ++ for (i = 0; i < gcmCOUNTOF(Event->queues); i++) ++ { ++ queue = &Event->queues[i]; ++ record = queue->head; ++ ++ gcmkPRINT(" [%d]:", i); ++ while(record) ++ { ++ _PrintRecord(record); ++ record = record->next; ++ } ++ } ++ ++#if gcdINTERRUPT_STATISTIC ++ gckOS_AtomGet(Event->os, Event->interruptCount, &pendingInterrupt); ++ gcmkPRINT(" Number of Pending Interrupt: %d", pendingInterrupt); ++ ++ if (Event->kernel->recovery == 0) ++ { ++ gckOS_ReadRegisterEx( ++ Event->os, ++ Event->kernel->core, ++ 0x10, ++ &intrAcknowledge ++ ); ++ ++ gcmkPRINT(" INTR_ACKNOWLEDGE=0x%x", intrAcknowledge); ++ } ++#endif ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel.h 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,1353 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_h_ ++#define __gc_hal_kernel_h_ ++ ++#include ++ ++#include "gc_hal.h" ++#include "gc_hal_kernel_hardware.h" ++#include "gc_hal_driver.h" ++ ++#if gcdENABLE_VG ++#include "gc_hal_kernel_vg.h" ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/******************************************************************************* ++***** New MMU Defination *******************************************************/ ++#define gcdMMU_MTLB_SHIFT 22 ++#define gcdMMU_STLB_4K_SHIFT 12 ++#define gcdMMU_STLB_64K_SHIFT 16 ++ ++#define gcdMMU_MTLB_BITS (32 - gcdMMU_MTLB_SHIFT) ++#define gcdMMU_PAGE_4K_BITS gcdMMU_STLB_4K_SHIFT ++#define gcdMMU_STLB_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS) ++#define gcdMMU_PAGE_64K_BITS gcdMMU_STLB_64K_SHIFT ++#define gcdMMU_STLB_64K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS) ++ ++#define gcdMMU_MTLB_ENTRY_NUM (1 << gcdMMU_MTLB_BITS) ++#define gcdMMU_MTLB_SIZE (gcdMMU_MTLB_ENTRY_NUM << 2) ++#define gcdMMU_STLB_4K_ENTRY_NUM (1 << gcdMMU_STLB_4K_BITS) ++#define gcdMMU_STLB_4K_SIZE (gcdMMU_STLB_4K_ENTRY_NUM << 2) ++#define gcdMMU_PAGE_4K_SIZE (1 << gcdMMU_STLB_4K_SHIFT) ++#define gcdMMU_STLB_64K_ENTRY_NUM (1 << gcdMMU_STLB_64K_BITS) ++#define gcdMMU_STLB_64K_SIZE (gcdMMU_STLB_64K_ENTRY_NUM << 2) ++#define gcdMMU_PAGE_64K_SIZE (1 << gcdMMU_STLB_64K_SHIFT) ++ ++#define gcdMMU_MTLB_MASK (~((1U << gcdMMU_MTLB_SHIFT)-1)) ++#define gcdMMU_STLB_4K_MASK ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK) ++#define gcdMMU_PAGE_4K_MASK (gcdMMU_PAGE_4K_SIZE - 1) ++#define gcdMMU_STLB_64K_MASK ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK) ++#define gcdMMU_PAGE_64K_MASK (gcdMMU_PAGE_64K_SIZE - 1) ++ ++/* Page offset definitions. */ ++#define gcdMMU_OFFSET_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_4K_BITS) ++#define gcdMMU_OFFSET_4K_MASK ((1U << gcdMMU_OFFSET_4K_BITS) - 1) ++#define gcdMMU_OFFSET_16K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_16K_BITS) ++#define gcdMMU_OFFSET_16K_MASK ((1U << gcdMMU_OFFSET_16K_BITS) - 1) ++ ++#define gcdMMU_MTLB_PRESENT 0x00000001 ++#define gcdMMU_MTLB_EXCEPTION 0x00000002 ++#define gcdMMU_MTLB_4K_PAGE 0x00000000 ++ ++#define gcdMMU_STLB_PRESENT 0x00000001 ++#define gcdMMU_STLB_EXCEPTION 0x00000002 ++#define gcdMMU_STLB_4K_PAGE 0x00000000 ++ ++/******************************************************************************* ++***** Stuck Dump Level ********************************************************/ ++ ++#define gcdSTUCK_DUMP_MINIMAL 1 ++#define gcdSTUCK_DUMP_MIDDLE 2 ++#define gcdSTUCK_DUMP_MAXIMAL 3 ++ ++/******************************************************************************* ++***** Process Secure Cache ****************************************************/ ++ ++#define gcdSECURE_CACHE_LRU 1 ++#define gcdSECURE_CACHE_LINEAR 2 ++#define gcdSECURE_CACHE_HASH 3 ++#define gcdSECURE_CACHE_TABLE 4 ++ ++#define gcvPAGE_TABLE_DIRTY_BIT_OTHER (1 << 0) ++#define gcvPAGE_TABLE_DIRTY_BIT_FE (1 << 1) ++ ++typedef struct _gcskLOGICAL_CACHE * gcskLOGICAL_CACHE_PTR; ++typedef struct _gcskLOGICAL_CACHE gcskLOGICAL_CACHE; ++struct _gcskLOGICAL_CACHE ++{ ++ /* Logical address. */ ++ gctPOINTER logical; ++ ++ /* DMAable address. */ ++ gctUINT32 dma; ++ ++#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH ++ /* Pointer to the previous and next hash tables. */ ++ gcskLOGICAL_CACHE_PTR nextHash; ++ gcskLOGICAL_CACHE_PTR prevHash; ++#endif ++ ++#if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE ++ /* Pointer to the previous and next slot. */ ++ gcskLOGICAL_CACHE_PTR next; ++ gcskLOGICAL_CACHE_PTR prev; ++#endif ++ ++#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR ++ /* Time stamp. */ ++ gctUINT64 stamp; ++#endif ++}; ++ ++typedef struct _gcskSECURE_CACHE * gcskSECURE_CACHE_PTR; ++typedef struct _gcskSECURE_CACHE ++{ ++ /* Cache memory. */ ++ gcskLOGICAL_CACHE cache[1 + gcdSECURE_CACHE_SLOTS]; ++ ++ /* Last known index for LINEAR mode. */ ++ gcskLOGICAL_CACHE_PTR cacheIndex; ++ ++ /* Current free slot for LINEAR mode. */ ++ gctUINT32 cacheFree; ++ ++ /* Time stamp for LINEAR mode. */ ++ gctUINT64 cacheStamp; ++ ++#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH ++ /* Hash table for HASH mode. */ ++ gcskLOGICAL_CACHE hash[256]; ++#endif ++} ++gcskSECURE_CACHE; ++ ++/******************************************************************************* ++***** Process Database Management *********************************************/ ++ ++typedef enum _gceDATABASE_TYPE ++{ ++ gcvDB_VIDEO_MEMORY = 1, /* Video memory created. */ ++ gcvDB_COMMAND_BUFFER, /* Command Buffer. */ ++ gcvDB_NON_PAGED, /* Non paged memory. */ ++ gcvDB_CONTIGUOUS, /* Contiguous memory. */ ++ gcvDB_SIGNAL, /* Signal. */ ++ gcvDB_VIDEO_MEMORY_LOCKED, /* Video memory locked. */ ++ gcvDB_CONTEXT, /* Context */ ++ gcvDB_IDLE, /* GPU idle. */ ++ gcvDB_MAP_MEMORY, /* Map memory */ ++ gcvDB_MAP_USER_MEMORY, /* Map user memory */ ++ gcvDB_SYNC_POINT, /* Sync point. */ ++ gcvDB_SHBUF, /* Shared buffer. */ ++} ++gceDATABASE_TYPE; ++ ++#define gcdDATABASE_TYPE_MASK 0x000000FF ++#define gcdDB_VIDEO_MEMORY_TYPE_MASK 0x0000FF00 ++#define gcdDB_VIDEO_MEMORY_TYPE_SHIFT 8 ++ ++#define gcdDB_VIDEO_MEMORY_POOL_MASK 0x00FF0000 ++#define gcdDB_VIDEO_MEMORY_POOL_SHIFT 16 ++ ++typedef struct _gcsDATABASE_RECORD * gcsDATABASE_RECORD_PTR; ++typedef struct _gcsDATABASE_RECORD ++{ ++ /* Pointer to kernel. */ ++ gckKERNEL kernel; ++ ++ /* Pointer to next database record. */ ++ gcsDATABASE_RECORD_PTR next; ++ ++ /* Type of record. */ ++ gceDATABASE_TYPE type; ++ ++ /* Data for record. */ ++ gctPOINTER data; ++ gctPHYS_ADDR physical; ++ gctSIZE_T bytes; ++} ++gcsDATABASE_RECORD; ++ ++typedef struct _gcsDATABASE * gcsDATABASE_PTR; ++typedef struct _gcsDATABASE ++{ ++ /* Pointer to next entry is hash list. */ ++ gcsDATABASE_PTR next; ++ gctSIZE_T slot; ++ ++ /* Process ID. */ ++ gctUINT32 processID; ++ ++ /* Sizes to query. */ ++ gcsDATABASE_COUNTERS vidMem; ++ gcsDATABASE_COUNTERS nonPaged; ++ gcsDATABASE_COUNTERS contiguous; ++ gcsDATABASE_COUNTERS mapUserMemory; ++ gcsDATABASE_COUNTERS mapMemory; ++ gcsDATABASE_COUNTERS virtualCommandBuffer; ++ ++ gcsDATABASE_COUNTERS vidMemType[gcvSURF_NUM_TYPES]; ++ /* Counter for each video memory pool. */ ++ gcsDATABASE_COUNTERS vidMemPool[gcvPOOL_NUMBER_OF_POOLS]; ++ gctPOINTER counterMutex; ++ ++ /* Idle time management. */ ++ gctUINT64 lastIdle; ++ gctUINT64 idle; ++ ++ /* Pointer to database. */ ++ gcsDATABASE_RECORD_PTR list[48]; ++ ++ gctPOINTER handleDatabase; ++ gctPOINTER handleDatabaseMutex; ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gckMMU mmu; ++#endif ++} ++gcsDATABASE; ++ ++typedef struct _gcsRECORDER * gckRECORDER; ++ ++typedef struct _gcsFDPRIVATE * gcsFDPRIVATE_PTR; ++typedef struct _gcsFDPRIVATE ++{ ++ gctINT (* release) (gcsFDPRIVATE_PTR Private); ++} ++gcsFDPRIVATE; ++ ++/* Create a process database that will contain all its allocations. */ ++gceSTATUS ++gckKERNEL_CreateProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID ++ ); ++ ++/* Add a record to the process database. */ ++gceSTATUS ++gckKERNEL_AddProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Pointer, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Size ++ ); ++ ++/* Remove a record to the process database. */ ++gceSTATUS ++gckKERNEL_RemoveProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Pointer ++ ); ++ ++/* Destroy the process database. */ ++gceSTATUS ++gckKERNEL_DestroyProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID ++ ); ++ ++/* Find a record to the process database. */ ++gceSTATUS ++gckKERNEL_FindProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 ThreadID, ++ IN gceDATABASE_TYPE Type, ++ IN gctPOINTER Pointer, ++ OUT gcsDATABASE_RECORD_PTR Record ++ ); ++ ++/* Query the process database. */ ++gceSTATUS ++gckKERNEL_QueryProcessDB( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctBOOL LastProcessID, ++ IN gceDATABASE_TYPE Type, ++ OUT gcuDATABASE_INFO * Info ++ ); ++ ++/* Dump the process database. */ ++gceSTATUS ++gckKERNEL_DumpProcessDB( ++ IN gckKERNEL Kernel ++ ); ++ ++/* Dump the video memory usage for process specified. */ ++gceSTATUS ++gckKERNEL_DumpVidMemUsage( ++ IN gckKERNEL Kernel, ++ IN gctINT32 ProcessID ++ ); ++ ++gceSTATUS ++gckKERNEL_FindDatabase( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctBOOL LastProcessID, ++ OUT gcsDATABASE_PTR * Database ++ ); ++ ++gceSTATUS ++gckKERNEL_FindHandleDatbase( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ OUT gctPOINTER * HandleDatabase, ++ OUT gctPOINTER * HandleDatabaseMutex ++ ); ++ ++gceSTATUS ++gckKERNEL_GetProcessMMU( ++ IN gckKERNEL Kernel, ++ OUT gckMMU * Mmu ++ ); ++ ++gceSTATUS ++gckKERNEL_SetRecovery( ++ IN gckKERNEL Kernel, ++ IN gctBOOL Recovery, ++ IN gctUINT32 StuckDump ++ ); ++ ++gceSTATUS ++gckMMU_FlatMapping( ++ IN gckMMU Mmu, ++ IN gctUINT32 Physical ++ ); ++ ++gceSTATUS ++gckMMU_GetPageEntry( ++ IN gckMMU Mmu, ++ IN gctUINT32 Address, ++ IN gctUINT32_PTR *PageTable ++ ); ++ ++gceSTATUS ++gckMMU_FreePagesEx( ++ IN gckMMU Mmu, ++ IN gctUINT32 Address, ++ IN gctSIZE_T PageCount ++ ); ++ ++gceSTATUS ++gckKERNEL_CreateIntegerDatabase( ++ IN gckKERNEL Kernel, ++ OUT gctPOINTER * Database ++ ); ++ ++gceSTATUS ++gckKERNEL_DestroyIntegerDatabase( ++ IN gckKERNEL Kernel, ++ IN gctPOINTER Database ++ ); ++ ++gceSTATUS ++gckKERNEL_AllocateIntegerId( ++ IN gctPOINTER Database, ++ IN gctPOINTER Pointer, ++ OUT gctUINT32 * Id ++ ); ++ ++gceSTATUS ++gckKERNEL_FreeIntegerId( ++ IN gctPOINTER Database, ++ IN gctUINT32 Id ++ ); ++ ++gceSTATUS ++gckKERNEL_QueryIntegerId( ++ IN gctPOINTER Database, ++ IN gctUINT32 Id, ++ OUT gctPOINTER * Pointer ++ ); ++ ++/* Pointer rename */ ++gctUINT32 ++gckKERNEL_AllocateNameFromPointer( ++ IN gckKERNEL Kernel, ++ IN gctPOINTER Pointer ++ ); ++ ++gctPOINTER ++gckKERNEL_QueryPointerFromName( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Name ++ ); ++ ++gceSTATUS ++gckKERNEL_DeleteName( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Name ++ ); ++ ++/******************************************************************************* ++********* Timer Management ****************************************************/ ++typedef struct _gcsTIMER * gcsTIMER_PTR; ++typedef struct _gcsTIMER ++{ ++ /* Start and Stop time holders. */ ++ gctUINT64 startTime; ++ gctUINT64 stopTime; ++} ++gcsTIMER; ++ ++/******************************************************************************\ ++********************************** Structures ********************************** ++\******************************************************************************/ ++ ++/* gckDB object. */ ++struct _gckDB ++{ ++ /* Database management. */ ++ gcsDATABASE_PTR db[16]; ++ gctPOINTER dbMutex; ++ gcsDATABASE_PTR freeDatabase; ++ gcsDATABASE_RECORD_PTR freeRecord; ++ gcsDATABASE_PTR lastDatabase; ++ gctUINT32 lastProcessID; ++ gctUINT64 lastIdle; ++ gctUINT64 idleTime; ++ gctUINT64 lastSlowdown; ++ gctUINT64 lastSlowdownIdle; ++ gctPOINTER nameDatabase; ++ gctPOINTER nameDatabaseMutex; ++ ++ gctPOINTER pointerDatabase; ++ gctPOINTER pointerDatabaseMutex; ++}; ++ ++typedef struct _gckVIRTUAL_COMMAND_BUFFER * gckVIRTUAL_COMMAND_BUFFER_PTR; ++typedef struct _gckVIRTUAL_COMMAND_BUFFER ++{ ++ gctPHYS_ADDR physical; ++ gctPOINTER userLogical; ++ gctPOINTER kernelLogical; ++ gctSIZE_T bytes; ++ gctSIZE_T pageCount; ++ gctPOINTER pageTable; ++ gctUINT32 gpuAddress; ++ gctUINT pid; ++ gckVIRTUAL_COMMAND_BUFFER_PTR next; ++ gckVIRTUAL_COMMAND_BUFFER_PTR prev; ++ gckKERNEL kernel; ++#if gcdPROCESS_ADDRESS_SPACE ++ gckMMU mmu; ++#endif ++} ++gckVIRTUAL_COMMAND_BUFFER; ++ ++/* gckKERNEL object. */ ++struct _gckKERNEL ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gckOS object. */ ++ gckOS os; ++ ++ /* Core */ ++ gceCORE core; ++ ++ /* Pointer to gckHARDWARE object. */ ++ gckHARDWARE hardware; ++ ++ /* Pointer to gckCOMMAND object. */ ++ gckCOMMAND command; ++ ++ /* Pointer to gckEVENT object. */ ++ gckEVENT eventObj; ++ ++ /* Pointer to context. */ ++ gctPOINTER context; ++ ++ /* Pointer to gckMMU object. */ ++ gckMMU mmu; ++ ++ /* Arom holding number of clients. */ ++ gctPOINTER atomClients; ++ ++#if VIVANTE_PROFILER ++ /* Enable profiling */ ++ gctBOOL profileEnable; ++ /* Clear profile register or not*/ ++ gctBOOL profileCleanRegister; ++#endif ++ ++ /* Database management. */ ++ gckDB db; ++ gctBOOL dbCreated; ++ ++ gctUINT64 resetTimeStamp; ++ ++ /* Pointer to gckEVENT object. */ ++ gcsTIMER timers[8]; ++ gctUINT32 timeOut; ++ ++#if gcdENABLE_VG ++ gckVGKERNEL vg; ++#endif ++ ++ /* Virtual command buffer list. */ ++ gckVIRTUAL_COMMAND_BUFFER_PTR virtualBufferHead; ++ gckVIRTUAL_COMMAND_BUFFER_PTR virtualBufferTail; ++ gctPOINTER virtualBufferLock; ++ ++ /* Enable virtual command buffer. */ ++ gctBOOL virtualCommandBuffer; ++ ++#if gcdDVFS ++ gckDVFS dvfs; ++#endif ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ gctHANDLE timeline; ++#endif ++ ++ /* Enable recovery. */ ++ gctBOOL recovery; ++ ++ /* Level of dump information after stuck. */ ++ gctUINT stuckDump; ++ ++ /* Timer to monitor GPU stuck. */ ++ gctPOINTER monitorTimer; ++ ++ /* Flag to quit monitor timer. */ ++ gctBOOL monitorTimerStop; ++ ++ /* Monitor states. */ ++ gctBOOL monitoring; ++ gctUINT32 lastCommitStamp; ++ gctUINT32 timer; ++ gctUINT32 restoreAddress; ++ gctUINT32 restoreMask; ++ ++ spinlock_t irq_lock; ++}; ++ ++struct _FrequencyHistory ++{ ++ gctUINT32 frequency; ++ gctUINT32 count; ++}; ++ ++/* gckDVFS object. */ ++struct _gckDVFS ++{ ++ gckOS os; ++ gckHARDWARE hardware; ++ gctPOINTER timer; ++ gctUINT32 pollingTime; ++ gctBOOL stop; ++ gctUINT32 totalConfig; ++ gctUINT32 loads[8]; ++ gctUINT8 currentScale; ++ struct _FrequencyHistory frequencyHistory[16]; ++}; ++ ++/* gckCOMMAND object. */ ++struct _gckCOMMAND ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to required object. */ ++ gckKERNEL kernel; ++ gckOS os; ++ ++ /* Number of bytes per page. */ ++ gctUINT32 pageSize; ++ ++ /* Current pipe select. */ ++ gcePIPE_SELECT pipeSelect; ++ ++ /* Command queue running flag. */ ++ gctBOOL running; ++ ++ /* Idle flag and commit stamp. */ ++ gctBOOL idle; ++ gctUINT64 commitStamp; ++ ++ /* Command queue mutex. */ ++ gctPOINTER mutexQueue; ++ ++ /* Context switching mutex. */ ++ gctPOINTER mutexContext; ++ ++#if VIVANTE_PROFILER_CONTEXT ++ /* Context sequence mutex. */ ++ gctPOINTER mutexContextSeq; ++#endif ++ ++ /* Command queue power semaphore. */ ++ gctPOINTER powerSemaphore; ++ ++ /* Current command queue. */ ++ struct _gcskCOMMAND_QUEUE ++ { ++ gctSIGNAL signal; ++ gctPHYS_ADDR physical; ++ gctPOINTER logical; ++ gctUINT32 address; ++ } ++ queues[gcdCOMMAND_QUEUES]; ++ ++ gctPHYS_ADDR physical; ++ gctPOINTER logical; ++ gctUINT32 address; ++ gctUINT32 offset; ++ gctINT index; ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++ gctUINT wrapCount; ++#endif ++ ++ /* The command queue is new. */ ++ gctBOOL newQueue; ++ ++ /* Context management. */ ++ gckCONTEXT currContext; ++ ++ /* Pointer to last WAIT command. */ ++ gctPHYS_ADDR waitPhysical; ++ gctPOINTER waitLogical; ++ gctUINT32 waitSize; ++ ++ /* Command buffer alignment. */ ++ gctUINT32 alignment; ++ gctUINT32 reservedHead; ++ gctUINT32 reservedTail; ++ ++ /* Commit counter. */ ++ gctPOINTER atomCommit; ++ ++ /* Kernel process ID. */ ++ gctUINT32 kernelProcessID; ++ ++ /* End Event signal. */ ++ gctSIGNAL endEventSignal; ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gckMMU currentMmu; ++#endif ++ struct _gckENTRYQUEUE queue; ++}; ++ ++typedef struct _gcsEVENT * gcsEVENT_PTR; ++ ++/* Structure holding one event to be processed. */ ++typedef struct _gcsEVENT ++{ ++ /* Pointer to next event in queue. */ ++ gcsEVENT_PTR next; ++ ++ /* Event information. */ ++ gcsHAL_INTERFACE info; ++ ++ /* Process ID owning the event. */ ++ gctUINT32 processID; ++ ++ gctBOOL fromKernel; ++} ++gcsEVENT; ++ ++/* Structure holding a list of events to be processed by an interrupt. */ ++typedef struct _gcsEVENT_QUEUE * gcsEVENT_QUEUE_PTR; ++typedef struct _gcsEVENT_QUEUE ++{ ++ /* Time stamp. */ ++ gctUINT64 stamp; ++ ++ /* Source of the event. */ ++ gceKERNEL_WHERE source; ++ ++ /* Pointer to head of event queue. */ ++ gcsEVENT_PTR head; ++ ++ /* Pointer to tail of event queue. */ ++ gcsEVENT_PTR tail; ++ ++ /* Next list of events. */ ++ gcsEVENT_QUEUE_PTR next; ++} ++gcsEVENT_QUEUE; ++ ++/* ++ gcdREPO_LIST_COUNT defines the maximum number of event queues with different ++ hardware module sources that may coexist at the same time. Only two sources ++ are supported - gcvKERNEL_COMMAND and gcvKERNEL_PIXEL. gcvKERNEL_COMMAND ++ source is used only for managing the kernel command queue and is only issued ++ when the current command queue gets full. Since we commit event queues every ++ time we commit command buffers, in the worst case we can have up to three ++ pending event queues: ++ - gcvKERNEL_PIXEL ++ - gcvKERNEL_COMMAND (queue overflow) ++ - gcvKERNEL_PIXEL ++*/ ++#define gcdREPO_LIST_COUNT 3 ++ ++/* gckEVENT object. */ ++struct _gckEVENT ++{ ++ /* The object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to required objects. */ ++ gckOS os; ++ gckKERNEL kernel; ++ ++ /* Time stamp. */ ++ gctUINT64 stamp; ++ gctUINT32 lastCommitStamp; ++ ++ /* Queue mutex. */ ++ gctPOINTER eventQueueMutex; ++ ++ /* Array of event queues. */ ++ gcsEVENT_QUEUE queues[29]; ++ gctUINT8 lastID; ++ gctPOINTER freeAtom; ++ ++ /* Pending events. */ ++#if gcdSMP ++ gctPOINTER pending; ++#else ++ volatile gctUINT pending; ++#endif ++ ++ /* List of free event structures and its mutex. */ ++ gcsEVENT_PTR freeEventList; ++ gctSIZE_T freeEventCount; ++ gctPOINTER freeEventMutex; ++ ++ /* Event queues. */ ++ gcsEVENT_QUEUE_PTR queueHead; ++ gcsEVENT_QUEUE_PTR queueTail; ++ gcsEVENT_QUEUE_PTR freeList; ++ gcsEVENT_QUEUE repoList[gcdREPO_LIST_COUNT]; ++ gctPOINTER eventListMutex; ++ ++ gctPOINTER submitTimer; ++ ++#if gcdINTERRUPT_STATISTIC ++ gctPOINTER interruptCount; ++#endif ++ ++#if gcdRECORD_COMMAND ++ gckRECORDER recorder; ++#endif ++}; ++ ++/* Free all events belonging to a process. */ ++gceSTATUS ++gckEVENT_FreeProcess( ++ IN gckEVENT Event, ++ IN gctUINT32 ProcessID ++ ); ++ ++gceSTATUS ++gckEVENT_Stop( ++ IN gckEVENT Event, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Handle, ++ IN gctPOINTER Logical, ++ IN gctSIGNAL Signal, ++ IN OUT gctUINT32 * waitSize ++ ); ++ ++typedef struct _gcsLOCK_INFO * gcsLOCK_INFO_PTR; ++typedef struct _gcsLOCK_INFO ++{ ++ gctUINT32 GPUAddresses[gcdMAX_GPU_COUNT]; ++ gctPOINTER pageTables[gcdMAX_GPU_COUNT]; ++ gctUINT32 lockeds[gcdMAX_GPU_COUNT]; ++ gckKERNEL lockKernels[gcdMAX_GPU_COUNT]; ++ gckMMU lockMmus[gcdMAX_GPU_COUNT]; ++} ++gcsLOCK_INFO; ++ ++typedef struct _gcsGPU_MAP * gcsGPU_MAP_PTR; ++typedef struct _gcsGPU_MAP ++{ ++ gctINT pid; ++ gcsLOCK_INFO lockInfo; ++ gcsGPU_MAP_PTR prev; ++ gcsGPU_MAP_PTR next; ++} ++gcsGPU_MAP; ++ ++/* gcuVIDMEM_NODE structure. */ ++typedef union _gcuVIDMEM_NODE ++{ ++ /* Allocated from gckVIDMEM. */ ++ struct _gcsVIDMEM_NODE_VIDMEM ++ { ++ /* Owner of this node. */ ++ gckVIDMEM memory; ++ ++ /* Dual-linked list of nodes. */ ++ gcuVIDMEM_NODE_PTR next; ++ gcuVIDMEM_NODE_PTR prev; ++ ++ /* Dual linked list of free nodes. */ ++ gcuVIDMEM_NODE_PTR nextFree; ++ gcuVIDMEM_NODE_PTR prevFree; ++ ++ /* Information for this node. */ ++ gctSIZE_T offset; ++ gctSIZE_T bytes; ++ gctUINT32 alignment; ++ ++ /* Locked counter. */ ++ gctINT32 locked; ++ ++ /* Memory pool. */ ++ gcePOOL pool; ++ gctUINT32 physical; ++ ++ /* Process ID owning this memory. */ ++ gctUINT32 processID; ++ ++#if gcdENABLE_VG ++ gctPOINTER kernelVirtual; ++#endif ++ } ++ VidMem; ++ ++ /* Allocated from gckOS. */ ++ struct _gcsVIDMEM_NODE_VIRTUAL ++ { ++ /* Pointer to gckKERNEL object. */ ++ gckKERNEL kernel; ++ ++ /* Information for this node. */ ++ /* Contiguously allocated? */ ++ gctBOOL contiguous; ++ /* mdl record pointer... a kmalloc address. Process agnostic. */ ++ gctPHYS_ADDR physical; ++ gctSIZE_T bytes; ++ /* do_mmap_pgoff address... mapped per-process. */ ++ gctPOINTER logical; ++ ++#if gcdENABLE_VG ++ /* Physical address of this node, only meaningful when it is contiguous. */ ++ gctUINT32 physicalAddress; ++ ++ /* Kernel logical of this node. */ ++ gctPOINTER kernelVirtual; ++#endif ++ ++ /* Customer private handle */ ++ gctUINT32 gid; ++ ++ /* Page table information. */ ++ /* Used only when node is not contiguous */ ++ gctSIZE_T pageCount; ++ ++ /* Used only when node is not contiguous */ ++ gctPOINTER pageTables[gcdMAX_GPU_COUNT]; ++ /* Pointer to gckKERNEL object who lock this. */ ++ gckKERNEL lockKernels[gcdMAX_GPU_COUNT]; ++ /* Actual physical address */ ++ gctUINT32 addresses[gcdMAX_GPU_COUNT]; ++ ++ /* Locked counter. */ ++ gctINT32 lockeds[gcdMAX_GPU_COUNT]; ++ ++ /* Process ID owning this memory. */ ++ gctUINT32 processID; ++ ++ /* Surface type. */ ++ gceSURF_TYPE type; ++ } ++ Virtual; ++} ++gcuVIDMEM_NODE; ++ ++/* gckVIDMEM object. */ ++struct _gckVIDMEM ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gckOS object. */ ++ gckOS os; ++ ++ /* Information for this video memory heap. */ ++ gctUINT32 baseAddress; ++ gctSIZE_T bytes; ++ gctSIZE_T freeBytes; ++ ++ /* Mapping for each type of surface. */ ++ gctINT mapping[gcvSURF_NUM_TYPES]; ++ ++ /* Sentinel nodes for up to 8 banks. */ ++ gcuVIDMEM_NODE sentinel[8]; ++ ++ /* Allocation threshold. */ ++ gctSIZE_T threshold; ++ ++ /* The heap mutex. */ ++ gctPOINTER mutex; ++}; ++ ++typedef struct _gcsVIDMEM_NODE ++{ ++ /* Pointer to gcuVIDMEM_NODE. */ ++ gcuVIDMEM_NODE_PTR node; ++ ++ /* Mutex to protect node. */ ++ gctPOINTER mutex; ++ ++ /* Reference count. */ ++ gctPOINTER reference; ++ ++ /* Name for client to import. */ ++ gctUINT32 name; ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ /* Head of mapping list. */ ++ gcsGPU_MAP_PTR mapHead; ++ ++ /* Tail of mapping list. */ ++ gcsGPU_MAP_PTR mapTail; ++ ++ gctPOINTER mapMutex; ++#endif ++ ++ /* Surface Type. */ ++ gceSURF_TYPE type; ++ ++ /* Pool from which node is allocated. */ ++ gcePOOL pool; ++} ++gcsVIDMEM_NODE; ++ ++typedef struct _gcsVIDMEM_HANDLE * gckVIDMEM_HANDLE; ++typedef struct _gcsVIDMEM_HANDLE ++{ ++ /* Pointer to gckVIDMEM_NODE. */ ++ gckVIDMEM_NODE node; ++ ++ /* Handle for current process. */ ++ gctUINT32 handle; ++ ++ /* Reference count for this handle. */ ++ gctPOINTER reference; ++} ++gcsVIDMEM_HANDLE; ++ ++typedef struct _gcsSHBUF * gcsSHBUF_PTR; ++typedef struct _gcsSHBUF ++{ ++ /* ID. */ ++ gctUINT32 id; ++ ++ /* Reference count. */ ++ gctPOINTER reference; ++ ++ /* Data size. */ ++ gctUINT32 size; ++ ++ /* Data. */ ++ gctPOINTER data; ++} ++gcsSHBUF; ++ ++gceSTATUS ++gckVIDMEM_HANDLE_Reference( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle ++ ); ++ ++gceSTATUS ++gckVIDMEM_HANDLE_Dereference( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle ++ ); ++ ++gceSTATUS ++gckVIDMEM_NODE_Allocate( ++ IN gckKERNEL Kernel, ++ IN gcuVIDMEM_NODE_PTR VideoNode, ++ IN gceSURF_TYPE Type, ++ IN gcePOOL Pool, ++ IN gctUINT32 * Handle ++ ); ++ ++gceSTATUS ++gckVIDMEM_Node_Lock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ OUT gctUINT32 *Address ++ ); ++ ++gceSTATUS ++gckVIDMEM_NODE_Unlock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ IN gctUINT32 ProcessID ++ ); ++ ++gceSTATUS ++gckVIDMEM_NODE_Dereference( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node ++ ); ++ ++gceSTATUS ++gckVIDMEM_NODE_Name( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Handle, ++ IN gctUINT32 * Name ++ ); ++ ++gceSTATUS ++gckVIDMEM_NODE_Import( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Name, ++ IN gctUINT32 * Handle ++ ); ++ ++gceSTATUS ++gckVIDMEM_HANDLE_LookupAndReference( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Handle, ++ OUT gckVIDMEM_NODE * Node ++ ); ++ ++gceSTATUS ++gckVIDMEM_HANDLE_Lookup( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle, ++ OUT gckVIDMEM_NODE * Node ++ ); ++ ++gceSTATUS ++gckVIDMEM_NODE_GetFd( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Handle, ++ OUT gctINT * Fd ++ ); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gceSTATUS ++gckEVENT_DestroyMmu( ++ IN gckEVENT Event, ++ IN gckMMU Mmu, ++ IN gceKERNEL_WHERE FromWhere ++ ); ++#endif ++ ++/* gckMMU object. */ ++struct _gckMMU ++{ ++ /* The object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gckOS object. */ ++ gckOS os; ++ ++ /* Pointer to gckHARDWARE object. */ ++ gckHARDWARE hardware; ++ ++ /* The page table mutex. */ ++ gctPOINTER pageTableMutex; ++ ++ /* Page table information. */ ++ gctSIZE_T pageTableSize; ++ gctPHYS_ADDR pageTablePhysical; ++ gctUINT32_PTR pageTableLogical; ++ gctUINT32 pageTableEntries; ++ ++ /* Master TLB information. */ ++ gctSIZE_T mtlbSize; ++ gctPHYS_ADDR mtlbPhysical; ++ gctUINT32_PTR mtlbLogical; ++ gctUINT32 mtlbEntries; ++ ++ /* Free entries. */ ++ gctUINT32 heapList; ++ gctBOOL freeNodes; ++ ++ gctPOINTER staticSTLB; ++ gctBOOL enabled; ++ ++ gctUINT32 dynamicMappingStart; ++ ++ gctUINT32_PTR mapLogical; ++#if gcdPROCESS_ADDRESS_SPACE ++ gctPOINTER pageTableDirty[gcdMAX_GPU_COUNT]; ++ gctPOINTER stlbs; ++#endif ++}; ++ ++gceSTATUS ++gckOS_CreateKernelVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical, ++ OUT gctSIZE_T * PageCount ++ ); ++ ++gceSTATUS ++gckOS_DestroyKernelVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ); ++ ++gceSTATUS ++gckOS_CreateUserVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical, ++ OUT gctSIZE_T * PageCount ++ ); ++ ++gceSTATUS ++gckOS_DestroyUserVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ); ++ ++gceSTATUS ++gckOS_GetFd( ++ IN gctSTRING Name, ++ IN gcsFDPRIVATE_PTR Private, ++ OUT gctINT *Fd ++ ); ++ ++gceSTATUS ++gckKERNEL_AllocateVirtualCommandBuffer( ++ IN gckKERNEL Kernel, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ); ++ ++gceSTATUS ++gckKERNEL_DestroyVirtualCommandBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical ++ ); ++ ++gceSTATUS ++gckKERNEL_GetGPUAddress( ++ IN gckKERNEL Kernel, ++ IN gctPOINTER Logical, ++ IN gctBOOL InUserSpace, ++ OUT gctUINT32 * Address ++ ); ++ ++gceSTATUS ++gckKERNEL_QueryGPUAddress( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 GpuAddress, ++ OUT gckVIRTUAL_COMMAND_BUFFER_PTR * Buffer ++ ); ++ ++gceSTATUS ++gckKERNEL_AttachProcess( ++ IN gckKERNEL Kernel, ++ IN gctBOOL Attach ++ ); ++ ++gceSTATUS ++gckKERNEL_AttachProcessEx( ++ IN gckKERNEL Kernel, ++ IN gctBOOL Attach, ++ IN gctUINT32 PID ++ ); ++ ++gceSTATUS ++gckHARDWARE_QueryIdle( ++ IN gckHARDWARE Hardware, ++ OUT gctBOOL_PTR IsIdle ++ ); ++ ++gceSTATUS ++gckKERNEL_CreateShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Size, ++ OUT gctSHBUF * ShBuf ++ ); ++ ++gceSTATUS ++gckKERNEL_DestroyShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf ++ ); ++ ++gceSTATUS ++gckKERNEL_MapShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf ++ ); ++ ++gceSTATUS ++gckKERNEL_WriteShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf, ++ IN gctPOINTER UserData, ++ IN gctUINT32 ByteCount ++ ); ++ ++gceSTATUS ++gckKERNEL_ReadShBuffer( ++ IN gckKERNEL Kernel, ++ IN gctSHBUF ShBuf, ++ IN gctPOINTER UserData, ++ IN gctUINT32 ByteCount, ++ OUT gctUINT32 * BytesRead ++ ); ++ ++ ++/******************************************************************************\ ++******************************* gckCONTEXT Object ******************************* ++\******************************************************************************/ ++ ++gceSTATUS ++gckCONTEXT_Construct( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 ProcessID, ++ OUT gckCONTEXT * Context ++ ); ++ ++gceSTATUS ++gckCONTEXT_Destroy( ++ IN gckCONTEXT Context ++ ); ++ ++gceSTATUS ++gckCONTEXT_Update( ++ IN gckCONTEXT Context, ++ IN gctUINT32 ProcessID, ++ IN gcsSTATE_DELTA_PTR StateDelta ++ ); ++ ++gceSTATUS ++gckCONTEXT_MapBuffer( ++ IN gckCONTEXT Context, ++ OUT gctUINT32 *Physicals, ++ OUT gctUINT64 *Logicals, ++ OUT gctUINT32 *Bytes ++ ); ++ ++#if gcdLINK_QUEUE_SIZE ++void ++gckLINKQUEUE_Enqueue( ++ IN gckLINKQUEUE LinkQueue, ++ IN gctUINT32 start, ++ IN gctUINT32 end ++ ); ++ ++void ++gckLINKQUEUE_GetData( ++ IN gckLINKQUEUE LinkQueue, ++ IN gctUINT32 Index, ++ OUT gckLINKDATA * Data ++ ); ++#endif ++ ++gceSTATUS ++gckENTRYQUEUE_Enqueue( ++ IN gckKERNEL Kernel, ++ IN gckENTRYQUEUE Queue, ++ IN gctUINT32 physical, ++ IN gctUINT32 bytes ++ ); ++ ++gceSTATUS ++gckENTRYQUEUE_Dequeue( ++ IN gckENTRYQUEUE Queue, ++ OUT gckENTRYDATA * Data ++ ); ++ ++/******************************************************************************\ ++****************************** gckRECORDER Object ****************************** ++\******************************************************************************/ ++gceSTATUS ++gckRECORDER_Construct( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ OUT gckRECORDER * Recorder ++ ); ++ ++gceSTATUS ++gckRECORDER_Destory( ++ IN gckOS Os, ++ IN gckRECORDER Recorder ++ ); ++ ++void ++gckRECORDER_AdvanceIndex( ++ gckRECORDER Recorder, ++ gctUINT64 CommitStamp ++ ); ++ ++void ++gckRECORDER_Record( ++ gckRECORDER Recorder, ++ gctUINT8_PTR CommandBuffer, ++ gctUINT32 CommandBytes, ++ gctUINT8_PTR ContextBuffer, ++ gctUINT32 ContextBytes ++ ); ++ ++void ++gckRECORDER_Dump( ++ gckRECORDER Recorder ++ ); ++ ++gceSTATUS ++gckRECORDER_UpdateMirror( ++ gckRECORDER Recorder, ++ gctUINT32 State, ++ gctUINT32 Data ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_kernel_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,858 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#if gcdENABLE_VG ++ ++/******************************************************************************\ ++*********************** Support Functions and Definitions ********************** ++\******************************************************************************/ ++ ++/* Interruot statistics will be accumulated if not zero. */ ++#define gcmENABLE_INTERRUPT_STATISTICS 0 ++ ++#define _GC_OBJ_ZONE gcvZONE_INTERRUPT ++ ++/* Object structure. */ ++struct _gckVGINTERRUPT ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* gckVGKERNEL pointer. */ ++ gckVGKERNEL kernel; ++ ++ /* gckOS pointer. */ ++ gckOS os; ++ ++ /* Interrupt handlers. */ ++ gctINTERRUPT_HANDLER handlers[32]; ++ ++ /* Main interrupt handler thread. */ ++ gctTHREAD handler; ++ gctBOOL terminate; ++ ++ /* Interrupt FIFO. */ ++ gctSEMAPHORE fifoValid; ++ gctUINT32 fifo[256]; ++ gctUINT fifoItems; ++ gctUINT8 head; ++ gctUINT8 tail; ++ ++ /* Interrupt statistics. */ ++#if gcmENABLE_INTERRUPT_STATISTICS ++ gctUINT maxFifoItems; ++ gctUINT fifoOverflow; ++ gctUINT maxSimultaneous; ++ gctUINT multipleCount; ++#endif ++}; ++ ++ ++/******************************************************************************* ++** ++** _ProcessInterrupt ++** ++** The interrupt processor. ++** ++** INPUT: ++** ++** ThreadParameter ++** Pointer to the gckVGINTERRUPT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++#if gcmENABLE_INTERRUPT_STATISTICS ++static void ++_ProcessInterrupt( ++ gckVGINTERRUPT Interrupt, ++ gctUINT_PTR TriggeredCount ++ ) ++#else ++static void ++_ProcessInterrupt( ++ gckVGINTERRUPT Interrupt ++ ) ++#endif ++{ ++ gceSTATUS status; ++ gctUINT32 triggered; ++ gctUINT i; ++ ++ /* Advance to the next entry. */ ++ Interrupt->tail += 1; ++ Interrupt->fifoItems -= 1; ++ ++ /* Get the interrupt value. */ ++ triggered = Interrupt->fifo[Interrupt->tail]; ++ gcmkASSERT(triggered != 0); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s: triggered=0x%08X\n", ++ __FUNCTION__, ++ triggered ++ ); ++ ++ /* Walk through all possible interrupts. */ ++ for (i = 0; i < gcmSIZEOF(Interrupt->handlers); i += 1) ++ { ++ /* Test if interrupt happened. */ ++ if ((triggered & 1) == 1) ++ { ++#if gcmENABLE_INTERRUPT_STATISTICS ++ if (TriggeredCount != gcvNULL) ++ { ++ (* TriggeredCount) += 1; ++ } ++#endif ++ ++ /* Make sure we have valid handler. */ ++ if (Interrupt->handlers[i] == gcvNULL) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s: Interrupt %d isn't registered.\n", ++ __FUNCTION__, i ++ ); ++ } ++ else ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s: interrupt=%d\n", ++ __FUNCTION__, ++ i ++ ); ++ ++ /* Call the handler. */ ++ status = Interrupt->handlers[i] (Interrupt->kernel); ++ ++ if (gcmkIS_ERROR(status)) ++ { ++ /* Failed to signal the semaphore. */ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s: Error %d incrementing the semaphore #%d.\n", ++ __FUNCTION__, status, i ++ ); ++ } ++ } ++ } ++ ++ /* Next interrupt. */ ++ triggered >>= 1; ++ ++ /* No more interrupts to handle? */ ++ if (triggered == 0) ++ { ++ break; ++ } ++ } ++} ++ ++ ++/******************************************************************************* ++** ++** _MainInterruptHandler ++** ++** The main interrupt thread serves the interrupt FIFO and calls registered ++** handlers for the interrupts that occured. The handlers are called in the ++** sequence interrupts occured with the exception when multiple interrupts ++** occured at the same time. In that case the handler calls are "sorted" by ++** the interrupt number therefore giving the interrupts with lower numbers ++** higher priority. ++** ++** INPUT: ++** ++** ThreadParameter ++** Pointer to the gckVGINTERRUPT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++static gctTHREADFUNCRESULT gctTHREADFUNCTYPE ++_MainInterruptHandler( ++ gctTHREADFUNCPARAMETER ThreadParameter ++ ) ++{ ++ gceSTATUS status; ++ gckVGINTERRUPT interrupt; ++ ++#if gcmENABLE_INTERRUPT_STATISTICS ++ gctUINT count; ++#endif ++ ++ /* Cast the object. */ ++ interrupt = (gckVGINTERRUPT) ThreadParameter; ++ ++ /* Enter the loop. */ ++ while (gcvTRUE) ++ { ++ /* Wait for an interrupt. */ ++ status = gckOS_DecrementSemaphore(interrupt->os, interrupt->fifoValid); ++ ++ /* Error? */ ++ if (gcmkIS_ERROR(status)) ++ { ++ break; ++ } ++ ++ /* System termination request? */ ++ if (status == gcvSTATUS_TERMINATE) ++ { ++ break; ++ } ++ ++ /* Driver is shutting down? */ ++ if (interrupt->terminate) ++ { ++ break; ++ } ++ ++#if gcmENABLE_INTERRUPT_STATISTICS ++ /* Reset triggered count. */ ++ count = 0; ++ ++ /* Process the interrupt. */ ++ _ProcessInterrupt(interrupt, &count); ++ ++ /* Update conters. */ ++ if (count > interrupt->maxSimultaneous) ++ { ++ interrupt->maxSimultaneous = count; ++ } ++ ++ if (count > 1) ++ { ++ interrupt->multipleCount += 1; ++ } ++#else ++ /* Process the interrupt. */ ++ _ProcessInterrupt(interrupt); ++#endif ++ } ++ ++ return 0; ++} ++ ++ ++/******************************************************************************* ++** ++** _StartInterruptHandler / _StopInterruptHandler ++** ++** Main interrupt handler routine control. ++** ++** INPUT: ++** ++** ThreadParameter ++** Pointer to the gckVGINTERRUPT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++static gceSTATUS ++_StartInterruptHandler( ++ gckVGINTERRUPT Interrupt ++ ) ++{ ++ gceSTATUS status, last; ++ ++ do ++ { ++ /* Objects must not be already created. */ ++ gcmkASSERT(Interrupt->fifoValid == gcvNULL); ++ gcmkASSERT(Interrupt->handler == gcvNULL); ++ ++ /* Reset the termination request. */ ++ Interrupt->terminate = gcvFALSE; ++ ++#if !gcdENABLE_INFINITE_SPEED_HW ++ /* Construct the fifo semaphore. */ ++ gcmkERR_BREAK(gckOS_CreateSemaphoreVG( ++ Interrupt->os, &Interrupt->fifoValid ++ )); ++ ++ /* Start the interrupt handler thread. */ ++ gcmkERR_BREAK(gckOS_StartThread( ++ Interrupt->os, ++ _MainInterruptHandler, ++ Interrupt, ++ &Interrupt->handler ++ )); ++#endif ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Roll back. */ ++ if (Interrupt->fifoValid != gcvNULL) ++ { ++ gcmkCHECK_STATUS(gckOS_DestroySemaphore( ++ Interrupt->os, Interrupt->fifoValid ++ )); ++ ++ Interrupt->fifoValid = gcvNULL; ++ } ++ ++ /* Return the status. */ ++ return status; ++} ++ ++static gceSTATUS ++_StopInterruptHandler( ++ gckVGINTERRUPT Interrupt ++ ) ++{ ++ gceSTATUS status; ++ ++ do ++ { ++ /* Does the thread exist? */ ++ if (Interrupt->handler == gcvNULL) ++ { ++ /* The semaphore must be NULL as well. */ ++ gcmkASSERT(Interrupt->fifoValid == gcvNULL); ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ break; ++ } ++ ++ /* The semaphore must exist as well. */ ++ gcmkASSERT(Interrupt->fifoValid != gcvNULL); ++ ++ /* Set the termination request. */ ++ Interrupt->terminate = gcvTRUE; ++ ++ /* Unlock the thread. */ ++ gcmkERR_BREAK(gckOS_IncrementSemaphore( ++ Interrupt->os, Interrupt->fifoValid ++ )); ++ ++ /* Wait until the thread quits. */ ++ gcmkERR_BREAK(gckOS_StopThread( ++ Interrupt->os, ++ Interrupt->handler ++ )); ++ ++ /* Destroy the semaphore. */ ++ gcmkERR_BREAK(gckOS_DestroySemaphore( ++ Interrupt->os, Interrupt->fifoValid ++ )); ++ ++ /* Reset handles. */ ++ Interrupt->handler = gcvNULL; ++ Interrupt->fifoValid = gcvNULL; ++ } ++ while (gcvFALSE); ++ ++ /* Return the status. */ ++ return status; ++} ++ ++ ++/******************************************************************************\ ++***************************** Interrupt Object API ***************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckVGINTERRUPT_Construct ++** ++** Construct an interrupt object. ++** ++** INPUT: ++** ++** Kernel ++** Pointer to the gckVGKERNEL object. ++** ++** OUTPUT: ++** ++** Interrupt ++** Pointer to the new gckVGINTERRUPT object. ++*/ ++ ++gceSTATUS ++gckVGINTERRUPT_Construct( ++ IN gckVGKERNEL Kernel, ++ OUT gckVGINTERRUPT * Interrupt ++ ) ++{ ++ gceSTATUS status; ++ gckVGINTERRUPT interrupt = gcvNULL; ++ ++ gcmkHEADER_ARG("Kernel=0x%x Interrupt=0x%x", Kernel, Interrupt); ++ ++ /* Verify argeuments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Interrupt != gcvNULL); ++ ++ do ++ { ++ /* Allocate the gckVGINTERRUPT structure. */ ++ gcmkERR_BREAK(gckOS_Allocate( ++ Kernel->os, ++ gcmSIZEOF(struct _gckVGINTERRUPT), ++ (gctPOINTER *) &interrupt ++ )); ++ ++ /* Reset the object data. */ ++ gcmkVERIFY_OK(gckOS_ZeroMemory( ++ interrupt, gcmSIZEOF(struct _gckVGINTERRUPT) ++ )); ++ ++ /* Initialize the object. */ ++ interrupt->object.type = gcvOBJ_INTERRUPT; ++ ++ /* Initialize the object pointers. */ ++ interrupt->kernel = Kernel; ++ interrupt->os = Kernel->os; ++ ++ /* Initialize the current FIFO position. */ ++ interrupt->head = (gctUINT8)~0; ++ interrupt->tail = (gctUINT8)~0; ++ ++ /* Start the thread. */ ++ gcmkERR_BREAK(_StartInterruptHandler(interrupt)); ++ ++ /* Return interrupt object. */ ++ *Interrupt = interrupt; ++ ++ gcmkFOOTER_ARG("*Interrup=0x%x", *Interrupt); ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Roll back. */ ++ if (interrupt != gcvNULL) ++ { ++ /* Free the gckVGINTERRUPT structure. */ ++ gcmkVERIFY_OK(gckOS_Free(interrupt->os, interrupt)); ++ } ++ ++ gcmkFOOTER(); ++ ++ /* Return the status. */ ++ return status; ++} ++ ++ ++/******************************************************************************* ++** ++** gckVGINTERRUPT_Destroy ++** ++** Destroy an interrupt object. ++** ++** INPUT: ++** ++** Interrupt ++** Pointer to the gckVGINTERRUPT object to destroy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++gceSTATUS ++gckVGINTERRUPT_Destroy( ++ IN gckVGINTERRUPT Interrupt ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Interrupt=0x%x", Interrupt); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); ++ ++ do ++ { ++ /* Stop the interrupt thread. */ ++ gcmkERR_BREAK(_StopInterruptHandler(Interrupt)); ++ ++ /* Mark the object as unknown. */ ++ Interrupt->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckVGINTERRUPT structure. */ ++ gcmkERR_BREAK(gckOS_Free(Interrupt->os, Interrupt)); ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ ++ /* Return the status. */ ++ return status; ++} ++ ++ ++/******************************************************************************* ++** ++** gckVGINTERRUPT_DumpState ++** ++** Print the current state of the interrupt manager. ++** ++** INPUT: ++** ++** Interrupt ++** Pointer to a gckVGINTERRUPT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++#if gcvDEBUG ++gceSTATUS ++gckVGINTERRUPT_DumpState( ++ IN gckVGINTERRUPT Interrupt ++ ) ++{ ++ gcmkHEADER_ARG("Interrupt=0x%x", Interrupt); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); ++ ++ /* Print the header. */ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ "%s: INTERRUPT OBJECT STATUS\n", ++ __FUNCTION__ ++ ); ++ ++ /* Print statistics. */ ++#if gcmENABLE_INTERRUPT_STATISTICS ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " Maximum number of FIFO items accumulated at a single time: %d\n", ++ Interrupt->maxFifoItems ++ ); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " Interrupt FIFO overflow happened times: %d\n", ++ Interrupt->fifoOverflow ++ ); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " Maximum number of interrupts simultaneously generated: %d\n", ++ Interrupt->maxSimultaneous ++ ); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " Number of times when there were multiple interrupts generated: %d\n", ++ Interrupt->multipleCount ++ ); ++#endif ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " The current number of entries in the FIFO: %d\n", ++ Interrupt->fifoItems ++ ); ++ ++ /* Print the FIFO contents. */ ++ if (Interrupt->fifoItems != 0) ++ { ++ gctUINT8 index; ++ gctUINT8 last; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " FIFO current contents:\n" ++ ); ++ ++ /* Get the current pointers. */ ++ index = Interrupt->tail; ++ last = Interrupt->head; ++ ++ while (index != last) ++ { ++ /* Advance to the next entry. */ ++ index += 1; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_VERBOSE, gcvZONE_COMMAND, ++ " %d: 0x%08X\n", ++ index, Interrupt->fifo[index] ++ ); ++ } ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++#endif ++ ++ ++/******************************************************************************* ++** ++** gckVGINTERRUPT_Enable ++** ++** Enable the specified interrupt. ++** ++** INPUT: ++** ++** Interrupt ++** Pointer to a gckVGINTERRUPT object. ++** ++** Id ++** Pointer to the variable that holds the interrupt number to be ++** registered in range 0..31. ++** If the value is less then 0, gckVGINTERRUPT_Enable will attempt ++** to find an unused interrupt. If such interrupt is found, the number ++** will be assigned to the variable if the functuion call succeedes. ++** ++** Handler ++** Pointer to the handler to register for the interrupt. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++gceSTATUS ++gckVGINTERRUPT_Enable( ++ IN gckVGINTERRUPT Interrupt, ++ IN OUT gctINT32_PTR Id, ++ IN gctINTERRUPT_HANDLER Handler ++ ) ++{ ++ gceSTATUS status; ++ gctINT32 i; ++ ++ gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x Handler=0x%x", Interrupt, Id, Handler); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); ++ gcmkVERIFY_ARGUMENT(Id != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Handler != gcvNULL); ++ ++ do ++ { ++ /* See if we need to allocate an ID. */ ++ if (*Id < 0) ++ { ++ /* Find the first unused interrupt handler. */ ++ for (i = 0; i < gcmCOUNTOF(Interrupt->handlers); ++i) ++ { ++ if (Interrupt->handlers[i] == gcvNULL) ++ { ++ break; ++ } ++ } ++ ++ /* No unused innterrupts? */ ++ if (i == gcmCOUNTOF(Interrupt->handlers)) ++ { ++ status = gcvSTATUS_OUT_OF_RESOURCES; ++ break; ++ } ++ ++ /* Update the interrupt ID. */ ++ *Id = i; ++ } ++ ++ /* Make sure the ID is in range. */ ++ else if (*Id >= gcmCOUNTOF(Interrupt->handlers)) ++ { ++ status = gcvSTATUS_INVALID_ARGUMENT; ++ break; ++ } ++ ++ /* Set interrupt handler. */ ++ Interrupt->handlers[*Id] = Handler; ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++ ++/******************************************************************************* ++** ++** gckVGINTERRUPT_Disable ++** ++** Disable the specified interrupt. ++** ++** INPUT: ++** ++** Interrupt ++** Pointer to a gckVGINTERRUPT object. ++** ++** Id ++** Interrupt number to be disabled in range 0..31. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++gceSTATUS ++gckVGINTERRUPT_Disable( ++ IN gckVGINTERRUPT Interrupt, ++ IN gctINT32 Id ++ ) ++{ ++ gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x", Interrupt, Id); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); ++ gcmkVERIFY_ARGUMENT((Id >= 0) && (Id < gcmCOUNTOF(Interrupt->handlers))); ++ ++ /* Reset interrupt handler. */ ++ Interrupt->handlers[Id] = gcvNULL; ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++ ++/******************************************************************************* ++** ++** gckVGINTERRUPT_Enque ++** ++** Read the interrupt status register and put the value in the interrupt FIFO. ++** ++** INPUT: ++** ++** Interrupt ++** Pointer to a gckVGINTERRUPT object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++ ++gceSTATUS ++gckVGINTERRUPT_Enque( ++ IN gckVGINTERRUPT Interrupt ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 triggered; ++ ++ gcmkHEADER_ARG("Interrupt=0x%x", Interrupt); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); ++ ++ do ++ { ++ /* Read interrupt status register. */ ++ gcmkERR_BREAK(gckVGHARDWARE_ReadInterrupt( ++ Interrupt->kernel->hardware, &triggered ++ )); ++ ++ /* Mask out TS overflow interrupt */ ++ triggered &= 0xfffffffe; ++ ++ /* No interrupts to process? */ ++ if (triggered == 0) ++ { ++ status = gcvSTATUS_NOT_OUR_INTERRUPT; ++ break; ++ } ++ ++ /* FIFO overflow? */ ++ if (Interrupt->fifoItems == gcmCOUNTOF(Interrupt->fifo)) ++ { ++#if gcmENABLE_INTERRUPT_STATISTICS ++ Interrupt->fifoOverflow += 1; ++#endif ++ ++ /* OR the interrupt with the last value in the FIFO. */ ++ Interrupt->fifo[Interrupt->head] |= triggered; ++ ++ /* Success (kind of). */ ++ status = gcvSTATUS_OK; ++ } ++ else ++ { ++ /* Advance to the next entry. */ ++ Interrupt->head += 1; ++ Interrupt->fifoItems += 1; ++ ++#if gcmENABLE_INTERRUPT_STATISTICS ++ if (Interrupt->fifoItems > Interrupt->maxFifoItems) ++ { ++ Interrupt->maxFifoItems = Interrupt->fifoItems; ++ } ++#endif ++ ++ /* Set the new value. */ ++ Interrupt->fifo[Interrupt->head] = triggered; ++ ++ /* Increment the FIFO semaphore. */ ++ gcmkERR_BREAK(gckOS_IncrementSemaphore( ++ Interrupt->os, Interrupt->fifoValid ++ )); ++ ++ /* Windows kills our threads prematurely when the application ++ exists. Verify here that the thread is still alive. */ ++ status = gckOS_VerifyThread(Interrupt->os, Interrupt->handler); ++ ++ /* Has the thread been prematurely terminated? */ ++ if (status != gcvSTATUS_OK) ++ { ++ /* Process all accumulated interrupts. */ ++ while (Interrupt->head != Interrupt->tail) ++ { ++#if gcmENABLE_INTERRUPT_STATISTICS ++ /* Process the interrupt. */ ++ _ProcessInterrupt(Interrupt, gcvNULL); ++#else ++ /* Process the interrupt. */ ++ _ProcessInterrupt(Interrupt); ++#endif ++ } ++ ++ /* Set success. */ ++ status = gcvSTATUS_OK; ++ } ++ } ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++#endif /* gcdENABLE_VG */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_iommu.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_iommu.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_iommu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_iommu.c 2016-06-19 22:11:55.141150767 +0200 +@@ -0,0 +1,202 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++#include "gc_hal_kernel_device.h" ++ ++#include ++#include ++ ++#define _GC_OBJ_ZONE gcvZONE_OS ++ ++typedef struct _gcsIOMMU ++{ ++ struct iommu_domain * domain; ++ struct device * device; ++} ++gcsIOMMU; ++ ++static int ++_IOMMU_Fault_Handler( ++ struct iommu_domain * Domain, ++ struct device * Dev, ++ unsigned long DomainAddress, ++ int flags, ++ void * args ++ ) ++{ ++ return 0; ++} ++ ++static int ++_FlatMapping( ++ IN gckIOMMU Iommu ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 physical; ++ ++ for (physical = 0; physical < 0x80000000; physical += PAGE_SIZE) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "Map %x => %x bytes = %d", ++ physical, physical, PAGE_SIZE ++ ); ++ ++ gcmkONERROR(gckIOMMU_Map(Iommu, physical, physical, PAGE_SIZE)); ++ } ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++void ++gckIOMMU_Destory( ++ IN gckOS Os, ++ IN gckIOMMU Iommu ++ ) ++{ ++ gcmkHEADER(); ++ ++ if (Iommu->domain && Iommu->device) ++ { ++ iommu_attach_device(Iommu->domain, Iommu->device); ++ } ++ ++ if (Iommu->domain) ++ { ++ iommu_domain_free(Iommu->domain); ++ } ++ ++ if (Iommu) ++ { ++ gcmkOS_SAFE_FREE(Os, Iommu); ++ } ++ ++ gcmkFOOTER_NO(); ++} ++ ++gceSTATUS ++gckIOMMU_Construct( ++ IN gckOS Os, ++ OUT gckIOMMU * Iommu ++ ) ++{ ++ gceSTATUS status; ++ gckIOMMU iommu = gcvNULL; ++ struct device *dev; ++ int ret; ++ ++ gcmkHEADER(); ++ ++ dev = &Os->device->platform->device->dev; ++ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsIOMMU), (gctPOINTER *)&iommu)); ++ ++ gckOS_ZeroMemory(iommu, gcmSIZEOF(gcsIOMMU)); ++ ++ iommu->domain = iommu_domain_alloc(&platform_bus_type); ++ ++ if (!iommu->domain) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "iommu_domain_alloc() fail"); ++ ++ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); ++ } ++ ++ iommu_set_fault_handler(iommu->domain, _IOMMU_Fault_Handler, dev); ++ ++ ret = iommu_attach_device(iommu->domain, dev); ++ ++ if (ret) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, "iommu_attach_device() fail %d", ret); ++ ++ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); ++ } ++ ++ iommu->device = dev; ++ ++ _FlatMapping(iommu); ++ ++ *Iommu = iommu; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ gckIOMMU_Destory(Os, iommu); ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckIOMMU_Map( ++ IN gckIOMMU Iommu, ++ IN gctUINT32 DomainAddress, ++ IN gctUINT32 Physical, ++ IN gctUINT32 Bytes ++ ) ++{ ++ gceSTATUS status; ++ int ret; ++ ++ gcmkHEADER_ARG("DomainAddress=%#X, Physical=%#X, Bytes=%d", ++ DomainAddress, Physical, Bytes); ++ ++ ret = iommu_map(Iommu->domain, DomainAddress, Physical, Bytes, 0); ++ ++ if (ret) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ gcmkFOOTER(); ++ return status; ++ ++} ++ ++gceSTATUS ++gckIOMMU_Unmap( ++ IN gckIOMMU Iommu, ++ IN gctUINT32 DomainAddress, ++ IN gctUINT32 Bytes ++ ) ++{ ++ gcmkHEADER(); ++ ++ iommu_unmap(Iommu->domain, DomainAddress, Bytes); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_linux.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_linux.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_linux.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_linux.c 2016-06-19 22:11:55.145150505 +0200 +@@ -0,0 +1,487 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_KERNEL ++ ++/******************************************************************************\ ++******************************* gckKERNEL API Code ****************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckKERNEL_QueryVideoMemory ++** ++** Query the amount of video memory. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** OUTPUT: ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to an gcsHAL_INTERFACE structure that will be filled in with ++** the memory information. ++*/ ++gceSTATUS ++gckKERNEL_QueryVideoMemory( ++ IN gckKERNEL Kernel, ++ OUT gcsHAL_INTERFACE * Interface ++ ) ++{ ++ gckGALDEVICE device; ++ ++ gcmkHEADER_ARG("Kernel=%p", Kernel); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Interface != NULL); ++ ++ /* Extract the pointer to the gckGALDEVICE class. */ ++ device = (gckGALDEVICE) Kernel->context; ++ ++ /* Get internal memory size and physical address. */ ++ Interface->u.QueryVideoMemory.internalSize = device->internalSize; ++ Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysicalName; ++ ++ /* Get external memory size and physical address. */ ++ Interface->u.QueryVideoMemory.externalSize = device->externalSize; ++ Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysicalName; ++ ++ /* Get contiguous memory size and physical address. */ ++ Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize; ++ Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysicalName; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_GetVideoMemoryPool ++** ++** Get the gckVIDMEM object belonging to the specified pool. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcePOOL Pool ++** Pool to query gckVIDMEM object for. ++** ++** OUTPUT: ++** ++** gckVIDMEM * VideoMemory ++** Pointer to a variable that will hold the pointer to the gckVIDMEM ++** object belonging to the requested pool. ++*/ ++gceSTATUS ++gckKERNEL_GetVideoMemoryPool( ++ IN gckKERNEL Kernel, ++ IN gcePOOL Pool, ++ OUT gckVIDMEM * VideoMemory ++ ) ++{ ++ gckGALDEVICE device; ++ gckVIDMEM videoMemory; ++ ++ gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(VideoMemory != NULL); ++ ++ /* Extract the pointer to the gckGALDEVICE class. */ ++ device = (gckGALDEVICE) Kernel->context; ++ ++ /* Dispatch on pool. */ ++ switch (Pool) ++ { ++ case gcvPOOL_LOCAL_INTERNAL: ++ /* Internal memory. */ ++ videoMemory = device->internalVidMem; ++ break; ++ ++ case gcvPOOL_LOCAL_EXTERNAL: ++ /* External memory. */ ++ videoMemory = device->externalVidMem; ++ break; ++ ++ case gcvPOOL_SYSTEM: ++ /* System memory. */ ++ videoMemory = device->contiguousVidMem; ++ break; ++ ++ default: ++ /* Unknown pool. */ ++ videoMemory = NULL; ++ } ++ ++ /* Return pointer to the gckVIDMEM object. */ ++ *VideoMemory = videoMemory; ++ ++ /* Return status. */ ++ gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory); ++ return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_MapMemory ++** ++** Map video memory into the current process space. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctPHYS_ADDR Physical ++** Physical address of video memory to map. ++** ++** gctSIZE_T Bytes ++** Number of bytes to map. ++** ++** OUTPUT: ++** ++** gctPOINTER * Logical ++** Pointer to a variable that will hold the base address of the mapped ++** memory region. ++*/ ++gceSTATUS ++gckKERNEL_MapMemory( ++ IN gckKERNEL Kernel, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ gckKERNEL kernel = Kernel; ++ gctPHYS_ADDR physical = gcmNAME_TO_PTR(Physical); ++ ++ return gckOS_MapMemory(Kernel->os, physical, Bytes, Logical); ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_UnmapMemory ++** ++** Unmap video memory from the current process space. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctPHYS_ADDR Physical ++** Physical address of video memory to map. ++** ++** gctSIZE_T Bytes ++** Number of bytes to map. ++** ++** gctPOINTER Logical ++** Base address of the mapped memory region. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_UnmapMemory( ++ IN gckKERNEL Kernel, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ) ++{ ++ gckKERNEL kernel = Kernel; ++ gctPHYS_ADDR physical = gcmNAME_TO_PTR(Physical); ++ ++ return gckOS_UnmapMemory(Kernel->os, physical, Bytes, Logical); ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_MapVideoMemory ++** ++** Get the logical address for a hardware specific memory address for the ++** current process. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctBOOL InUserSpace ++** gcvTRUE to map the memory into the user space. ++** ++** gctUINT32 Address ++** Hardware specific memory address. ++** ++** OUTPUT: ++** ++** gctPOINTER * Logical ++** Pointer to a variable that will hold the logical address of the ++** specified memory address. ++*/ ++gceSTATUS ++gckKERNEL_MapVideoMemoryEx( ++ IN gckKERNEL Kernel, ++ IN gceCORE Core, ++ IN gctBOOL InUserSpace, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ gckGALDEVICE device = gcvNULL; ++ PLINUX_MDL mdl = gcvNULL; ++ PLINUX_MDL_MAP mdlMap = gcvNULL; ++ gcePOOL pool = gcvPOOL_UNKNOWN; ++ gctUINT32 offset = 0; ++ gctUINT32 base = 0; ++ gceSTATUS status; ++ gctPOINTER logical = gcvNULL; ++ gctUINT32 baseAddress; ++ ++ gcmkHEADER_ARG("Kernel=%p InUserSpace=%d Address=%08x", ++ Kernel, InUserSpace, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Logical != NULL); ++ ++ /* Extract the pointer to the gckGALDEVICE class. */ ++ device = (gckGALDEVICE) Kernel->context; ++ ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ /* Split the memory address into a pool type and offset. */ ++ gcmkONERROR( ++ gckVGHARDWARE_SplitMemory(Kernel->vg->hardware, Address, &pool, &offset)); ++ } ++ else ++#endif ++ { ++ /* Split the memory address into a pool type and offset. */ ++ gcmkONERROR( ++ gckHARDWARE_SplitMemory(Kernel->hardware, Address, &pool, &offset)); ++ } ++ ++ /* Dispatch on pool. */ ++ switch (pool) ++ { ++ case gcvPOOL_LOCAL_INTERNAL: ++ /* Internal memory. */ ++ logical = device->internalLogical; ++ break; ++ ++ case gcvPOOL_LOCAL_EXTERNAL: ++ /* External memory. */ ++ logical = device->externalLogical; ++ break; ++ ++ case gcvPOOL_SYSTEM: ++ /* System memory. */ ++ if (device->contiguousMapped) ++ { ++ logical = device->contiguousBase; ++ } ++ else ++ { ++ gctINT processID; ++ gckOS_GetProcessID(&processID); ++ ++ mdl = (PLINUX_MDL) device->contiguousPhysical; ++ ++ mdlMap = FindMdlMap(mdl, processID); ++ gcmkASSERT(mdlMap); ++ ++ logical = (gctPOINTER) mdlMap->vmaAddr; ++ } ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ gcmkVERIFY_OK( ++ gckVGHARDWARE_SplitMemory(Kernel->vg->hardware, ++ device->contiguousVidMem->baseAddress, ++ &pool, ++ &base)); ++ } ++ else ++#endif ++ { ++ gctUINT32 systemBaseAddress = 0; ++ ++ if (Kernel->hardware->mmuVersion == 0) ++ { ++ gcmkONERROR(gckOS_GetBaseAddress(Kernel->os, &systemBaseAddress)); ++ } ++ ++ gcmkVERIFY_OK( ++ gckOS_CPUPhysicalToGPUPhysical( ++ Kernel->os, ++ device->contiguousVidMem->baseAddress - systemBaseAddress, ++ &baseAddress ++ )); ++ ++ gcmkVERIFY_OK( ++ gckHARDWARE_SplitMemory(Kernel->hardware, ++ baseAddress, ++ &pool, ++ &base)); ++ } ++ offset -= base; ++ break; ++ ++ default: ++ /* Invalid memory pool. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Build logical address of specified address. */ ++ *Logical = (gctPOINTER) ((gctUINT8_PTR) logical + offset); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Logical=%p", *Logical); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Retunn the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_MapVideoMemory ++** ++** Get the logical address for a hardware specific memory address for the ++** current process. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctBOOL InUserSpace ++** gcvTRUE to map the memory into the user space. ++** ++** gctUINT32 Address ++** Hardware specific memory address. ++** ++** OUTPUT: ++** ++** gctPOINTER * Logical ++** Pointer to a variable that will hold the logical address of the ++** specified memory address. ++*/ ++gceSTATUS ++gckKERNEL_MapVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gctBOOL InUserSpace, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ return gckKERNEL_MapVideoMemoryEx(Kernel, gcvCORE_MAJOR, InUserSpace, Address, Logical); ++} ++/******************************************************************************* ++** ++** gckKERNEL_Notify ++** ++** This function iscalled by clients to notify the gckKERNRL object of an event. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gceNOTIFY Notification ++** Notification event. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_Notify( ++ IN gckKERNEL Kernel, ++ IN gceNOTIFY Notification, ++ IN gctBOOL Data ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d", ++ Kernel, Notification, Data); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Dispatch on notifcation. */ ++ switch (Notification) ++ { ++ case gcvNOTIFY_INTERRUPT: ++ /* Process the interrupt. */ ++ status = gckHARDWARE_Interrupt(Kernel->hardware, ++ Data); ++ break; ++ ++ default: ++ status = gcvSTATUS_OK; ++ break; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckKERNEL_QuerySettings( ++ IN gckKERNEL Kernel, ++ OUT gcsKERNEL_SETTINGS * Settings ++ ) ++{ ++ gckGALDEVICE device; ++ ++ gcmkHEADER_ARG("Kernel=%p", Kernel); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Settings != gcvNULL); ++ ++ /* Extract the pointer to the gckGALDEVICE class. */ ++ device = (gckGALDEVICE) Kernel->context; ++ ++ /* Fill in signal. */ ++ Settings->signal = device->signal; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal); ++ return gcvSTATUS_OK; ++} +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_linux.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_linux.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_linux.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_linux.h 2016-06-19 22:11:55.145150505 +0200 +@@ -0,0 +1,364 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_linux_h_ ++#define __gc_hal_kernel_linux_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef MODVERSIONS ++# include ++#endif ++#include ++#include ++ ++#include ++ ++#define NTSTRSAFE_NO_CCH_FUNCTIONS ++#include "gc_hal.h" ++#include "gc_hal_driver.h" ++#include "gc_hal_kernel.h" ++#include "gc_hal_kernel_platform.h" ++#include "gc_hal_kernel_device.h" ++#include "gc_hal_kernel_os.h" ++#include "gc_hal_kernel_debugfs.h" ++ ++ ++#define FIND_TASK_BY_PID(x) pid_task(find_vpid(x), PIDTYPE_PID) ++ ++#define _WIDE(string) L##string ++#define WIDE(string) _WIDE(string) ++ ++#define countof(a) (sizeof(a) / sizeof(a[0])) ++ ++#ifndef DEVICE_NAME ++# define DEVICE_NAME "galcore" ++#endif ++ ++#define GetPageCount(size, offset) ((((size) + ((offset) & ~PAGE_CACHE_MASK)) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) ++ ++#define gcdVM_FLAGS (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP) ++ ++/* Protection bit when mapping memroy to user sapce */ ++#define gcmkPAGED_MEMROY_PROT(x) pgprot_writecombine(x) ++ ++#if gcdNONPAGED_MEMORY_BUFFERABLE ++#define gcmkIOREMAP ioremap_wc ++#define gcmkNONPAGED_MEMROY_PROT(x) pgprot_writecombine(x) ++#elif !gcdNONPAGED_MEMORY_CACHEABLE ++#define gcmkIOREMAP ioremap_nocache ++#define gcmkNONPAGED_MEMROY_PROT(x) pgprot_noncached(x) ++#endif ++ ++#define gcdSUPPRESS_OOM_MESSAGE 1 ++ ++#if gcdSUPPRESS_OOM_MESSAGE ++#define gcdNOWARN __GFP_NOWARN ++#else ++#define gcdNOWARN 0 ++#endif ++ ++/******************************************************************************\ ++********************************** Structures ********************************** ++\******************************************************************************/ ++typedef struct _gcsIOMMU * gckIOMMU; ++ ++typedef struct _gcsUSER_MAPPING * gcsUSER_MAPPING_PTR; ++typedef struct _gcsUSER_MAPPING ++{ ++ /* Pointer to next mapping structure. */ ++ gcsUSER_MAPPING_PTR next; ++ ++ /* Physical address of this mapping. */ ++ gctUINT32 physical; ++ ++ /* Logical address of this mapping. */ ++ gctPOINTER logical; ++ ++ /* Number of bytes of this mapping. */ ++ gctSIZE_T bytes; ++ ++ /* Starting address of this mapping. */ ++ gctINT8_PTR start; ++ ++ /* Ending address of this mapping. */ ++ gctINT8_PTR end; ++} ++gcsUSER_MAPPING; ++ ++typedef struct _gcsINTEGER_DB * gcsINTEGER_DB_PTR; ++typedef struct _gcsINTEGER_DB ++{ ++ struct idr idr; ++ spinlock_t lock; ++ gctINT curr; ++} ++gcsINTEGER_DB; ++ ++struct _gckOS ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to device */ ++ gckGALDEVICE device; ++ ++ /* Memory management */ ++ gctPOINTER memoryLock; ++ gctPOINTER memoryMapLock; ++ ++ struct _LINUX_MDL *mdlHead; ++ struct _LINUX_MDL *mdlTail; ++ ++ /* Kernel process ID. */ ++ gctUINT32 kernelProcessID; ++ ++ /* Signal management. */ ++ ++ /* Lock. */ ++ gctPOINTER signalMutex; ++ ++ /* signal id database. */ ++ gcsINTEGER_DB signalDB; ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ /* Lock. */ ++ gctPOINTER syncPointMutex; ++ ++ /* sync point id database. */ ++ gcsINTEGER_DB syncPointDB; ++#endif ++ ++ gcsUSER_MAPPING_PTR userMap; ++ gctPOINTER debugLock; ++ ++ /* workqueue for os timer. */ ++ struct workqueue_struct * workqueue; ++ ++ /* Allocate extra page to avoid cache overflow */ ++ struct page* paddingPage; ++ ++ /* Detect unfreed allocation. */ ++ atomic_t allocateCount; ++ ++ struct list_head allocatorList; ++ ++ gcsDEBUGFS_DIR allocatorDebugfsDir; ++ ++ /* Lock for register access check. */ ++ struct mutex registerAccessLocks[gcdMAX_GPU_COUNT]; ++ ++ /* External power states. */ ++ gctBOOL powerStates[gcdMAX_GPU_COUNT]; ++ ++ /* External clock states. */ ++ gctBOOL clockStates[gcdMAX_GPU_COUNT]; ++ ++ /* IOMMU. */ ++ gckIOMMU iommu; ++}; ++ ++typedef struct _gcsSIGNAL * gcsSIGNAL_PTR; ++typedef struct _gcsSIGNAL ++{ ++ /* Kernel sync primitive. */ ++ struct completion obj; ++ ++ /* Manual reset flag. */ ++ gctBOOL manualReset; ++ ++ /* The reference counter. */ ++ atomic_t ref; ++ ++ /* The owner of the signal. */ ++ gctHANDLE process; ++ ++ gckHARDWARE hardware; ++ ++ /* ID. */ ++ gctUINT32 id; ++} ++gcsSIGNAL; ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++typedef struct _gcsSYNC_POINT * gcsSYNC_POINT_PTR; ++typedef struct _gcsSYNC_POINT ++{ ++ /* The reference counter. */ ++ atomic_t ref; ++ ++ /* State. */ ++ atomic_t state; ++ ++ /* timeline. */ ++ struct sync_timeline * timeline; ++ ++ /* ID. */ ++ gctUINT32 id; ++} ++gcsSYNC_POINT; ++#endif ++ ++typedef struct _gcsPageInfo * gcsPageInfo_PTR; ++typedef struct _gcsPageInfo ++{ ++ struct page **pages; ++ gctUINT32_PTR pageTable; ++ gctUINT32 extraPage; ++ gctUINT32 address; ++#if gcdPROCESS_ADDRESS_SPACE ++ gckMMU mmu; ++#endif ++} ++gcsPageInfo; ++ ++typedef struct _gcsOSTIMER * gcsOSTIMER_PTR; ++typedef struct _gcsOSTIMER ++{ ++ struct delayed_work work; ++ gctTIMERFUNCTION function; ++ gctPOINTER data; ++} gcsOSTIMER; ++ ++gceSTATUS ++gckOS_ImportAllocators( ++ gckOS Os ++ ); ++ ++gceSTATUS ++gckOS_FreeAllocators( ++ gckOS Os ++ ); ++ ++gceSTATUS ++_HandleOuterCache( ++ IN gckOS Os, ++ IN gctUINT32 Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes, ++ IN gceCACHEOPERATION Type ++ ); ++ ++gceSTATUS ++_ConvertLogical2Physical( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ IN gctUINT32 ProcessID, ++ IN PLINUX_MDL Mdl, ++ OUT gctUINT32_PTR Physical ++ ); ++ ++gctSTRING ++_CreateKernelVirtualMapping( ++ IN PLINUX_MDL Mdl ++ ); ++ ++void ++_DestoryKernelVirtualMapping( ++ IN gctSTRING Addr ++ ); ++ ++void ++_UnmapUserLogical( ++ IN gctPOINTER Logical, ++ IN gctUINT32 Size ++ ); ++ ++static inline gctINT ++_GetProcessID( ++ void ++ ) ++{ ++ return task_tgid_vnr(current); ++} ++ ++static inline struct page * ++_NonContiguousToPage( ++ IN struct page ** Pages, ++ IN gctUINT32 Index ++ ) ++{ ++ gcmkASSERT(Pages != gcvNULL); ++ return Pages[Index]; ++} ++ ++static inline unsigned long ++_NonContiguousToPfn( ++ IN struct page ** Pages, ++ IN gctUINT32 Index ++ ) ++{ ++ gcmkASSERT(Pages != gcvNULL); ++ return page_to_pfn(_NonContiguousToPage(Pages, Index)); ++} ++ ++static inline unsigned long ++_NonContiguousToPhys( ++ IN struct page ** Pages, ++ IN gctUINT32 Index ++ ) ++{ ++ gcmkASSERT(Pages != gcvNULL); ++ return page_to_phys(_NonContiguousToPage(Pages, Index)); ++} ++ ++#ifdef CONFIG_IOMMU_SUPPORT ++void ++gckIOMMU_Destory( ++ IN gckOS Os, ++ IN gckIOMMU Iommu ++ ); ++ ++gceSTATUS ++gckIOMMU_Construct( ++ IN gckOS Os, ++ OUT gckIOMMU * Iommu ++ ); ++ ++gceSTATUS ++gckIOMMU_Map( ++ IN gckIOMMU Iommu, ++ IN gctUINT32 DomainAddress, ++ IN gctUINT32 Physical, ++ IN gctUINT32 Bytes ++ ); ++ ++gceSTATUS ++gckIOMMU_Unmap( ++ IN gckIOMMU Iommu, ++ IN gctUINT32 DomainAddress, ++ IN gctUINT32 Bytes ++ ); ++#endif ++ ++#endif /* __gc_hal_kernel_linux_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_math.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_math.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_math.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_math.c 2016-06-19 22:11:55.145150505 +0200 +@@ -0,0 +1,32 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++ ++gctINT ++gckMATH_ModuloInt( ++ IN gctINT X, ++ IN gctINT Y ++ ) ++{ ++ if(Y ==0) {return 0;} ++ else {return X % Y;} ++} +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_mmu.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_mmu.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_mmu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_mmu.c 2016-06-19 22:11:55.145150505 +0200 +@@ -0,0 +1,2260 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_MMU ++ ++typedef enum _gceMMU_TYPE ++{ ++ gcvMMU_USED = (0 << 4), ++ gcvMMU_SINGLE = (1 << 4), ++ gcvMMU_FREE = (2 << 4), ++} ++gceMMU_TYPE; ++ ++#define gcmENTRY_TYPE(x) (x & 0xF0) ++ ++#define gcdMMU_TABLE_DUMP 0 ++ ++#define gcdUSE_MMU_EXCEPTION 1 ++ ++/* ++ gcdMMU_CLEAR_VALUE ++ ++ The clear value for the entry of the old MMU. ++*/ ++#ifndef gcdMMU_CLEAR_VALUE ++# define gcdMMU_CLEAR_VALUE 0x00000ABC ++#endif ++ ++#define gcdVERTEX_START (128 << 10) ++ ++typedef struct _gcsMMU_STLB *gcsMMU_STLB_PTR; ++ ++typedef struct _gcsMMU_STLB ++{ ++ gctPHYS_ADDR physical; ++ gctUINT32_PTR logical; ++ gctSIZE_T size; ++ gctUINT32 physBase; ++ gctSIZE_T pageCount; ++ gctUINT32 mtlbIndex; ++ gctUINT32 mtlbEntryNum; ++ gcsMMU_STLB_PTR next; ++} gcsMMU_STLB; ++ ++#if gcdSHARED_PAGETABLE ++typedef struct _gcsSharedPageTable * gcsSharedPageTable_PTR; ++typedef struct _gcsSharedPageTable ++{ ++ /* Shared gckMMU object. */ ++ gckMMU mmu; ++ ++ /* Hardwares which use this shared pagetable. */ ++ gckHARDWARE hardwares[gcdMAX_GPU_COUNT]; ++ ++ /* Number of cores use this shared pagetable. */ ++ gctUINT32 reference; ++} ++gcsSharedPageTable; ++ ++static gcsSharedPageTable_PTR sharedPageTable = gcvNULL; ++#endif ++ ++#if gcdMIRROR_PAGETABLE ++typedef struct _gcsMirrorPageTable * gcsMirrorPageTable_PTR; ++typedef struct _gcsMirrorPageTable ++{ ++ /* gckMMU objects. */ ++ gckMMU mmus[gcdMAX_GPU_COUNT]; ++ ++ /* Hardwares which use this shared pagetable. */ ++ gckHARDWARE hardwares[gcdMAX_GPU_COUNT]; ++ ++ /* Number of cores use this shared pagetable. */ ++ gctUINT32 reference; ++} ++gcsMirrorPageTable; ++ ++static gcsMirrorPageTable_PTR mirrorPageTable = gcvNULL; ++static gctPOINTER mirrorPageTableMutex = gcvNULL; ++#endif ++ ++typedef struct _gcsDynamicSpaceNode * gcsDynamicSpaceNode_PTR; ++typedef struct _gcsDynamicSpaceNode ++{ ++ gctUINT32 start; ++ gctINT32 entries; ++} ++gcsDynamicSpaceNode; ++ ++static void ++_WritePageEntry( ++ IN gctUINT32_PTR PageEntry, ++ IN gctUINT32 EntryValue ++ ) ++{ ++ static gctUINT16 data = 0xff00; ++ ++ if (*(gctUINT8 *)&data == 0xff) ++ { ++ *PageEntry = gcmSWAB32(EntryValue); ++ } ++ else ++ { ++ *PageEntry = EntryValue; ++ } ++} ++ ++static gctUINT32 ++_ReadPageEntry( ++ IN gctUINT32_PTR PageEntry ++ ) ++{ ++ static gctUINT16 data = 0xff00; ++ gctUINT32 entryValue; ++ ++ if (*(gctUINT8 *)&data == 0xff) ++ { ++ entryValue = *PageEntry; ++ return gcmSWAB32(entryValue); ++ } ++ else ++ { ++ return *PageEntry; ++ } ++} ++ ++static gceSTATUS ++_FillPageTable( ++ IN gctUINT32_PTR PageTable, ++ IN gctUINT32 PageCount, ++ IN gctUINT32 EntryValue ++) ++{ ++ gctUINT i; ++ ++ for (i = 0; i < PageCount; i++) ++ { ++ _WritePageEntry(PageTable + i, EntryValue); ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++static gceSTATUS ++_Link( ++ IN gckMMU Mmu, ++ IN gctUINT32 Index, ++ IN gctUINT32 Next ++ ) ++{ ++ if (Index >= Mmu->pageTableEntries) ++ { ++ /* Just move heap pointer. */ ++ Mmu->heapList = Next; ++ } ++ else ++ { ++ /* Address page table. */ ++ gctUINT32_PTR map = Mmu->mapLogical; ++ ++ /* Dispatch on node type. */ ++ switch (gcmENTRY_TYPE(_ReadPageEntry(&map[Index]))) ++ { ++ case gcvMMU_SINGLE: ++ /* Set single index. */ ++ _WritePageEntry(&map[Index], (Next << 8) | gcvMMU_SINGLE); ++ break; ++ ++ case gcvMMU_FREE: ++ /* Set index. */ ++ _WritePageEntry(&map[Index + 1], Next); ++ break; ++ ++ default: ++ gcmkFATAL("MMU table correcupted at index %u!", Index); ++ return gcvSTATUS_HEAP_CORRUPTED; ++ } ++ } ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++static gceSTATUS ++_AddFree( ++ IN gckMMU Mmu, ++ IN gctUINT32 Index, ++ IN gctUINT32 Node, ++ IN gctUINT32 Count ++ ) ++{ ++ gctUINT32_PTR map = Mmu->mapLogical; ++ ++ if (Count == 1) ++ { ++ /* Initialize a single page node. */ ++ _WritePageEntry(map + Node, (~((1U<<8)-1)) | gcvMMU_SINGLE); ++ } ++ else ++ { ++ /* Initialize the node. */ ++ _WritePageEntry(map + Node + 0, (Count << 8) | gcvMMU_FREE); ++ _WritePageEntry(map + Node + 1, ~0U); ++ } ++ ++ /* Append the node. */ ++ return _Link(Mmu, Index, Node); ++} ++ ++static gceSTATUS ++_Collect( ++ IN gckMMU Mmu ++ ) ++{ ++ gctUINT32_PTR map = Mmu->mapLogical; ++ gceSTATUS status; ++ gctUINT32 i, previous, start = 0, count = 0; ++ ++ previous = Mmu->heapList = ~0U; ++ Mmu->freeNodes = gcvFALSE; ++ ++ /* Walk the entire page table. */ ++ for (i = 0; i < Mmu->pageTableEntries; ++i) ++ { ++ /* Dispatch based on type of page. */ ++ switch (gcmENTRY_TYPE(_ReadPageEntry(&map[i]))) ++ { ++ case gcvMMU_USED: ++ /* Used page, so close any open node. */ ++ if (count > 0) ++ { ++ /* Add the node. */ ++ gcmkONERROR(_AddFree(Mmu, previous, start, count)); ++ ++ /* Reset the node. */ ++ previous = start; ++ count = 0; ++ } ++ break; ++ ++ case gcvMMU_SINGLE: ++ /* Single free node. */ ++ if (count++ == 0) ++ { ++ /* Start a new node. */ ++ start = i; ++ } ++ break; ++ ++ case gcvMMU_FREE: ++ /* A free node. */ ++ if (count == 0) ++ { ++ /* Start a new node. */ ++ start = i; ++ } ++ ++ /* Advance the count. */ ++ count += _ReadPageEntry(&map[i]) >> 8; ++ ++ /* Advance the index into the page table. */ ++ i += (_ReadPageEntry(&map[i]) >> 8) - 1; ++ break; ++ ++ default: ++ gcmkFATAL("MMU page table correcupted at index %u!", i); ++ return gcvSTATUS_HEAP_CORRUPTED; ++ } ++ } ++ ++ /* See if we have an open node left. */ ++ if (count > 0) ++ { ++ /* Add the node to the list. */ ++ gcmkONERROR(_AddFree(Mmu, previous, start, count)); ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU, ++ "Performed a garbage collection of the MMU heap."); ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the staus. */ ++ return status; ++} ++ ++static gctUINT32 ++_SetPage(gctUINT32 PageAddress) ++{ ++ return PageAddress ++ /* writable */ ++ | (1 << 2) ++ /* Ignore exception */ ++ | (0 << 1) ++ /* Present */ ++ | (1 << 0); ++} ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gctUINT32 ++_AddressToIndex( ++ IN gckMMU Mmu, ++ IN gctUINT32 Address ++ ) ++{ ++ gctUINT32 mtlbOffset = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT; ++ gctUINT32 stlbOffset = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT; ++ ++ return (mtlbOffset - Mmu->dynamicMappingStart) * gcdMMU_STLB_4K_ENTRY_NUM + stlbOffset; ++} ++ ++gctUINT32 ++_MtlbOffset( ++ gctUINT32 Address ++ ) ++{ ++ return (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT; ++} ++ ++gctUINT32 ++_StlbOffset( ++ gctUINT32 Address ++ ) ++{ ++ return (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT; ++} ++ ++static gceSTATUS ++_AllocateStlb( ++ IN gckOS Os, ++ OUT gcsMMU_STLB_PTR *Stlb ++ ) ++{ ++ gceSTATUS status; ++ gcsMMU_STLB_PTR stlb; ++ gctPOINTER pointer; ++ ++ /* Allocate slave TLB record. */ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsMMU_STLB), &pointer)); ++ stlb = pointer; ++ ++ stlb->size = gcdMMU_STLB_4K_SIZE; ++ ++ /* Allocate slave TLB entries. */ ++ gcmkONERROR(gckOS_AllocateContiguous( ++ Os, ++ gcvFALSE, ++ &stlb->size, ++ &stlb->physical, ++ (gctPOINTER)&stlb->logical ++ )); ++ ++ gcmkONERROR(gckOS_GetPhysicalAddress(Os, stlb->logical, &stlb->physBase)); ++ ++#if gcdUSE_MMU_EXCEPTION ++ _FillPageTable(stlb->logical, stlb->size / 4, gcdMMU_STLB_EXCEPTION); ++#else ++ gckOS_ZeroMemory(stlb->logical, stlb->size); ++#endif ++ ++ *Stlb = stlb; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++gceSTATUS ++_SetupProcessAddressSpace( ++ IN gckMMU Mmu ++ ) ++{ ++ gceSTATUS status; ++ gctINT numEntries = 0; ++ gctUINT32_PTR map; ++ ++ numEntries = gcdPROCESS_ADDRESS_SPACE_SIZE ++ /* Address space mapped by one MTLB entry. */ ++ / (1 << gcdMMU_MTLB_SHIFT); ++ ++ Mmu->dynamicMappingStart = 0; ++ ++ Mmu->pageTableSize = numEntries * 4096; ++ ++ Mmu->pageTableEntries = Mmu->pageTableSize / gcmSIZEOF(gctUINT32); ++ ++ gcmkONERROR(gckOS_Allocate(Mmu->os, ++ Mmu->pageTableSize, ++ (void **)&Mmu->mapLogical)); ++ ++ /* Initilization. */ ++ map = Mmu->mapLogical; ++ _WritePageEntry(map, (Mmu->pageTableEntries << 8) | gcvMMU_FREE); ++ _WritePageEntry(map + 1, ~0U); ++ Mmu->heapList = 0; ++ Mmu->freeNodes = gcvFALSE; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++#else ++static gceSTATUS ++_FillFlatMapping( ++ IN gckMMU Mmu, ++ IN gctUINT32 PhysBase, ++ OUT gctSIZE_T Size ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL mutex = gcvFALSE; ++ gcsMMU_STLB_PTR head = gcvNULL, pre = gcvNULL; ++ gctUINT32 start = PhysBase & (~gcdMMU_PAGE_64K_MASK); ++ gctUINT32 end = (PhysBase + Size - 1) & (~gcdMMU_PAGE_64K_MASK); ++ gctUINT32 mStart = start >> gcdMMU_MTLB_SHIFT; ++ gctUINT32 mEnd = end >> gcdMMU_MTLB_SHIFT; ++ gctUINT32 sStart = (start & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT; ++ gctUINT32 sEnd = (end & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT; ++ gctBOOL ace = gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_ACE); ++ ++ /* Grab the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); ++ mutex = gcvTRUE; ++ ++ while (mStart <= mEnd) ++ { ++ gcmkASSERT(mStart < gcdMMU_MTLB_ENTRY_NUM); ++ if (*(Mmu->mtlbLogical + mStart) == 0) ++ { ++ gcsMMU_STLB_PTR stlb; ++ gctPOINTER pointer = gcvNULL; ++ gctUINT32 last = (mStart == mEnd) ? sEnd : (gcdMMU_STLB_64K_ENTRY_NUM - 1); ++ gctUINT32 mtlbEntry; ++ ++ gcmkONERROR(gckOS_Allocate(Mmu->os, sizeof(struct _gcsMMU_STLB), &pointer)); ++ stlb = pointer; ++ ++ stlb->mtlbEntryNum = 0; ++ stlb->next = gcvNULL; ++ stlb->physical = gcvNULL; ++ stlb->logical = gcvNULL; ++ stlb->size = gcdMMU_STLB_64K_SIZE; ++ stlb->pageCount = 0; ++ ++ if (pre == gcvNULL) ++ { ++ pre = head = stlb; ++ } ++ else ++ { ++ gcmkASSERT(pre->next == gcvNULL); ++ pre->next = stlb; ++ pre = stlb; ++ } ++ ++ gcmkONERROR( ++ gckOS_AllocateContiguous(Mmu->os, ++ gcvFALSE, ++ &stlb->size, ++ &stlb->physical, ++ (gctPOINTER)&stlb->logical)); ++ ++ gcmkONERROR(gckOS_ZeroMemory(stlb->logical, stlb->size)); ++ ++ gcmkONERROR(gckOS_GetPhysicalAddress( ++ Mmu->os, ++ stlb->logical, ++ &stlb->physBase)); ++ ++ if (stlb->physBase & (gcdMMU_STLB_64K_SIZE - 1)) ++ { ++ gcmkONERROR(gcvSTATUS_NOT_ALIGNED); ++ } ++ ++ mtlbEntry = stlb->physBase ++ /* 64KB page size */ ++ | (1 << 2) ++ /* Ignore exception */ ++ | (0 << 1) ++ /* Present */ ++ | (1 << 0); ++ ++ if (ace) ++ { ++ mtlbEntry = mtlbEntry ++ /* Secure */ ++ | (1 << 4); ++ } ++ ++ _WritePageEntry(Mmu->mtlbLogical + mStart, mtlbEntry); ++ ++#if gcdMMU_TABLE_DUMP ++ gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n", ++ __FUNCTION__, __LINE__, ++ mStart, ++ _ReadPageEntry(Mmu->mtlbLogical + mStart)); ++#endif ++ ++ stlb->mtlbIndex = mStart; ++ stlb->mtlbEntryNum = 1; ++#if gcdMMU_TABLE_DUMP ++ gckOS_Print("%s(%d): STLB: logical:%08x -> physical:%08x\n", ++ __FUNCTION__, __LINE__, ++ stlb->logical, ++ stlb->physBase); ++#endif ++ ++ while (sStart <= last) ++ { ++ gcmkASSERT(!(start & gcdMMU_PAGE_64K_MASK)); ++ _WritePageEntry(stlb->logical + sStart, _SetPage(start)); ++#if gcdMMU_TABLE_DUMP ++ gckOS_Print("%s(%d): insert STLB[%d]: %08x\n", ++ __FUNCTION__, __LINE__, ++ sStart, ++ _ReadPageEntry(stlb->logical + sStart)); ++#endif ++ /* next page. */ ++ start += gcdMMU_PAGE_64K_SIZE; ++ sStart++; ++ stlb->pageCount++; ++ } ++ ++ sStart = 0; ++ ++mStart; ++ } ++ else ++ { ++ gcmkONERROR(gcvSTATUS_INVALID_REQUEST); ++ } ++ } ++ ++ /* Insert the stlb into staticSTLB. */ ++ if (Mmu->staticSTLB == gcvNULL) ++ { ++ Mmu->staticSTLB = head; ++ } ++ else ++ { ++ gcmkASSERT(pre == gcvNULL); ++ gcmkASSERT(pre->next == gcvNULL); ++ pre->next = Mmu->staticSTLB; ++ Mmu->staticSTLB = head; ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ /* Roll back. */ ++ while (head != gcvNULL) ++ { ++ pre = head; ++ head = head->next; ++ ++ if (pre->physical != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_FreeContiguous(Mmu->os, ++ pre->physical, ++ pre->logical, ++ pre->size)); ++ } ++ ++ if (pre->mtlbEntryNum != 0) ++ { ++ gcmkASSERT(pre->mtlbEntryNum == 1); ++ _WritePageEntry(Mmu->mtlbLogical + pre->mtlbIndex, 0); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre)); ++ } ++ ++ if (mutex) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ } ++ ++ return status; ++} ++ ++static gceSTATUS ++_FindDynamicSpace( ++ IN gckMMU Mmu, ++ OUT gcsDynamicSpaceNode_PTR *Array, ++ OUT gctINT * Size ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gctPOINTER pointer = gcvNULL; ++ gcsDynamicSpaceNode_PTR array = gcvNULL; ++ gctINT size = 0; ++ gctINT i = 0, nodeStart = -1, nodeEntries = 0; ++ ++ /* Allocate memory for the array. */ ++ gcmkONERROR(gckOS_Allocate(Mmu->os, ++ gcmSIZEOF(*array) * (gcdMMU_MTLB_ENTRY_NUM / 2), ++ &pointer)); ++ ++ array = (gcsDynamicSpaceNode_PTR)pointer; ++ ++ /* Loop all the entries. */ ++ while (i < gcdMMU_MTLB_ENTRY_NUM) ++ { ++ if (!Mmu->mtlbLogical[i]) ++ { ++ if (nodeStart < 0) ++ { ++ /* This is the first entry of the dynamic space. */ ++ nodeStart = i; ++ nodeEntries = 1; ++ } ++ else ++ { ++ /* Other entries of the dynamic space. */ ++ nodeEntries++; ++ } ++ } ++ else if (nodeStart >= 0) ++ { ++ /* Save the previous node. */ ++ array[size].start = nodeStart; ++ array[size].entries = nodeEntries; ++ size++; ++ ++ /* Reset the start. */ ++ nodeStart = -1; ++ nodeEntries = 0; ++ } ++ ++ i++; ++ } ++ ++ /* Save the previous node. */ ++ if (nodeStart >= 0) ++ { ++ array[size].start = nodeStart; ++ array[size].entries = nodeEntries; ++ size++; ++ } ++ ++#if gcdMMU_TABLE_DUMP ++ for (i = 0; i < size; i++) ++ { ++ gckOS_Print("%s(%d): [%d]: start=%d, entries=%d.\n", ++ __FUNCTION__, __LINE__, ++ i, ++ array[i].start, ++ array[i].entries); ++ } ++#endif ++ ++ *Array = array; ++ *Size = size; ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (pointer != gcvNULL) ++ { ++ gckOS_Free(Mmu->os, pointer); ++ } ++ ++ return status; ++} ++ ++static gceSTATUS ++_SetupDynamicSpace( ++ IN gckMMU Mmu ++ ) ++{ ++ gceSTATUS status; ++ gcsDynamicSpaceNode_PTR nodeArray = gcvNULL; ++ gctINT i, nodeArraySize = 0; ++ gctUINT32 physical; ++ gctINT numEntries = 0; ++ gctUINT32_PTR map; ++ gctBOOL acquired = gcvFALSE; ++ gctUINT32 mtlbEntry; ++ gctBOOL ace = gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_ACE); ++ ++ /* Find all the dynamic address space. */ ++ gcmkONERROR(_FindDynamicSpace(Mmu, &nodeArray, &nodeArraySize)); ++ ++ /* TODO: We only use the largest one for now. */ ++ for (i = 0; i < nodeArraySize; i++) ++ { ++ if (nodeArray[i].entries > numEntries) ++ { ++ Mmu->dynamicMappingStart = nodeArray[i].start; ++ numEntries = nodeArray[i].entries; ++ } ++ } ++ ++ gckOS_Free(Mmu->os, (gctPOINTER)nodeArray); ++ ++ Mmu->pageTableSize = numEntries * 4096; ++ ++ gcmkSAFECASTSIZET(Mmu->pageTableEntries, Mmu->pageTableSize / gcmSIZEOF(gctUINT32)); ++ ++ gcmkONERROR(gckOS_Allocate(Mmu->os, ++ Mmu->pageTableSize, ++ (void **)&Mmu->mapLogical)); ++ ++ /* Construct Slave TLB. */ ++ gcmkONERROR(gckOS_AllocateContiguous(Mmu->os, ++ gcvFALSE, ++ &Mmu->pageTableSize, ++ &Mmu->pageTablePhysical, ++ (gctPOINTER)&Mmu->pageTableLogical)); ++ ++#if gcdUSE_MMU_EXCEPTION ++ gcmkONERROR(_FillPageTable(Mmu->pageTableLogical, ++ Mmu->pageTableEntries, ++ /* Enable exception */ ++ 1 << 1)); ++#else ++ /* Invalidate all entries. */ ++ gcmkONERROR(gckOS_ZeroMemory(Mmu->pageTableLogical, ++ Mmu->pageTableSize)); ++#endif ++ ++ /* Initilization. */ ++ map = Mmu->mapLogical; ++ _WritePageEntry(map, (Mmu->pageTableEntries << 8) | gcvMMU_FREE); ++ _WritePageEntry(map + 1, ~0U); ++ Mmu->heapList = 0; ++ Mmu->freeNodes = gcvFALSE; ++ ++ gcmkONERROR(gckOS_GetPhysicalAddress(Mmu->os, ++ Mmu->pageTableLogical, ++ &physical)); ++ ++ /* Grab the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Map to Master TLB. */ ++ for (i = (gctINT)Mmu->dynamicMappingStart; ++ i < (gctINT)Mmu->dynamicMappingStart + numEntries; ++ i++) ++ { ++ mtlbEntry = physical ++ /* 4KB page size */ ++ | (0 << 2) ++ /* Ignore exception */ ++ | (0 << 1) ++ /* Present */ ++ | (1 << 0); ++ ++ if (ace) ++ { ++ mtlbEntry = mtlbEntry ++ /* Secure */ ++ | (1 << 4); ++ } ++ ++ _WritePageEntry(Mmu->mtlbLogical + i, mtlbEntry); ++ ++#if gcdMMU_TABLE_DUMP ++ gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n", ++ __FUNCTION__, __LINE__, ++ i, ++ _ReadPageEntry(Mmu->mtlbLogical + i)); ++#endif ++ physical += gcdMMU_STLB_4K_SIZE; ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (Mmu->mapLogical) ++ { ++ gcmkVERIFY_OK( ++ gckOS_Free(Mmu->os, (gctPOINTER) Mmu->mapLogical)); ++ ++ ++ gcmkVERIFY_OK( ++ gckOS_FreeContiguous(Mmu->os, ++ Mmu->pageTablePhysical, ++ (gctPOINTER) Mmu->pageTableLogical, ++ Mmu->pageTableSize)); ++ } ++ ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ } ++ ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** _Construct ++** ++** Construct a new gckMMU object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctSIZE_T MmuSize ++** Number of bytes for the page table. ++** ++** OUTPUT: ++** ++** gckMMU * Mmu ++** Pointer to a variable that receives the gckMMU object pointer. ++*/ ++gceSTATUS ++_Construct( ++ IN gckKERNEL Kernel, ++ IN gctSIZE_T MmuSize, ++ OUT gckMMU * Mmu ++ ) ++{ ++ gckOS os; ++ gckHARDWARE hardware; ++ gceSTATUS status; ++ gckMMU mmu = gcvNULL; ++ gctUINT32_PTR map; ++ gctPOINTER pointer = gcvNULL; ++#if gcdPROCESS_ADDRESS_SPACE ++ gctUINT32 i; ++ gctUINT32 physical; ++#endif ++ gctUINT32 physBase; ++ gctUINT32 physSize; ++ gctUINT32 gpuAddress; ++ ++ gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(MmuSize > 0); ++ gcmkVERIFY_ARGUMENT(Mmu != gcvNULL); ++ ++ /* Extract the gckOS object pointer. */ ++ os = Kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Extract the gckHARDWARE object pointer. */ ++ hardware = Kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ /* Allocate memory for the gckMMU object. */ ++ gcmkONERROR(gckOS_Allocate(os, sizeof(struct _gckMMU), &pointer)); ++ ++ mmu = pointer; ++ ++ /* Initialize the gckMMU object. */ ++ mmu->object.type = gcvOBJ_MMU; ++ mmu->os = os; ++ mmu->hardware = hardware; ++ mmu->pageTableMutex = gcvNULL; ++ mmu->pageTableLogical = gcvNULL; ++ mmu->mtlbLogical = gcvNULL; ++ mmu->staticSTLB = gcvNULL; ++ mmu->enabled = gcvFALSE; ++ mmu->mapLogical = gcvNULL; ++ ++ /* Create the page table mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex)); ++ ++ if (hardware->mmuVersion == 0) ++ { ++ mmu->pageTableSize = MmuSize; ++ ++ /* Construct address space management table. */ ++ gcmkONERROR(gckOS_Allocate(mmu->os, ++ mmu->pageTableSize, ++ &pointer)); ++ ++ mmu->mapLogical = pointer; ++ ++ /* Construct page table read by GPU. */ ++ gcmkONERROR(gckOS_AllocateContiguous(mmu->os, ++ gcvFALSE, ++ &mmu->pageTableSize, ++ &mmu->pageTablePhysical, ++ (gctPOINTER)&mmu->pageTableLogical)); ++ ++ ++ /* Compute number of entries in page table. */ ++ gcmkSAFECASTSIZET(mmu->pageTableEntries, mmu->pageTableSize / sizeof(gctUINT32)); ++ ++ /* Mark all pages as free. */ ++ map = mmu->mapLogical; ++ ++#if gcdMMU_CLEAR_VALUE ++ _FillPageTable(mmu->pageTableLogical, mmu->pageTableEntries, gcdMMU_CLEAR_VALUE); ++#endif ++ ++ _WritePageEntry(map, (mmu->pageTableEntries << 8) | gcvMMU_FREE); ++ _WritePageEntry(map + 1, ~0U); ++ mmu->heapList = 0; ++ mmu->freeNodes = gcvFALSE; ++ } ++ else ++ { ++ /* Allocate the 4K mode MTLB table. */ ++ mmu->mtlbSize = gcdMMU_MTLB_SIZE + 64; ++ ++ gcmkONERROR( ++ gckOS_AllocateContiguous(os, ++ gcvFALSE, ++ &mmu->mtlbSize, ++ &mmu->mtlbPhysical, ++ &pointer)); ++ ++ mmu->mtlbLogical = pointer; ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ _FillPageTable(pointer, mmu->mtlbSize / 4, gcdMMU_MTLB_EXCEPTION); ++ ++ /* Allocate a array to store stlbs. */ ++ gcmkONERROR(gckOS_Allocate(os, mmu->mtlbSize, &mmu->stlbs)); ++ ++ gckOS_ZeroMemory(mmu->stlbs, mmu->mtlbSize); ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ gcmkONERROR(gckOS_AtomConstruct(os, &mmu->pageTableDirty[i])); ++ } ++ ++ _SetupProcessAddressSpace(mmu); ++ ++ /* Map kernel command buffer in MMU. */ ++ for (i = 0; i < gcdCOMMAND_QUEUES; i++) ++ { ++ gcmkONERROR(gckOS_GetPhysicalAddress( ++ mmu->os, ++ Kernel->command->queues[i].logical, ++ &physical ++ )); ++ ++ gcmkONERROR(gckMMU_FlatMapping(mmu, physical)); ++ } ++#else ++ /* Invalid all the entries. */ ++ gcmkONERROR( ++ gckOS_ZeroMemory(pointer, mmu->mtlbSize)); ++ ++ gcmkONERROR( ++ gckOS_QueryOption(mmu->os, "physBase", &physBase)); ++ ++ gcmkONERROR( ++ gckOS_QueryOption(mmu->os, "physSize", &physSize)); ++ ++ gcmkONERROR( ++ gckOS_CPUPhysicalToGPUPhysical(mmu->os, physBase, &gpuAddress)); ++ ++ /* Setup [physBase - physSize) flat mapping. */ ++ gcmkONERROR(_FillFlatMapping( ++ mmu, ++ gpuAddress, ++ physSize ++ )); ++ ++ gcmkONERROR(_SetupDynamicSpace(mmu)); ++#endif ++ } ++ ++ /* Return the gckMMU object pointer. */ ++ *Mmu = mmu; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Mmu=0x%x", *Mmu); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (mmu != gcvNULL) ++ { ++ if (mmu->mapLogical != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_Free(os, (gctPOINTER) mmu->mapLogical)); ++ ++ ++ gcmkVERIFY_OK( ++ gckOS_FreeContiguous(os, ++ mmu->pageTablePhysical, ++ (gctPOINTER) mmu->pageTableLogical, ++ mmu->pageTableSize)); ++ } ++ ++ if (mmu->mtlbLogical != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_FreeContiguous(os, ++ mmu->mtlbPhysical, ++ (gctPOINTER) mmu->mtlbLogical, ++ mmu->mtlbSize)); ++ } ++ ++ if (mmu->pageTableMutex != gcvNULL) ++ { ++ /* Delete the mutex. */ ++ gcmkVERIFY_OK( ++ gckOS_DeleteMutex(os, mmu->pageTableMutex)); ++ } ++ ++ /* Mark the gckMMU object as unknown. */ ++ mmu->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the allocates memory. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, mmu)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** _Destroy ++** ++** Destroy a gckMMU object. ++** ++** INPUT: ++** ++** gckMMU Mmu ++** Pointer to an gckMMU object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++_Destroy( ++ IN gckMMU Mmu ++ ) ++{ ++#if gcdPROCESS_ADDRESS_SPACE ++ gctUINT32 i; ++#endif ++ gcmkHEADER_ARG("Mmu=0x%x", Mmu); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ ++ while (Mmu->staticSTLB != gcvNULL) ++ { ++ gcsMMU_STLB_PTR pre = Mmu->staticSTLB; ++ Mmu->staticSTLB = pre->next; ++ ++ if (pre->physical != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_FreeContiguous(Mmu->os, ++ pre->physical, ++ pre->logical, ++ pre->size)); ++ } ++ ++ if (pre->mtlbEntryNum != 0) ++ { ++ gcmkASSERT(pre->mtlbEntryNum == 1); ++ _WritePageEntry(Mmu->mtlbLogical + pre->mtlbIndex, 0); ++#if gcdMMU_TABLE_DUMP ++ gckOS_Print("%s(%d): clean MTLB[%d]\n", ++ __FUNCTION__, __LINE__, ++ pre->mtlbIndex); ++#endif ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre)); ++ } ++ ++ if (Mmu->hardware->mmuVersion != 0) ++ { ++ gcmkVERIFY_OK( ++ gckOS_FreeContiguous(Mmu->os, ++ Mmu->mtlbPhysical, ++ (gctPOINTER) Mmu->mtlbLogical, ++ Mmu->mtlbSize)); ++ } ++ ++ /* Free address space management table. */ ++ if (Mmu->mapLogical != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_Free(Mmu->os, (gctPOINTER) Mmu->mapLogical)); ++ } ++ ++ if (Mmu->pageTableLogical != gcvNULL) ++ { ++ /* Free page table. */ ++ gcmkVERIFY_OK( ++ gckOS_FreeContiguous(Mmu->os, ++ Mmu->pageTablePhysical, ++ (gctPOINTER) Mmu->pageTableLogical, ++ Mmu->pageTableSize)); ++ } ++ ++ /* Delete the page table mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex)); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ for (i = 0; i < Mmu->mtlbSize / 4; i++) ++ { ++ struct _gcsMMU_STLB *stlb = ((struct _gcsMMU_STLB **)Mmu->stlbs)[i]; ++ ++ if (stlb) ++ { ++ gcmkVERIFY_OK(gckOS_FreeContiguous( ++ Mmu->os, ++ stlb->physical, ++ stlb->logical, ++ stlb->size)); ++ ++ gcmkOS_SAFE_FREE(Mmu->os, stlb); ++ } ++ } ++ ++ gcmkOS_SAFE_FREE(Mmu->os, Mmu->stlbs); ++#endif ++ ++ /* Mark the gckMMU object as unknown. */ ++ Mmu->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckMMU object. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, Mmu)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** _AdjstIndex ++** ++** Adjust the index from which we search for a usable node to make sure ++** index allocated is greater than Start. ++*/ ++gceSTATUS ++_AdjustIndex( ++ IN gckMMU Mmu, ++ IN gctUINT32 Index, ++ IN gctUINT32 PageCount, ++ IN gctUINT32 Start, ++ OUT gctUINT32 * IndexAdjusted ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 index = Index; ++ gctUINT32_PTR map = Mmu->mapLogical; ++ ++ gcmkHEADER(); ++ ++ for (; index < Mmu->pageTableEntries;) ++ { ++ gctUINT32 result = 0; ++ gctUINT32 nodeSize = 0; ++ ++ if (index >= Start) ++ { ++ break; ++ } ++ ++ switch (gcmENTRY_TYPE(map[index])) ++ { ++ case gcvMMU_SINGLE: ++ nodeSize = 1; ++ break; ++ ++ case gcvMMU_FREE: ++ nodeSize = map[index] >> 8; ++ break; ++ ++ default: ++ gcmkFATAL("MMU table correcupted at index %u!", index); ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ if (nodeSize > PageCount) ++ { ++ result = index + (nodeSize - PageCount); ++ ++ if (result >= Start) ++ { ++ break; ++ } ++ } ++ ++ switch (gcmENTRY_TYPE(map[index])) ++ { ++ case gcvMMU_SINGLE: ++ index = map[index] >> 8; ++ break; ++ ++ case gcvMMU_FREE: ++ index = map[index + 1]; ++ break; ++ ++ default: ++ gcmkFATAL("MMU table correcupted at index %u!", index); ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ } ++ ++ *IndexAdjusted = index; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckMMU_Construct( ++ IN gckKERNEL Kernel, ++ IN gctSIZE_T MmuSize, ++ OUT gckMMU * Mmu ++ ) ++{ ++#if gcdSHARED_PAGETABLE ++ gceSTATUS status; ++ gctPOINTER pointer; ++ ++ gcmkHEADER_ARG("Kernel=0x%08x", Kernel); ++ ++ if (sharedPageTable == gcvNULL) ++ { ++ gcmkONERROR( ++ gckOS_Allocate(Kernel->os, ++ sizeof(struct _gcsSharedPageTable), ++ &pointer)); ++ sharedPageTable = pointer; ++ ++ gcmkONERROR( ++ gckOS_ZeroMemory(sharedPageTable, ++ sizeof(struct _gcsSharedPageTable))); ++ ++ gcmkONERROR(_Construct(Kernel, MmuSize, &sharedPageTable->mmu)); ++ } ++ ++ *Mmu = sharedPageTable->mmu; ++ ++ sharedPageTable->hardwares[sharedPageTable->reference] = Kernel->hardware; ++ ++ sharedPageTable->reference++; ++ ++ gcmkFOOTER_ARG("sharedPageTable->reference=%lu", sharedPageTable->reference); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (sharedPageTable) ++ { ++ if (sharedPageTable->mmu) ++ { ++ gcmkVERIFY_OK(gckMMU_Destroy(sharedPageTable->mmu)); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, sharedPageTable)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++#elif gcdMIRROR_PAGETABLE ++ gceSTATUS status; ++ gctPOINTER pointer; ++ ++ gcmkHEADER_ARG("Kernel=0x%08x", Kernel); ++ ++ if (mirrorPageTable == gcvNULL) ++ { ++ gcmkONERROR( ++ gckOS_Allocate(Kernel->os, ++ sizeof(struct _gcsMirrorPageTable), ++ &pointer)); ++ mirrorPageTable = pointer; ++ ++ gcmkONERROR( ++ gckOS_ZeroMemory(mirrorPageTable, ++ sizeof(struct _gcsMirrorPageTable))); ++ ++ gcmkONERROR( ++ gckOS_CreateMutex(Kernel->os, &mirrorPageTableMutex)); ++ } ++ ++ gcmkONERROR(_Construct(Kernel, MmuSize, Mmu)); ++ ++ mirrorPageTable->mmus[mirrorPageTable->reference] = *Mmu; ++ ++ mirrorPageTable->hardwares[mirrorPageTable->reference] = Kernel->hardware; ++ ++ mirrorPageTable->reference++; ++ ++ gcmkFOOTER_ARG("mirrorPageTable->reference=%lu", mirrorPageTable->reference); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (mirrorPageTable && mirrorPageTable->reference == 0) ++ { ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, mirrorPageTable)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++#else ++ return _Construct(Kernel, MmuSize, Mmu); ++#endif ++} ++ ++gceSTATUS ++gckMMU_Destroy( ++ IN gckMMU Mmu ++ ) ++{ ++#if gcdSHARED_PAGETABLE ++ gckOS os = Mmu->os; ++ ++ sharedPageTable->reference--; ++ ++ if (sharedPageTable->reference == 0) ++ { ++ if (sharedPageTable->mmu) ++ { ++ gcmkVERIFY_OK(_Destroy(Mmu)); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, sharedPageTable)); ++ } ++ ++ return gcvSTATUS_OK; ++#elif gcdMIRROR_PAGETABLE ++ mirrorPageTable->reference--; ++ ++ if (mirrorPageTable->reference == 0) ++ { ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, mirrorPageTable)); ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, mirrorPageTableMutex)); ++ } ++ ++ return _Destroy(Mmu); ++#else ++ return _Destroy(Mmu); ++#endif ++} ++ ++/******************************************************************************* ++** ++** gckMMU_AllocatePages ++** ++** Allocate pages inside the page table. ++** ++** INPUT: ++** ++** gckMMU Mmu ++** Pointer to an gckMMU object. ++** ++** gctSIZE_T PageCount ++** Number of pages to allocate. ++** ++** OUTPUT: ++** ++** gctPOINTER * PageTable ++** Pointer to a variable that receives the base address of the page ++** table. ++** ++** gctUINT32 * Address ++** Pointer to a variable that receives the hardware specific address. ++*/ ++gceSTATUS ++_AllocatePages( ++ IN gckMMU Mmu, ++ IN gctSIZE_T PageCount, ++ IN gceSURF_TYPE Type, ++ OUT gctPOINTER * PageTable, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL mutex = gcvFALSE; ++ gctUINT32 index = 0, previous = ~0U, left; ++ gctUINT32_PTR map; ++ gctBOOL gotIt; ++ gctUINT32 address; ++ gctUINT32 pageCount; ++ ++ gcmkHEADER_ARG("Mmu=0x%x PageCount=%lu", Mmu, PageCount); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT(PageCount > 0); ++ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); ++ ++ if (PageCount > Mmu->pageTableEntries) ++ { ++ /* Not enough pages avaiable. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ gcmkSAFECASTSIZET(pageCount, PageCount); ++ ++ /* Grab the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); ++ mutex = gcvTRUE; ++ ++ /* Cast pointer to page table. */ ++ for (map = Mmu->mapLogical, gotIt = gcvFALSE; !gotIt;) ++ { ++ index = Mmu->heapList; ++ ++ if ((Mmu->hardware->mmuVersion == 0) && (Type == gcvSURF_VERTEX)) ++ { ++ gcmkONERROR(_AdjustIndex( ++ Mmu, ++ index, ++ pageCount, ++ gcdVERTEX_START / gcmSIZEOF(gctUINT32), ++ &index ++ )); ++ } ++ ++ /* Walk the heap list. */ ++ for (; !gotIt && (index < Mmu->pageTableEntries);) ++ { ++ /* Check the node type. */ ++ switch (gcmENTRY_TYPE(_ReadPageEntry(&map[index]))) ++ { ++ case gcvMMU_SINGLE: ++ /* Single odes are valid if we only need 1 page. */ ++ if (pageCount == 1) ++ { ++ gotIt = gcvTRUE; ++ } ++ else ++ { ++ /* Move to next node. */ ++ previous = index; ++ index = _ReadPageEntry(&map[index]) >> 8; ++ } ++ break; ++ ++ case gcvMMU_FREE: ++ /* Test if the node has enough space. */ ++ if (pageCount <= (_ReadPageEntry(&map[index]) >> 8)) ++ { ++ gotIt = gcvTRUE; ++ } ++ else ++ { ++ /* Move to next node. */ ++ previous = index; ++ index = _ReadPageEntry(&map[index + 1]); ++ } ++ break; ++ ++ default: ++ gcmkFATAL("MMU table correcupted at index %u!", index); ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ } ++ ++ /* Test if we are out of memory. */ ++ if (index >= Mmu->pageTableEntries) ++ { ++ if (Mmu->freeNodes) ++ { ++ /* Time to move out the trash! */ ++ gcmkONERROR(_Collect(Mmu)); ++ } ++ else ++ { ++ /* Out of resources. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ } ++ } ++ ++ switch (gcmENTRY_TYPE(_ReadPageEntry(&map[index]))) ++ { ++ case gcvMMU_SINGLE: ++ /* Unlink single node from free list. */ ++ gcmkONERROR( ++ _Link(Mmu, previous, _ReadPageEntry(&map[index]) >> 8)); ++ break; ++ ++ case gcvMMU_FREE: ++ /* Check how many pages will be left. */ ++ left = (_ReadPageEntry(&map[index]) >> 8) - pageCount; ++ switch (left) ++ { ++ case 0: ++ /* The entire node is consumed, just unlink it. */ ++ gcmkONERROR( ++ _Link(Mmu, previous, _ReadPageEntry(&map[index + 1]))); ++ break; ++ ++ case 1: ++ /* One page will remain. Convert the node to a single node and ++ ** advance the index. */ ++ _WritePageEntry(&map[index], (_ReadPageEntry(&map[index + 1]) << 8) | gcvMMU_SINGLE); ++ index ++; ++ break; ++ ++ default: ++ /* Enough pages remain for a new node. However, we will just adjust ++ ** the size of the current node and advance the index. */ ++ _WritePageEntry(&map[index], (left << 8) | gcvMMU_FREE); ++ index += left; ++ break; ++ } ++ break; ++ } ++ ++ /* Mark node as used. */ ++ gcmkONERROR(_FillPageTable(&map[index], pageCount, gcvMMU_USED)); ++ ++ /* Return pointer to page table. */ ++ *PageTable = &Mmu->pageTableLogical[index]; ++ ++ /* Build virtual address. */ ++ if (Mmu->hardware->mmuVersion == 0) ++ { ++ gcmkONERROR( ++ gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address)); ++ } ++ else ++ { ++ gctUINT32 masterOffset = index / gcdMMU_STLB_4K_ENTRY_NUM ++ + Mmu->dynamicMappingStart; ++ gctUINT32 slaveOffset = index % gcdMMU_STLB_4K_ENTRY_NUM; ++ ++ address = (masterOffset << gcdMMU_MTLB_SHIFT) ++ | (slaveOffset << gcdMMU_STLB_4K_SHIFT); ++ } ++ ++ if (Address != gcvNULL) ++ { ++ *Address = address; ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x", ++ *PageTable, gcmOPT_VALUE(Address)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ if (mutex) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckMMU_FreePages ++** ++** Free pages inside the page table. ++** ++** INPUT: ++** ++** gckMMU Mmu ++** Pointer to an gckMMU object. ++** ++** gctPOINTER PageTable ++** Base address of the page table to free. ++** ++** gctSIZE_T PageCount ++** Number of pages to free. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++_FreePages( ++ IN gckMMU Mmu, ++ IN gctPOINTER PageTable, ++ IN gctSIZE_T PageCount ++ ) ++{ ++ gctUINT32_PTR node; ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gctUINT32 pageCount; ++ ++ gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu", ++ Mmu, PageTable, PageCount); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); ++ gcmkVERIFY_ARGUMENT(PageCount > 0); ++ ++ gcmkSAFECASTSIZET(pageCount, PageCount); ++ ++ /* Get the node by index. */ ++ node = Mmu->mapLogical + ((gctUINT32_PTR)PageTable - Mmu->pageTableLogical); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++#if gcdMMU_CLEAR_VALUE ++ if (Mmu->hardware->mmuVersion == 0) ++ { ++ _FillPageTable(PageTable, pageCount, gcdMMU_CLEAR_VALUE); ++ } ++#endif ++ ++ if (PageCount == 1) ++ { ++ /* Single page node. */ ++ _WritePageEntry(node, (~((1U<<8)-1)) | gcvMMU_SINGLE); ++#if gcdUSE_MMU_EXCEPTION ++ /* Enable exception */ ++ _WritePageEntry(PageTable, (1 << 1)); ++#endif ++ } ++ else ++ { ++ /* Mark the node as free. */ ++ _WritePageEntry(node, (pageCount << 8) | gcvMMU_FREE); ++ _WritePageEntry(node + 1, ~0U); ++ ++#if gcdUSE_MMU_EXCEPTION ++ /* Enable exception */ ++ gcmkVERIFY_OK(_FillPageTable(PageTable, pageCount, 1 << 1)); ++#endif ++ } ++ ++ /* We have free nodes. */ ++ Mmu->freeNodes = gcvTRUE; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ acquired = gcvFALSE; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckMMU_AllocatePages( ++ IN gckMMU Mmu, ++ IN gctSIZE_T PageCount, ++ OUT gctPOINTER * PageTable, ++ OUT gctUINT32 * Address ++ ) ++{ ++ return gckMMU_AllocatePagesEx( ++ Mmu, PageCount, gcvSURF_TYPE_UNKNOWN, PageTable, Address); ++} ++ ++gceSTATUS ++gckMMU_AllocatePagesEx( ++ IN gckMMU Mmu, ++ IN gctSIZE_T PageCount, ++ IN gceSURF_TYPE Type, ++ OUT gctPOINTER * PageTable, ++ OUT gctUINT32 * Address ++ ) ++{ ++#if gcdMIRROR_PAGETABLE ++ gceSTATUS status; ++ gctPOINTER pageTable; ++ gctUINT32 address; ++ gctINT i; ++ gckMMU mmu; ++ gctBOOL acquired = gcvFALSE; ++ gctBOOL allocated = gcvFALSE; ++ ++ gckOS_AcquireMutex(Mmu->os, mirrorPageTableMutex, gcvINFINITE); ++ acquired = gcvTRUE; ++ ++ /* Allocate page table for current MMU. */ ++ for (i = 0; i < (gctINT)mirrorPageTable->reference; i++) ++ { ++ if (Mmu == mirrorPageTable->mmus[i]) ++ { ++ gcmkONERROR(_AllocatePages(Mmu, PageCount, Type, PageTable, Address)); ++ allocated = gcvTRUE; ++ } ++ } ++ ++ /* Allocate page table for other MMUs. */ ++ for (i = 0; i < (gctINT)mirrorPageTable->reference; i++) ++ { ++ mmu = mirrorPageTable->mmus[i]; ++ ++ if (Mmu != mmu) ++ { ++ gcmkONERROR(_AllocatePages(mmu, PageCount, Type, &pageTable, &address)); ++ gcmkASSERT(address == *Address); ++ } ++ } ++ ++ gckOS_ReleaseMutex(Mmu->os, mirrorPageTableMutex); ++ acquired = gcvFALSE; ++ ++ return gcvSTATUS_OK; ++OnError: ++ ++ if (allocated) ++ { ++ /* Page tables for multiple GPU always keep the same. So it is impossible ++ * the fist one allocates successfully but others fail. ++ */ ++ gcmkASSERT(0); ++ } ++ ++ if (acquired) ++ { ++ gckOS_ReleaseMutex(Mmu->os, mirrorPageTableMutex); ++ } ++ ++ return status; ++#else ++ return _AllocatePages(Mmu, PageCount, Type, PageTable, Address); ++#endif ++} ++ ++gceSTATUS ++gckMMU_FreePages( ++ IN gckMMU Mmu, ++ IN gctPOINTER PageTable, ++ IN gctSIZE_T PageCount ++ ) ++{ ++#if gcdMIRROR_PAGETABLE ++ gctINT i; ++ gctUINT32 offset; ++ gckMMU mmu; ++ ++ gckOS_AcquireMutex(Mmu->os, mirrorPageTableMutex, gcvINFINITE); ++ ++ gcmkVERIFY_OK(_FreePages(Mmu, PageTable, PageCount)); ++ ++ offset = (gctUINT32)PageTable - (gctUINT32)Mmu->pageTableLogical; ++ ++ for (i = 0; i < (gctINT)mirrorPageTable->reference; i++) ++ { ++ mmu = mirrorPageTable->mmus[i]; ++ ++ if (mmu != Mmu) ++ { ++ gcmkVERIFY_OK(_FreePages(mmu, mmu->pageTableLogical + offset/4, PageCount)); ++ } ++ } ++ ++ gckOS_ReleaseMutex(Mmu->os, mirrorPageTableMutex); ++ ++ return gcvSTATUS_OK; ++#else ++ return _FreePages(Mmu, PageTable, PageCount); ++#endif ++} ++ ++gceSTATUS ++gckMMU_SetPage( ++ IN gckMMU Mmu, ++ IN gctUINT32 PageAddress, ++ IN gctUINT32 *PageEntry ++ ) ++{ ++#if gcdMIRROR_PAGETABLE ++ gctUINT32_PTR pageEntry; ++ gctINT i; ++ gckMMU mmu; ++ gctUINT32 offset = (gctUINT32)PageEntry - (gctUINT32)Mmu->pageTableLogical; ++#endif ++ ++ gcmkHEADER_ARG("Mmu=0x%x", Mmu); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL); ++ gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF)); ++ ++ if (Mmu->hardware->mmuVersion == 0) ++ { ++ _WritePageEntry(PageEntry, PageAddress); ++ } ++ else ++ { ++ _WritePageEntry(PageEntry, _SetPage(PageAddress)); ++ } ++ ++#if gcdMIRROR_PAGETABLE ++ for (i = 0; i < (gctINT)mirrorPageTable->reference; i++) ++ { ++ mmu = mirrorPageTable->mmus[i]; ++ ++ if (mmu != Mmu) ++ { ++ pageEntry = mmu->pageTableLogical + offset / 4; ++ ++ if (mmu->hardware->mmuVersion == 0) ++ { ++ _WritePageEntry(pageEntry, PageAddress); ++ } ++ else ++ { ++ _WritePageEntry(pageEntry, _SetPage(PageAddress)); ++ } ++ } ++ ++ } ++#endif ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gceSTATUS ++gckMMU_GetPageEntry( ++ IN gckMMU Mmu, ++ IN gctUINT32 Address, ++ IN gctUINT32_PTR *PageTable ++ ) ++{ ++ gceSTATUS status; ++ struct _gcsMMU_STLB *stlb; ++ struct _gcsMMU_STLB **stlbs = Mmu->stlbs; ++ gctUINT32 offset = _MtlbOffset(Address); ++ gctUINT32 mtlbEntry; ++ gctBOOL ace = gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_ACE); ++ ++ gcmkHEADER_ARG("Mmu=0x%x", Mmu); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT((Address & 0xFFF) == 0); ++ ++ stlb = stlbs[offset]; ++ ++ if (stlb == gcvNULL) ++ { ++ gcmkONERROR(_AllocateStlb(Mmu->os, &stlb)); ++ ++ mtlbEntry = stlb->physBase ++ | gcdMMU_MTLB_4K_PAGE ++ | gcdMMU_MTLB_PRESENT ++ ; ++ ++ if (ace) ++ { ++ mtlbEntry = mtlbEntry ++ /* Secure */ ++ | (1 << 4); ++ } ++ ++ /* Insert Slave TLB address to Master TLB entry.*/ ++ _WritePageEntry(Mmu->mtlbLogical + offset, mtlbEntry); ++ ++ /* Record stlb. */ ++ stlbs[offset] = stlb; ++ } ++ ++ *PageTable = &stlb->logical[_StlbOffset(Address)]; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++_CheckMap( ++ IN gckMMU Mmu ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32_PTR map = Mmu->mapLogical; ++ gctUINT32 index; ++ ++ for (index = Mmu->heapList; index < Mmu->pageTableEntries;) ++ { ++ /* Check the node type. */ ++ switch (gcmENTRY_TYPE(_ReadPageEntry(&map[index]))) ++ { ++ case gcvMMU_SINGLE: ++ /* Move to next node. */ ++ index = _ReadPageEntry(&map[index]) >> 8; ++ break; ++ ++ case gcvMMU_FREE: ++ /* Move to next node. */ ++ index = _ReadPageEntry(&map[index + 1]); ++ break; ++ ++ default: ++ gcmkFATAL("MMU table correcupted at index [%u] = %x!", index, map[index]); ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ } ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ return status; ++} ++ ++gceSTATUS ++gckMMU_FlatMapping( ++ IN gckMMU Mmu, ++ IN gctUINT32 Physical ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 index = _AddressToIndex(Mmu, Physical); ++ gctUINT32 i; ++ gctBOOL gotIt = gcvFALSE; ++ gctUINT32_PTR map = Mmu->mapLogical; ++ gctUINT32 previous = ~0U; ++ gctUINT32_PTR pageTable; ++ ++ gckMMU_GetPageEntry(Mmu, Physical, &pageTable); ++ ++ _WritePageEntry(pageTable, _SetPage(Physical)); ++ ++ if (map) ++ { ++ /* Find node which contains index. */ ++ for (i = 0; !gotIt && (i < Mmu->pageTableEntries);) ++ { ++ gctUINT32 numPages; ++ ++ switch (gcmENTRY_TYPE(_ReadPageEntry(&map[i]))) ++ { ++ case gcvMMU_SINGLE: ++ if (i == index) ++ { ++ gotIt = gcvTRUE; ++ } ++ else ++ { ++ previous = i; ++ i = _ReadPageEntry(&map[i]) >> 8; ++ } ++ break; ++ ++ case gcvMMU_FREE: ++ numPages = _ReadPageEntry(&map[i]) >> 8; ++ if (index >= i && index < i + numPages) ++ { ++ gotIt = gcvTRUE; ++ } ++ else ++ { ++ previous = i; ++ i = _ReadPageEntry(&map[i + 1]); ++ } ++ break; ++ ++ default: ++ gcmkFATAL("MMU table correcupted at index %u!", index); ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ } ++ ++ switch (gcmENTRY_TYPE(_ReadPageEntry(&map[i]))) ++ { ++ case gcvMMU_SINGLE: ++ /* Unlink single node from free list. */ ++ gcmkONERROR( ++ _Link(Mmu, previous, _ReadPageEntry(&map[i]) >> 8)); ++ break; ++ ++ case gcvMMU_FREE: ++ /* Split the node. */ ++ { ++ gctUINT32 start; ++ gctUINT32 next = _ReadPageEntry(&map[i+1]); ++ gctUINT32 total = _ReadPageEntry(&map[i]) >> 8; ++ gctUINT32 countLeft = index - i; ++ gctUINT32 countRight = total - countLeft - 1; ++ ++ if (countLeft) ++ { ++ start = i; ++ _AddFree(Mmu, previous, start, countLeft); ++ previous = start; ++ } ++ ++ if (countRight) ++ { ++ start = index + 1; ++ _AddFree(Mmu, previous, start, countRight); ++ previous = start; ++ } ++ ++ _Link(Mmu, previous, next); ++ } ++ break; ++ } ++ } ++ ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++ /* Roll back. */ ++ return status; ++} ++ ++ ++ ++gceSTATUS ++gckMMU_FreePagesEx( ++ IN gckMMU Mmu, ++ IN gctUINT32 Address, ++ IN gctSIZE_T PageCount ++ ) ++{ ++ gctUINT32_PTR node; ++ gceSTATUS status; ++ ++#if gcdUSE_MMU_EXCEPTION ++ gctUINT32 i; ++ struct _gcsMMU_STLB *stlb; ++ struct _gcsMMU_STLB **stlbs = Mmu->stlbs; ++#endif ++ ++ gcmkHEADER_ARG("Mmu=0x%x Address=0x%x PageCount=%lu", ++ Mmu, Address, PageCount); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT(PageCount > 0); ++ ++ /* Get the node by index. */ ++ node = Mmu->mapLogical + _AddressToIndex(Mmu, Address); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); ++ ++ if (PageCount == 1) ++ { ++ /* Single page node. */ ++ _WritePageEntry(node, (~((1U<<8)-1)) | gcvMMU_SINGLE); ++ } ++ else ++ { ++ /* Mark the node as free. */ ++ _WritePageEntry(node, (PageCount << 8) | gcvMMU_FREE); ++ _WritePageEntry(node + 1, ~0U); ++ } ++ ++ /* We have free nodes. */ ++ Mmu->freeNodes = gcvTRUE; ++ ++#if gcdUSE_MMU_EXCEPTION ++ for (i = 0; i < PageCount; i++) ++ { ++ /* Get */ ++ stlb = stlbs[_MtlbOffset(Address)]; ++ ++ /* Enable exception */ ++ stlb->logical[_StlbOffset(Address)] = gcdMMU_STLB_EXCEPTION; ++ } ++#endif ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); ++ ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++gceSTATUS ++gckMMU_Flush( ++ IN gckMMU Mmu, ++ IN gceSURF_TYPE Type ++ ) ++{ ++ gckHARDWARE hardware; ++ gctUINT32 mask; ++ gctINT i; ++ ++ if (Type == gcvSURF_VERTEX || Type == gcvSURF_INDEX) ++ { ++ mask = gcvPAGE_TABLE_DIRTY_BIT_FE; ++ } ++ else ++ { ++ mask = gcvPAGE_TABLE_DIRTY_BIT_OTHER; ++ } ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ gcmkVERIFY_OK( ++ gckOS_AtomSetMask(Mmu->pageTableDirty[i], mask)); ++ } ++#else ++#if gcdSHARED_PAGETABLE ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ hardware = sharedPageTable->hardwares[i]; ++ if (hardware) ++ { ++ gcmkVERIFY_OK(gckOS_AtomSetMask(hardware->pageTableDirty, mask)); ++ } ++ } ++#elif gcdMIRROR_PAGETABLE ++ for (i = 0; i < (gctINT)mirrorPageTable->reference; i++) ++ { ++ hardware = mirrorPageTable->hardwares[i]; ++ ++ /* Notify cores who use this page table. */ ++ gcmkVERIFY_OK( ++ gckOS_AtomSetMask(hardware->pageTableDirty, mask)); ++ } ++#else ++ hardware = Mmu->hardware; ++ gcmkVERIFY_OK( ++ gckOS_AtomSetMask(hardware->pageTableDirty, mask)); ++#endif ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckMMU_DumpPageTableEntry( ++ IN gckMMU Mmu, ++ IN gctUINT32 Address ++ ) ++{ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcsMMU_STLB_PTR *stlbs = Mmu->stlbs; ++ gcsMMU_STLB_PTR stlbDesc = stlbs[_MtlbOffset(Address)]; ++#else ++ gctUINT32_PTR pageTable; ++ gctUINT32 index; ++ gctUINT32 mtlb, stlb; ++#endif ++ ++ gcmkHEADER_ARG("Mmu=0x%08X Address=0x%08X", Mmu, Address); ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ ++ gcmkASSERT(Mmu->hardware->mmuVersion > 0); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ if (stlbDesc) ++ { ++ gcmkPRINT(" STLB entry = 0x%08X", ++ _ReadPageEntry(&stlbDesc->logical[_StlbOffset(Address)])); ++ } ++ else ++ { ++ gcmkPRINT(" MTLB entry is empty."); ++ } ++#else ++ mtlb = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT; ++ ++ if (mtlb >= Mmu->dynamicMappingStart) ++ { ++ stlb = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT; ++ ++ pageTable = Mmu->pageTableLogical; ++ ++ index = (mtlb - Mmu->dynamicMappingStart) ++ * gcdMMU_STLB_4K_ENTRY_NUM ++ + stlb; ++ ++ gcmkPRINT(" Page table entry = 0x%08X", _ReadPageEntry(pageTable + index)); ++ } ++ else ++ { ++ gcsMMU_STLB_PTR stlbObj = Mmu->staticSTLB; ++ gctUINT32 entry = Mmu->mtlbLogical[mtlb]; ++ ++ stlb = (Address & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT; ++ ++ entry &= 0xFFFFFFF0; ++ ++ while (stlbObj) ++ { ++ ++ if (entry == stlbObj->physBase) ++ { ++ gcmkPRINT(" Page table entry = 0x%08X", stlbObj->logical[stlb]); ++ break; ++ } ++ ++ stlbObj = stlbObj->next; ++ } ++ } ++#endif ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/****************************************************************************** ++****************************** T E S T C O D E ****************************** ++******************************************************************************/ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c 2016-06-19 22:11:55.145150505 +0200 +@@ -0,0 +1,522 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#if gcdENABLE_VG ++ ++#define _GC_OBJ_ZONE gcvZONE_MMU ++ ++/******************************************************************************* ++** ++** gckVGMMU_Construct ++** ++** Construct a new gckVGMMU object. ++** ++** INPUT: ++** ++** gckVGKERNEL Kernel ++** Pointer to an gckVGKERNEL object. ++** ++** gctSIZE_T MmuSize ++** Number of bytes for the page table. ++** ++** OUTPUT: ++** ++** gckVGMMU * Mmu ++** Pointer to a variable that receives the gckVGMMU object pointer. ++*/ ++gceSTATUS gckVGMMU_Construct( ++ IN gckVGKERNEL Kernel, ++ IN gctUINT32 MmuSize, ++ OUT gckVGMMU * Mmu ++ ) ++{ ++ gckOS os; ++ gckVGHARDWARE hardware; ++ gceSTATUS status; ++ gckVGMMU mmu; ++ gctUINT32 * pageTable; ++ gctUINT32 i; ++ ++ gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(MmuSize > 0); ++ gcmkVERIFY_ARGUMENT(Mmu != gcvNULL); ++ ++ /* Extract the gckOS object pointer. */ ++ os = Kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Extract the gckVGHARDWARE object pointer. */ ++ hardware = Kernel->hardware; ++ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); ++ ++ /* Allocate memory for the gckVGMMU object. */ ++ status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu); ++ ++ if (status < 0) ++ { ++ /* Error. */ ++ gcmkFATAL( ++ "%s(%d): could not allocate gckVGMMU object.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkFOOTER(); ++ return status; ++ } ++ ++ /* Initialize the gckVGMMU object. */ ++ mmu->object.type = gcvOBJ_MMU; ++ mmu->os = os; ++ mmu->hardware = hardware; ++ ++ /* Create the mutex. */ ++ status = gckOS_CreateMutex(os, &mmu->mutex); ++ ++ if (status < 0) ++ { ++ /* Roll back. */ ++ mmu->object.type = gcvOBJ_UNKNOWN; ++ gcmkVERIFY_OK(gckOS_Free(os, mmu)); ++ ++ gcmkFOOTER(); ++ /* Error. */ ++ return status; ++ } ++ ++ /* Allocate the page table. */ ++ mmu->pageTableSize = (gctUINT32)MmuSize; ++ status = gckOS_AllocateContiguous(os, ++ gcvFALSE, ++ &mmu->pageTableSize, ++ &mmu->pageTablePhysical, ++ &mmu->pageTableLogical); ++ ++ if (status < 0) ++ { ++ /* Roll back. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex)); ++ ++ mmu->object.type = gcvOBJ_UNKNOWN; ++ gcmkVERIFY_OK(gckOS_Free(os, mmu)); ++ ++ /* Error. */ ++ gcmkFATAL( ++ "%s(%d): could not allocate page table.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkFOOTER(); ++ return status; ++ } ++ ++ /* Compute number of entries in page table. */ ++ mmu->entryCount = (gctUINT32)mmu->pageTableSize / sizeof(gctUINT32); ++ mmu->entry = 0; ++ ++ /* Mark the entire page table as available. */ ++ pageTable = (gctUINT32 *) mmu->pageTableLogical; ++ for (i = 0; i < mmu->entryCount; i++) ++ { ++ pageTable[i] = (gctUINT32)~0; ++ } ++ ++ /* Set page table address. */ ++ status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical); ++ ++ if (status < 0) ++ { ++ /* Free the page table. */ ++ gcmkVERIFY_OK(gckOS_FreeContiguous(mmu->os, ++ mmu->pageTablePhysical, ++ mmu->pageTableLogical, ++ mmu->pageTableSize)); ++ ++ /* Roll back. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex)); ++ ++ mmu->object.type = gcvOBJ_UNKNOWN; ++ gcmkVERIFY_OK(gckOS_Free(os, mmu)); ++ ++ /* Error. */ ++ gcmkFATAL( ++ "%s(%d): could not program page table.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkFOOTER(); ++ return status; ++ } ++ ++ /* Return the gckVGMMU object pointer. */ ++ *Mmu = mmu; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_MMU, ++ "%s(%d): %u entries at %p.(0x%08X)\n", ++ __FUNCTION__, __LINE__, ++ mmu->entryCount, ++ mmu->pageTableLogical, ++ mmu->pageTablePhysical ++ ); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGMMU_Destroy ++** ++** Destroy a nAQMMU object. ++** ++** INPUT: ++** ++** gckVGMMU Mmu ++** Pointer to an gckVGMMU object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS gckVGMMU_Destroy( ++ IN gckVGMMU Mmu ++ ) ++{ ++ gcmkHEADER_ARG("Mmu=0x%x", Mmu); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ ++ /* Free the page table. */ ++ gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu->os, ++ Mmu->pageTablePhysical, ++ Mmu->pageTableLogical, ++ Mmu->pageTableSize)); ++ ++ /* Roll back. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex)); ++ ++ /* Mark the gckVGMMU object as unknown. */ ++ Mmu->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckVGMMU object. */ ++ gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu)); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVGMMU_AllocatePages ++** ++** Allocate pages inside the page table. ++** ++** INPUT: ++** ++** gckVGMMU Mmu ++** Pointer to an gckVGMMU object. ++** ++** gctSIZE_T PageCount ++** Number of pages to allocate. ++** ++** OUTPUT: ++** ++** gctPOINTER * PageTable ++** Pointer to a variable that receives the base address of the page ++** table. ++** ++** gctUINT32 * Address ++** Pointer to a variable that receives the hardware specific address. ++*/ ++gceSTATUS gckVGMMU_AllocatePages( ++ IN gckVGMMU Mmu, ++ IN gctSIZE_T PageCount, ++ OUT gctPOINTER * PageTable, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 tail, index, i; ++ gctUINT32 * table; ++ gctBOOL allocated = gcvFALSE; ++ ++ gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x", ++ Mmu, PageCount, PageTable, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT(PageCount > 0); ++ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_MMU, ++ "%s(%d): %u pages.\n", ++ __FUNCTION__, __LINE__, ++ PageCount ++ ); ++ ++ if (PageCount > Mmu->entryCount) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_MMU, ++ "%s(%d): page table too small for %u pages.\n", ++ __FUNCTION__, __LINE__, ++ PageCount ++ ); ++ ++ gcmkFOOTER_NO(); ++ /* Not enough pages avaiable. */ ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++ /* Grab the mutex. */ ++ status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE); ++ ++ if (status < 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_MMU, ++ "%s(%d): could not acquire mutex.\n" ++ ,__FUNCTION__, __LINE__ ++ ); ++ ++ gcmkFOOTER(); ++ /* Error. */ ++ return status; ++ } ++ ++ /* Compute the tail for this allocation. */ ++ tail = Mmu->entryCount - (gctUINT32)PageCount; ++ ++ /* Walk all entries until we find enough slots. */ ++ for (index = Mmu->entry; index <= tail;) ++ { ++ /* Access page table. */ ++ table = (gctUINT32 *) Mmu->pageTableLogical + index; ++ ++ /* See if all slots are available. */ ++ for (i = 0; i < PageCount; i++, table++) ++ { ++ if (*table != ~0) ++ { ++ /* Start from next slot. */ ++ index += i + 1; ++ break; ++ } ++ } ++ ++ if (i == PageCount) ++ { ++ /* Bail out if we have enough page entries. */ ++ allocated = gcvTRUE; ++ break; ++ } ++ } ++ ++ if (!allocated) ++ { ++ if (status >= 0) ++ { ++ /* Walk all entries until we find enough slots. */ ++ for (index = 0; index <= tail;) ++ { ++ /* Access page table. */ ++ table = (gctUINT32 *) Mmu->pageTableLogical + index; ++ ++ /* See if all slots are available. */ ++ for (i = 0; i < PageCount; i++, table++) ++ { ++ if (*table != ~0) ++ { ++ /* Start from next slot. */ ++ index += i + 1; ++ break; ++ } ++ } ++ ++ if (i == PageCount) ++ { ++ /* Bail out if we have enough page entries. */ ++ allocated = gcvTRUE; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (!allocated && (status >= 0)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_MMU, ++ "%s(%d): not enough free pages for %u pages.\n", ++ __FUNCTION__, __LINE__, ++ PageCount ++ ); ++ ++ /* Not enough empty slots available. */ ++ status = gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++ if (status >= 0) ++ { ++ /* Build virtual address. */ ++ status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware, ++ index, ++ 0, ++ Address); ++ ++ if (status >= 0) ++ { ++ /* Update current entry into page table. */ ++ Mmu->entry = index + (gctUINT32)PageCount; ++ ++ /* Return pointer to page table. */ ++ *PageTable = (gctUINT32 *) Mmu->pageTableLogical + index; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_MMU, ++ "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n", ++ __FUNCTION__, __LINE__, ++ PageCount, ++ index, ++ *Address, ++ *PageTable ++ ); ++ } ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex)); ++ gcmkFOOTER(); ++ ++ /* Return status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVGMMU_FreePages ++** ++** Free pages inside the page table. ++** ++** INPUT: ++** ++** gckVGMMU Mmu ++** Pointer to an gckVGMMU object. ++** ++** gctPOINTER PageTable ++** Base address of the page table to free. ++** ++** gctSIZE_T PageCount ++** Number of pages to free. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS gckVGMMU_FreePages( ++ IN gckVGMMU Mmu, ++ IN gctPOINTER PageTable, ++ IN gctSIZE_T PageCount ++ ) ++{ ++ gctUINT32 * table; ++ ++ gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x", ++ Mmu, PageTable, PageCount); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); ++ gcmkVERIFY_ARGUMENT(PageCount > 0); ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_MMU, ++ "%s(%d): freeing %u pages at index %u @ %p.\n", ++ __FUNCTION__, __LINE__, ++ PageCount, ++ ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical), ++ PageTable ++ ); ++ ++ /* Convert pointer. */ ++ table = (gctUINT32 *) PageTable; ++ ++ /* Mark the page table entries as available. */ ++ while (PageCount-- > 0) ++ { ++ *table++ = (gctUINT32)~0; ++ } ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckVGMMU_SetPage( ++ IN gckVGMMU Mmu, ++ IN gctUINT32 PageAddress, ++ IN gctUINT32 *PageEntry ++ ) ++{ ++ gcmkHEADER_ARG("Mmu=0x%x", Mmu); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); ++ gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL); ++ gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF)); ++ ++ *PageEntry = PageAddress; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckVGMMU_Flush( ++ IN gckVGMMU Mmu ++ ) ++{ ++ gckVGHARDWARE hardware; ++ ++ gcmkHEADER_ARG("Mmu=0x%x", Mmu); ++ ++ hardware = Mmu->hardware; ++ gcmkVERIFY_OK( ++ gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++#endif /* gcdENABLE_VG */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_os.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_os.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_os.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_os.c 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,8133 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++#include ++#include "gc_hal_kernel_sync.h" ++#endif ++ ++#define _GC_OBJ_ZONE gcvZONE_OS ++ ++#include "gc_hal_kernel_allocator.h" ++ ++#define MEMORY_LOCK(os) \ ++ gcmkVERIFY_OK(gckOS_AcquireMutex( \ ++ (os), \ ++ (os)->memoryLock, \ ++ gcvINFINITE)) ++ ++#define MEMORY_UNLOCK(os) \ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryLock)) ++ ++#define MEMORY_MAP_LOCK(os) \ ++ gcmkVERIFY_OK(gckOS_AcquireMutex( \ ++ (os), \ ++ (os)->memoryMapLock, \ ++ gcvINFINITE)) ++ ++#define MEMORY_MAP_UNLOCK(os) \ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryMapLock)) ++ ++ ++/* Create a new mutex. */ ++static gceSTATUS ++gckOS_CreateNamedMutex( ++ IN gckOS Os, ++ IN struct lock_class_key *key, ++ IN const char *name, ++ OUT gctPOINTER * Mutex ++ ); ++ ++static struct lock_class_key gckOS_key; ++static struct lock_class_key gckOS_MM_key; ++static struct lock_class_key gckOS_Signal_key; ++#if gcdANDROID_NATIVE_FENCE_SYNC ++static struct lock_class_key gckOS_SyncPoint_key; ++#endif ++ ++/******************************************************************************\ ++******************************* Private Functions ****************************** ++\******************************************************************************/ ++static gctINT ++_GetThreadID( ++ void ++ ) ++{ ++ return task_pid_vnr(current); ++} ++ ++static PLINUX_MDL ++_CreateMdl( ++ void ++ ) ++{ ++ PLINUX_MDL mdl; ++ ++ gcmkHEADER(); ++ ++ mdl = (PLINUX_MDL)kzalloc(sizeof(struct _LINUX_MDL), GFP_KERNEL | gcdNOWARN); ++ ++ gcmkFOOTER_ARG("0x%X", mdl); ++ return mdl; ++} ++ ++static gceSTATUS ++_DestroyMdlMap( ++ IN PLINUX_MDL Mdl, ++ IN PLINUX_MDL_MAP MdlMap ++ ); ++ ++static gceSTATUS ++_DestroyMdl( ++ IN PLINUX_MDL Mdl ++ ) ++{ ++ PLINUX_MDL_MAP mdlMap, next; ++ ++ gcmkHEADER_ARG("Mdl=0x%X", Mdl); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Mdl != gcvNULL); ++ ++ mdlMap = Mdl->maps; ++ ++ while (mdlMap != gcvNULL) ++ { ++ next = mdlMap->next; ++ ++ gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap)); ++ ++ mdlMap = next; ++ } ++ ++ kfree(Mdl); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++static PLINUX_MDL_MAP ++_CreateMdlMap( ++ IN PLINUX_MDL Mdl, ++ IN gctINT ProcessID ++ ) ++{ ++ PLINUX_MDL_MAP mdlMap; ++ ++ gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID); ++ ++ mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_KERNEL | gcdNOWARN); ++ if (mdlMap == gcvNULL) ++ { ++ gcmkFOOTER_NO(); ++ return gcvNULL; ++ } ++ ++ mdlMap->pid = ProcessID; ++ mdlMap->vmaAddr = gcvNULL; ++ mdlMap->vma = gcvNULL; ++ mdlMap->count = 0; ++ ++ mdlMap->next = Mdl->maps; ++ Mdl->maps = mdlMap; ++ ++ gcmkFOOTER_ARG("0x%X", mdlMap); ++ return mdlMap; ++} ++ ++static gceSTATUS ++_DestroyMdlMap( ++ IN PLINUX_MDL Mdl, ++ IN PLINUX_MDL_MAP MdlMap ++ ) ++{ ++ PLINUX_MDL_MAP prevMdlMap; ++ ++ gcmkHEADER_ARG("Mdl=0x%X MdlMap=0x%X", Mdl, MdlMap); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL); ++ gcmkASSERT(Mdl->maps != gcvNULL); ++ ++ if (Mdl->maps == MdlMap) ++ { ++ Mdl->maps = MdlMap->next; ++ } ++ else ++ { ++ prevMdlMap = Mdl->maps; ++ ++ while (prevMdlMap->next != MdlMap) ++ { ++ prevMdlMap = prevMdlMap->next; ++ ++ gcmkASSERT(prevMdlMap != gcvNULL); ++ } ++ ++ prevMdlMap->next = MdlMap->next; ++ } ++ ++ kfree(MdlMap); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++extern PLINUX_MDL_MAP ++FindMdlMap( ++ IN PLINUX_MDL Mdl, ++ IN gctINT ProcessID ++ ) ++{ ++ PLINUX_MDL_MAP mdlMap; ++ ++ gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID); ++ if(Mdl == gcvNULL) ++ { ++ gcmkFOOTER_NO(); ++ return gcvNULL; ++ } ++ mdlMap = Mdl->maps; ++ ++ while (mdlMap != gcvNULL) ++ { ++ if (mdlMap->pid == ProcessID) ++ { ++ gcmkFOOTER_ARG("0x%X", mdlMap); ++ return mdlMap; ++ } ++ ++ mdlMap = mdlMap->next; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvNULL; ++} ++ ++/******************************************************************************* ++** Integer Id Management. ++*/ ++gceSTATUS ++_AllocateIntegerId( ++ IN gcsINTEGER_DB_PTR Database, ++ IN gctPOINTER KernelPointer, ++ OUT gctUINT32 *Id ++ ) ++{ ++ int result; ++ gctINT next; ++ ++ idr_preload(GFP_KERNEL | gcdNOWARN); ++ ++ spin_lock(&Database->lock); ++ ++ next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1; ++ ++ result = idr_alloc(&Database->idr, KernelPointer, next, 0, GFP_ATOMIC); ++ ++ /* ID allocated should not be 0. */ ++ gcmkASSERT(result != 0); ++ ++ if (result > 0) ++ { ++ Database->curr = *Id = result; ++ } ++ ++ spin_unlock(&Database->lock); ++ ++ idr_preload_end(); ++ ++ if (result < 0) ++ { ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_QueryIntegerId( ++ IN gcsINTEGER_DB_PTR Database, ++ IN gctUINT32 Id, ++ OUT gctPOINTER * KernelPointer ++ ) ++{ ++ gctPOINTER pointer; ++ ++ spin_lock(&Database->lock); ++ ++ pointer = idr_find(&Database->idr, Id); ++ ++ spin_unlock(&Database->lock); ++ ++ if(pointer) ++ { ++ *KernelPointer = pointer; ++ return gcvSTATUS_OK; ++ } ++ else ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_OS, ++ "%s(%d) Id = %d is not found", ++ __FUNCTION__, __LINE__, Id); ++ ++ return gcvSTATUS_NOT_FOUND; ++ } ++} ++ ++gceSTATUS ++_DestroyIntegerId( ++ IN gcsINTEGER_DB_PTR Database, ++ IN gctUINT32 Id ++ ) ++{ ++ spin_lock(&Database->lock); ++ ++ idr_remove(&Database->idr, Id); ++ ++ spin_unlock(&Database->lock); ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_QueryProcessPageTable( ++ IN gctPOINTER Logical, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gctUINTPTR_T logical = (gctUINTPTR_T)Logical; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ if (!current->mm) ++ { ++ return gcvSTATUS_NOT_FOUND; ++ } ++ ++ pgd = pgd_offset(current->mm, logical); ++ if (pgd_none(*pgd) || pgd_bad(*pgd)) ++ { ++ return gcvSTATUS_NOT_FOUND; ++ } ++ ++ pud = pud_offset(pgd, logical); ++ if (pud_none(*pud) || pud_bad(*pud)) ++ { ++ return gcvSTATUS_NOT_FOUND; ++ } ++ ++ pmd = pmd_offset(pud, logical); ++ if (pmd_none(*pmd) || pmd_bad(*pmd)) ++ { ++ return gcvSTATUS_NOT_FOUND; ++ } ++ ++ pte = pte_offset_map(pmd, logical); ++ if (!pte) ++ { ++ return gcvSTATUS_NOT_FOUND; ++ } ++ ++ if (!pte_present(*pte)) ++ { ++ return gcvSTATUS_NOT_FOUND; ++ } ++ ++ *Address = (pte_pfn(*pte) << PAGE_SHIFT) | (logical & ~PAGE_MASK); ++ ++ return gcvSTATUS_OK; ++} ++ ++gctBOOL ++_AllowAccess( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT32 Address ++ ) ++{ ++ gctUINT32 data; ++ ++ /* Check external clock state. */ ++ if (Os->clockStates[Core] == gcvFALSE) ++ { ++ gcmkPRINT("[galcore]: %s(%d) External clock off", __FUNCTION__, __LINE__); ++ return gcvFALSE; ++ } ++ ++ /* Check internal clock state. */ ++ if (Address == 0) ++ { ++ return gcvTRUE; ++ } ++ ++ data = readl((gctUINT8 *)Os->device->registerBases[Core] + 0x0); ++ ++ if ((data & 0x3) == 0x3) ++ { ++ gcmkPRINT("[galcore]: %s(%d) Internal clock off", __FUNCTION__, __LINE__); ++ return gcvFALSE; ++ } ++ ++ return gcvTRUE; ++} ++ ++static gceSTATUS ++_ShrinkMemory( ++ IN gckOS Os ++ ) ++{ ++ gcsPLATFORM * platform; ++ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ platform = Os->device->platform; ++ ++ if (platform && platform->ops->shrinkMemory) ++ { ++ platform->ops->shrinkMemory(platform); ++ } ++ else ++ { ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_NOT_SUPPORTED; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_Construct ++** ++** Construct a new gckOS object. ++** ++** INPUT: ++** ++** gctPOINTER Context ++** Pointer to the gckGALDEVICE class. ++** ++** OUTPUT: ++** ++** gckOS * Os ++** Pointer to a variable that will hold the pointer to the gckOS object. ++*/ ++gceSTATUS ++gckOS_Construct( ++ IN gctPOINTER Context, ++ OUT gckOS * Os ++ ) ++{ ++ gckOS os; ++ gceSTATUS status; ++ gctINT i; ++ ++ gcmkHEADER_ARG("Context=0x%X", Context); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Os != gcvNULL); ++ ++ /* Allocate the gckOS object. */ ++ os = (gckOS) kmalloc(gcmSIZEOF(struct _gckOS), GFP_KERNEL | gcdNOWARN); ++ ++ if (os == gcvNULL) ++ { ++ /* Out of memory. */ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ /* Zero the memory. */ ++ gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS)); ++ ++ /* Initialize the gckOS object. */ ++ os->object.type = gcvOBJ_OS; ++ ++ /* Set device device. */ ++ os->device = Context; ++ ++ /* Set allocateCount to 0, gckOS_Allocate has not been used yet. */ ++ atomic_set(&os->allocateCount, 0); ++ ++ /* Initialize the memory lock. */ ++ gcmkONERROR(gckOS_CreateNamedMutex(os, &gckOS_key, "memoryLock", &os->memoryLock)); ++ gcmkONERROR(gckOS_CreateNamedMutex(os, &gckOS_MM_key, "memoryMapLock", &os->memoryMapLock)); ++ ++ /* Create debug lock mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(os, &os->debugLock)); ++ ++ os->mdlHead = os->mdlTail = gcvNULL; ++ ++ /* Get the kernel process ID. */ ++ gcmkONERROR(gckOS_GetProcessID(&os->kernelProcessID)); ++ ++ /* ++ * Initialize the signal manager. ++ */ ++ ++ /* Initialize mutex. */ ++ gcmkONERROR(gckOS_CreateNamedMutex(os, &gckOS_Signal_key, "signalMutex", &os->signalMutex)); ++ ++ /* Initialize signal id database lock. */ ++ spin_lock_init(&os->signalDB.lock); ++ ++ /* Initialize signal id database. */ ++ idr_init(&os->signalDB.idr); ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ /* ++ * Initialize the sync point manager. ++ */ ++ ++ /* Initialize mutex. */ ++ gcmkONERROR(gckOS_CreateNamedMutex(os, &gckOS_SyncPoint_key, "syncPointMutex", &os->syncPointMutex)); ++ ++ /* Initialize sync point id database lock. */ ++ spin_lock_init(&os->syncPointDB.lock); ++ ++ /* Initialize sync point id database. */ ++ idr_init(&os->syncPointDB.idr); ++#endif ++ ++ /* Create a workqueue for os timer. */ ++ os->workqueue = create_singlethread_workqueue("galcore workqueue"); ++ ++ if (os->workqueue == gcvNULL) ++ { ++ /* Out of memory. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ os->paddingPage = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN); ++ if (os->paddingPage == gcvNULL) ++ { ++ /* Out of memory. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ else ++ { ++ SetPageReserved(os->paddingPage); ++ } ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ mutex_init(&os->registerAccessLocks[i]); ++ } ++ ++ gckOS_ImportAllocators(os); ++ ++#ifdef CONFIG_IOMMU_SUPPORT ++ if (((gckGALDEVICE)(os->device))->mmu == gcvFALSE) ++ { ++ /* Only use IOMMU when internal MMU is not enabled. */ ++ status = gckIOMMU_Construct(os, &os->iommu); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): Fail to setup IOMMU", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ } ++#endif ++ ++ /* Return pointer to the gckOS object. */ ++ *Os = os; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Os=0x%X", *Os); ++ return gcvSTATUS_OK; ++ ++OnError: ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ if (os->syncPointMutex != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DeleteMutex(os, os->syncPointMutex)); ++ } ++#endif ++ ++ if (os->signalMutex != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DeleteMutex(os, os->signalMutex)); ++ } ++ ++ if (os->memoryMapLock != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DeleteMutex(os, os->memoryMapLock)); ++ } ++ ++ if (os->memoryLock != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DeleteMutex(os, os->memoryLock)); ++ } ++ ++ if (os->debugLock != gcvNULL) ++ { ++ gcmkVERIFY_OK( ++ gckOS_DeleteMutex(os, os->debugLock)); ++ } ++ ++ if (os->workqueue != gcvNULL) ++ { ++ destroy_workqueue(os->workqueue); ++ } ++ ++ kfree(os); ++ ++ /* Return the error. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_Destroy ++** ++** Destroy an gckOS object. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object that needs to be destroyed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_Destroy( ++ IN gckOS Os ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ if (Os->paddingPage != gcvNULL) ++ { ++ ClearPageReserved(Os->paddingPage); ++ __free_page(Os->paddingPage); ++ Os->paddingPage = gcvNULL; ++ } ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ /* ++ * Destroy the sync point manager. ++ */ ++ ++ /* Destroy the mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->syncPointMutex)); ++#endif ++ ++ /* ++ * Destroy the signal manager. ++ */ ++ ++ /* Destroy the mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->signalMutex)); ++ ++ /* Destroy the memory lock. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryMapLock)); ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryLock)); ++ ++ /* Destroy debug lock mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->debugLock)); ++ ++ /* Wait for all works done. */ ++ flush_workqueue(Os->workqueue); ++ ++ /* Destory work queue. */ ++ destroy_workqueue(Os->workqueue); ++ ++ gckOS_FreeAllocators(Os); ++ ++#ifdef CONFIG_IOMMU_SUPPORT ++ if (Os->iommu) ++ { ++ gckIOMMU_Destory(Os, Os->iommu); ++ } ++#endif ++ ++ /* Flush the debug cache. */ ++ gcmkDEBUGFLUSH(~0U); ++ ++ /* Mark the gckOS object as unknown. */ ++ Os->object.type = gcvOBJ_UNKNOWN; ++ ++ ++ /* Free the gckOS object. */ ++ kfree(Os); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_CreateKernelVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical, ++ OUT gctSIZE_T * PageCount ++ ) ++{ ++ gceSTATUS status; ++ PLINUX_MDL mdl = (PLINUX_MDL)Physical; ++ gckALLOCATOR allocator = mdl->allocator; ++ ++ gcmkHEADER(); ++ ++ *PageCount = mdl->numPages; ++ ++ gcmkONERROR(allocator->ops->MapKernel(allocator, mdl, Logical)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_DestroyKernelVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ) ++{ ++ PLINUX_MDL mdl = (PLINUX_MDL)Physical; ++ gckALLOCATOR allocator = mdl->allocator; ++ ++ gcmkHEADER(); ++ ++ allocator->ops->UnmapKernel(allocator, mdl, Logical); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_CreateUserVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical, ++ OUT gctSIZE_T * PageCount ++ ) ++{ ++ return gckOS_LockPages(Os, Physical, Bytes, gcvFALSE, Logical, PageCount); ++} ++ ++gceSTATUS ++gckOS_DestroyUserVirtualMapping( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ) ++{ ++ return gckOS_UnlockPages(Os, Physical, Bytes, Logical); ++} ++ ++/******************************************************************************* ++** ++** gckOS_Allocate ++** ++** Allocate memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIZE_T Bytes ++** Number of bytes to allocate. ++** ++** OUTPUT: ++** ++** gctPOINTER * Memory ++** Pointer to a variable that will hold the allocated memory location. ++*/ ++gceSTATUS ++gckOS_Allocate( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Memory ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL); ++ ++ gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Memory=0x%X", *Memory); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_Free ++** ++** Free allocated memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Memory ++** Pointer to memory allocation to free. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_Free( ++ IN gckOS Os, ++ IN gctPOINTER Memory ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Memory=0x%X", Os, Memory); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL); ++ ++ gcmkONERROR(gckOS_FreeMemory(Os, Memory)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AllocateMemory ++** ++** Allocate memory wrapper. ++** ++** INPUT: ++** ++** gctSIZE_T Bytes ++** Number of bytes to allocate. ++** ++** OUTPUT: ++** ++** gctPOINTER * Memory ++** Pointer to a variable that will hold the allocated memory location. ++*/ ++gceSTATUS ++gckOS_AllocateMemory( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Memory ++ ) ++{ ++ gctPOINTER memory; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL); ++ ++ if (Bytes > PAGE_SIZE) ++ { ++ memory = (gctPOINTER) vmalloc(Bytes); ++ } ++ else ++ { ++ memory = (gctPOINTER) kmalloc(Bytes, GFP_KERNEL | gcdNOWARN); ++ } ++ ++ if (memory == gcvNULL) ++ { ++ /* Out of memory. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Increase count. */ ++ atomic_inc(&Os->allocateCount); ++ ++ /* Return pointer to the memory allocation. */ ++ *Memory = memory; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Memory=0x%X", *Memory); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_FreeMemory ++** ++** Free allocated memory wrapper. ++** ++** INPUT: ++** ++** gctPOINTER Memory ++** Pointer to memory allocation to free. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_FreeMemory( ++ IN gckOS Os, ++ IN gctPOINTER Memory ++ ) ++{ ++ gcmkHEADER_ARG("Memory=0x%X", Memory); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL); ++ ++ /* Free the memory from the OS pool. */ ++ if (is_vmalloc_addr(Memory)) ++ { ++ vfree(Memory); ++ } ++ else ++ { ++ kfree(Memory); ++ } ++ ++ /* Decrease count. */ ++ atomic_dec(&Os->allocateCount); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_MapMemory ++** ++** Map physical memory into the current process. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Start of physical address memory. ++** ++** gctSIZE_T Bytes ++** Number of bytes to map. ++** ++** OUTPUT: ++** ++** gctPOINTER * Memory ++** Pointer to a variable that will hold the logical address of the ++** mapped memory. ++*/ ++gceSTATUS ++gckOS_MapMemory( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ PLINUX_MDL_MAP mdlMap; ++ PLINUX_MDL mdl = (PLINUX_MDL)Physical; ++ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != 0); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ MEMORY_LOCK(Os); ++ ++ mdlMap = FindMdlMap(mdl, _GetProcessID()); ++ ++ if (mdlMap == gcvNULL) ++ { ++ mdlMap = _CreateMdlMap(mdl, _GetProcessID()); ++ ++ if (mdlMap == gcvNULL) ++ { ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ } ++ ++ if (mdlMap->vmaAddr == gcvNULL) ++ { ++ mdlMap->vmaAddr = (char *)vm_mmap(gcvNULL, ++ 0L, ++ mdl->numPages * PAGE_SIZE, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED, ++ 0); ++ ++ if (IS_ERR(mdlMap->vmaAddr)) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): do_mmap_pgoff error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): mdl->numPages: %d mdl->vmaAddr: 0x%X", ++ __FUNCTION__, __LINE__, ++ mdl->numPages, ++ mdlMap->vmaAddr ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ down_write(¤t->mm->mmap_sem); ++ ++ mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); ++ ++ if (!mdlMap->vma) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): find_vma error.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++#ifndef NO_DMA_COHERENT ++ if (dma_mmap_writecombine(Os->device->dev, ++ mdlMap->vma, ++ mdl->addr, ++ mdl->dmaHandle, ++ mdl->numPages * PAGE_SIZE) < 0) ++ { ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): dma_mmap_coherent error.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++#else ++#if !gcdPAGED_MEMORY_CACHEABLE ++ mdlMap->vma->vm_page_prot = gcmkPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot); ++ mdlMap->vma->vm_flags |= gcdVM_FLAGS; ++# endif ++ mdlMap->vma->vm_pgoff = 0; ++ ++ if (remap_pfn_range(mdlMap->vma, ++ mdlMap->vma->vm_start, ++ mdl->dmaHandle >> PAGE_SHIFT, ++ mdl->numPages*PAGE_SIZE, ++ mdlMap->vma->vm_page_prot) < 0) ++ { ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): remap_pfn_range error.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++#endif ++ ++ up_write(¤t->mm->mmap_sem); ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ *Logical = mdlMap->vmaAddr; ++ ++ gcmkFOOTER_ARG("*Logical=0x%X", *Logical); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UnmapMemory ++** ++** Unmap physical memory out of the current process. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Start of physical address memory. ++** ++** gctSIZE_T Bytes ++** Number of bytes to unmap. ++** ++** gctPOINTER Memory ++** Pointer to a previously mapped memory region. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UnmapMemory( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X", ++ Os, Physical, Bytes, Logical); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != 0); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ gckOS_UnmapMemoryEx(Os, Physical, Bytes, Logical, _GetProcessID()); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++ ++/******************************************************************************* ++** ++** gckOS_UnmapMemoryEx ++** ++** Unmap physical memory in the specified process. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Start of physical address memory. ++** ++** gctSIZE_T Bytes ++** Number of bytes to unmap. ++** ++** gctPOINTER Memory ++** Pointer to a previously mapped memory region. ++** ++** gctUINT32 PID ++** Pid of the process that opened the device and mapped this memory. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UnmapMemoryEx( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical, ++ IN gctUINT32 PID ++ ) ++{ ++ PLINUX_MDL_MAP mdlMap; ++ PLINUX_MDL mdl = (PLINUX_MDL)Physical; ++ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X PID=%d", ++ Os, Physical, Bytes, Logical, PID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != 0); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(PID != 0); ++ ++ MEMORY_LOCK(Os); ++ ++ if (Logical) ++ { ++ mdlMap = FindMdlMap(mdl, PID); ++ ++ if (mdlMap == gcvNULL || mdlMap->vmaAddr == gcvNULL) ++ { ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); ++ return gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++ _UnmapUserLogical(mdlMap->vmaAddr, mdl->numPages * PAGE_SIZE); ++ ++ gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UnmapUserLogical ++** ++** Unmap user logical memory out of physical memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Start of physical address memory. ++** ++** gctSIZE_T Bytes ++** Number of bytes to unmap. ++** ++** gctPOINTER Memory ++** Pointer to a previously mapped memory region. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UnmapUserLogical( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X", ++ Os, Physical, Bytes, Logical); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != 0); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ gckOS_UnmapMemory(Os, Physical, Bytes, Logical); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++} ++ ++/******************************************************************************* ++** ++** gckOS_AllocateNonPagedMemory ++** ++** Allocate a number of pages from non-paged memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctBOOL InUserSpace ++** gcvTRUE if the pages need to be mapped into user space. ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that holds the number of bytes to allocate. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that hold the number of bytes allocated. ++** ++** gctPHYS_ADDR * Physical ++** Pointer to a variable that will hold the physical address of the ++** allocation. ++** ++** gctPOINTER * Logical ++** Pointer to a variable that will hold the logical address of the ++** allocation. ++*/ ++gceSTATUS ++gckOS_AllocateNonPagedMemory( ++ IN gckOS Os, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ gctSIZE_T bytes; ++ gctINT numPages; ++ PLINUX_MDL mdl = gcvNULL; ++ PLINUX_MDL_MAP mdlMap = gcvNULL; ++ gctSTRING addr; ++ gckKERNEL kernel; ++#ifdef NO_DMA_COHERENT ++ struct page * page; ++ long size, order; ++ gctPOINTER vaddr; ++#endif ++ gctBOOL locked = gcvFALSE; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu", ++ Os, InUserSpace, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes != gcvNULL); ++ gcmkVERIFY_ARGUMENT(*Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ /* Align number of bytes to page size. */ ++ bytes = gcmALIGN(*Bytes, PAGE_SIZE); ++ ++ /* Get total number of pages.. */ ++ numPages = GetPageCount(bytes, 0); ++ ++ /* Allocate mdl+vector structure */ ++ mdl = _CreateMdl(); ++ if (mdl == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ mdl->pagedMem = 0; ++ mdl->numPages = numPages; ++ ++ MEMORY_LOCK(Os); ++ locked = gcvTRUE; ++ ++#ifndef NO_DMA_COHERENT ++#ifdef CONFIG_ARM64 ++ addr = dma_alloc_coherent(Os->device->dev, ++#else ++ addr = dma_alloc_writecombine(Os->device->dev, ++#endif ++ mdl->numPages * PAGE_SIZE, ++ &mdl->dmaHandle, ++ GFP_KERNEL | gcdNOWARN); ++#else ++ size = mdl->numPages * PAGE_SIZE; ++ order = get_order(size); ++ ++ page = alloc_pages(GFP_KERNEL | gcdNOWARN, order); ++ ++ if (page == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ vaddr = (gctPOINTER)page_address(page); ++ mdl->contiguous = gcvTRUE; ++ mdl->u.contiguousPages = page; ++ addr = _CreateKernelVirtualMapping(mdl); ++ mdl->dmaHandle = virt_to_phys(vaddr); ++ mdl->kaddr = vaddr; ++ ++ /* Trigger a page fault. */ ++ memset(addr, 0, numPages * PAGE_SIZE); ++ ++#if !defined(CONFIG_PPC) ++ /* Cache invalidate. */ ++ dma_sync_single_for_device( ++ Os->device->dev, ++ page_to_phys(page), ++ bytes, ++ DMA_FROM_DEVICE); ++#endif ++ ++ while (size > 0) ++ { ++ SetPageReserved(virt_to_page(vaddr)); ++ ++ vaddr += PAGE_SIZE; ++ size -= PAGE_SIZE; ++ } ++#endif ++ ++ if (addr == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ kernel = Os->device->kernels[gcvCORE_MAJOR] != gcvNULL ? ++ Os->device->kernels[gcvCORE_MAJOR] : Os->device->kernels[gcvCORE_2D]; ++ if (((Os->device->baseAddress & 0x80000000) != (mdl->dmaHandle & 0x80000000)) && ++ kernel->hardware->mmuVersion == 0) ++ { ++ mdl->dmaHandle = (mdl->dmaHandle & ~0x80000000) ++ | (Os->device->baseAddress & 0x80000000); ++ } ++ ++ mdl->addr = addr; ++ ++ if (InUserSpace) ++ { ++ mdlMap = _CreateMdlMap(mdl, _GetProcessID()); ++ ++ if (mdlMap == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Only after mmap this will be valid. */ ++ ++ /* We need to map this to user space. */ ++ mdlMap->vmaAddr = (gctSTRING) vm_mmap(gcvNULL, ++ 0L, ++ mdl->numPages * PAGE_SIZE, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED, ++ 0); ++ ++ if (IS_ERR(mdlMap->vmaAddr)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d): do_mmap_pgoff error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ down_write(¤t->mm->mmap_sem); ++ ++ mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); ++ ++ if (mdlMap->vma == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d): find_vma error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++#ifndef NO_DMA_COHERENT ++ if (dma_mmap_coherent(Os->device->dev, ++ mdlMap->vma, ++ mdl->addr, ++ mdl->dmaHandle, ++ mdl->numPages * PAGE_SIZE) < 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d): dma_mmap_coherent error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++#else ++ mdlMap->vma->vm_page_prot = gcmkNONPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot); ++ mdlMap->vma->vm_flags |= gcdVM_FLAGS; ++ mdlMap->vma->vm_pgoff = 0; ++ ++ if (remap_pfn_range(mdlMap->vma, ++ mdlMap->vma->vm_start, ++ mdl->dmaHandle >> PAGE_SHIFT, ++ mdl->numPages * PAGE_SIZE, ++ mdlMap->vma->vm_page_prot)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_WARNING, gcvZONE_OS, ++ "%s(%d): remap_pfn_range error", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++#endif /* NO_DMA_COHERENT */ ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ *Logical = mdlMap->vmaAddr; ++ } ++ else ++ { ++ *Logical = (gctPOINTER)mdl->addr; ++ } ++ ++ /* ++ * Add this to a global list. ++ * Will be used by get physical address ++ * and mapuser pointer functions. ++ */ ++ ++ if (!Os->mdlHead) ++ { ++ /* Initialize the queue. */ ++ Os->mdlHead = Os->mdlTail = mdl; ++ } ++ else ++ { ++ /* Add to the tail. */ ++ mdl->prev = Os->mdlTail; ++ Os->mdlTail->next = mdl; ++ Os->mdlTail = mdl; ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ /* Return allocated memory. */ ++ *Bytes = bytes; ++ *Physical = (gctPHYS_ADDR) mdl; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X", ++ *Bytes, *Physical, *Logical); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (mdlMap != gcvNULL) ++ { ++ /* Free LINUX_MDL_MAP. */ ++ gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); ++ } ++ ++ if (mdl != gcvNULL) ++ { ++ /* Free LINUX_MDL. */ ++ gcmkVERIFY_OK(_DestroyMdl(mdl)); ++ } ++ *Physical = gcvNULL; ++ *Bytes = 0; ++ ++ if (locked) ++ { ++ /* Unlock memory. */ ++ MEMORY_UNLOCK(Os); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_FreeNonPagedMemory ++** ++** Free previously allocated and mapped pages from non-paged memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIZE_T Bytes ++** Number of bytes allocated. ++** ++** gctPHYS_ADDR Physical ++** Physical address of the allocated memory. ++** ++** gctPOINTER Logical ++** Logical address of the allocated memory. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS gckOS_FreeNonPagedMemory( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical ++ ) ++{ ++ PLINUX_MDL mdl; ++ PLINUX_MDL_MAP mdlMap; ++#ifdef NO_DMA_COHERENT ++ unsigned size; ++ gctPOINTER vaddr; ++#endif /* NO_DMA_COHERENT */ ++ ++ gcmkHEADER_ARG("Os=0x%X Bytes=%lu Physical=0x%X Logical=0x%X", ++ Os, Bytes, Physical, Logical); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Physical != 0); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ /* Convert physical address into a pointer to a MDL. */ ++ mdl = (PLINUX_MDL) Physical; ++ ++ MEMORY_LOCK(Os); ++ ++#ifndef NO_DMA_COHERENT ++#ifdef CONFIG_ARM64 ++ dma_free_coherent(Os->device->dev, ++#else ++ dma_free_writecombine(Os->device->dev, ++#endif ++ mdl->numPages * PAGE_SIZE, ++ mdl->addr, ++ mdl->dmaHandle); ++#else ++ size = mdl->numPages * PAGE_SIZE; ++ vaddr = mdl->kaddr; ++ ++ while (size > 0) ++ { ++ ClearPageReserved(virt_to_page(vaddr)); ++ ++ vaddr += PAGE_SIZE; ++ size -= PAGE_SIZE; ++ } ++ ++ free_pages((unsigned long)mdl->kaddr, get_order(mdl->numPages * PAGE_SIZE)); ++ ++ _DestoryKernelVirtualMapping(mdl->addr); ++#endif /* NO_DMA_COHERENT */ ++ ++ mdlMap = mdl->maps; ++ ++ while (mdlMap != gcvNULL) ++ { ++ /* No mapped memory exists when free nonpaged memory */ ++ gcmkASSERT(mdlMap->vmaAddr == gcvNULL); ++ ++ mdlMap = mdlMap->next; ++ } ++ ++ /* Remove the node from global list.. */ ++ if (mdl == Os->mdlHead) ++ { ++ if ((Os->mdlHead = mdl->next) == gcvNULL) ++ { ++ Os->mdlTail = gcvNULL; ++ } ++ } ++ else ++ { ++ mdl->prev->next = mdl->next; ++ if (mdl == Os->mdlTail) ++ { ++ Os->mdlTail = mdl->prev; ++ } ++ else ++ { ++ mdl->next->prev = mdl->prev; ++ } ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ gcmkVERIFY_OK(_DestroyMdl(mdl)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_ReadRegister ++** ++** Read data from a register. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 Address ++** Address of register. ++** ++** OUTPUT: ++** ++** gctUINT32 * Data ++** Pointer to a variable that receives the data read from the register. ++*/ ++gceSTATUS ++gckOS_ReadRegister( ++ IN gckOS Os, ++ IN gctUINT32 Address, ++ OUT gctUINT32 * Data ++ ) ++{ ++ return gckOS_ReadRegisterEx(Os, gcvCORE_MAJOR, Address, Data); ++} ++ ++gceSTATUS ++gckOS_ReadRegisterEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT32 Address, ++ OUT gctUINT32 * Data ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X", Os, Core, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Address < Os->device->requestedRegisterMemSizes[Core]); ++ gcmkVERIFY_ARGUMENT(Data != gcvNULL); ++ ++ if (!in_interrupt()) ++ { ++ mutex_lock(&Os->registerAccessLocks[Core]); ++ } ++ ++ BUG_ON(!_AllowAccess(Os, Core, Address)); ++ ++ *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address); ++ ++ if (!in_interrupt()) ++ { ++ mutex_unlock(&Os->registerAccessLocks[Core]); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Data=0x%08x", *Data); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_WriteRegister ++** ++** Write data to a register. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 Address ++** Address of register. ++** ++** gctUINT32 Data ++** Data for register. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_WriteRegister( ++ IN gckOS Os, ++ IN gctUINT32 Address, ++ IN gctUINT32 Data ++ ) ++{ ++ return gckOS_WriteRegisterEx(Os, gcvCORE_MAJOR, Address, Data); ++} ++ ++gceSTATUS ++gckOS_WriteRegisterEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT32 Address, ++ IN gctUINT32 Data ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X Data=0x%08x", Os, Core, Address, Data); ++ ++ gcmkVERIFY_ARGUMENT(Address < Os->device->requestedRegisterMemSizes[Core]); ++ ++ if (!in_interrupt()) ++ { ++ mutex_lock(&Os->registerAccessLocks[Core]); ++ } ++ ++ BUG_ON(!_AllowAccess(Os, Core, Address)); ++ ++ writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address); ++ ++ if (!in_interrupt()) ++ { ++ mutex_unlock(&Os->registerAccessLocks[Core]); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetPageSize ++** ++** Get the system's page size. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** OUTPUT: ++** ++** gctSIZE_T * PageSize ++** Pointer to a variable that will receive the system's page size. ++*/ ++gceSTATUS gckOS_GetPageSize( ++ IN gckOS Os, ++ OUT gctSIZE_T * PageSize ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(PageSize != gcvNULL); ++ ++ /* Return the page size. */ ++ *PageSize = (gctSIZE_T) PAGE_SIZE; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*PageSize", *PageSize); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetPhysicalAddress ++** ++** Get the physical system address of a corresponding virtual address. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Logical ++** Logical address. ++** ++** OUTPUT: ++** ++** gctUINT32 * Address ++** Poinetr to a variable that receives the 32-bit physical adress. ++*/ ++gceSTATUS ++gckOS_GetPhysicalAddress( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ OUT gctUINT32 * Address ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 processID; ++ ++ gcmkHEADER_ARG("Os=0x%X Logical=0x%X", Os, Logical); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ /* Query page table of current process first. */ ++ status = _QueryProcessPageTable(Logical, Address); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Get current process ID. */ ++ processID = _GetProcessID(); ++ ++ /* Route through other function. */ ++ gcmkONERROR( ++ gckOS_GetPhysicalAddressProcess(Os, Logical, processID, Address)); ++ } ++ ++ gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, *Address, Address)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Address=0x%08x", *Address); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UserLogicalToPhysical ++** ++** Get the physical system address of a corresponding user virtual address. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Logical ++** Logical address. ++** ++** OUTPUT: ++** ++** gctUINT32 * Address ++** Pointer to a variable that receives the 32-bit physical address. ++*/ ++gceSTATUS gckOS_UserLogicalToPhysical( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ OUT gctUINT32 * Address ++ ) ++{ ++ return gckOS_GetPhysicalAddress(Os, Logical, Address); ++} ++ ++gceSTATUS ++_ConvertLogical2Physical( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ IN gctUINT32 ProcessID, ++ IN PLINUX_MDL Mdl, ++ OUT gctUINT32_PTR Physical ++ ) ++{ ++ gctINT8_PTR base, vBase; ++ gctUINT32 offset; ++ PLINUX_MDL_MAP map; ++ gcsUSER_MAPPING_PTR userMap; ++ ++ base = (Mdl == gcvNULL) ? gcvNULL : (gctINT8_PTR) Mdl->addr; ++ ++ /* Check for the logical address match. */ ++ if ((base != gcvNULL) ++ && ((gctINT8_PTR) Logical >= base) ++ && ((gctINT8_PTR) Logical < base + Mdl->numPages * PAGE_SIZE) ++ ) ++ { ++ offset = (gctINT8_PTR) Logical - base; ++ ++ if (Mdl->dmaHandle != 0) ++ { ++ /* The memory was from coherent area. */ ++ *Physical = (gctUINT32) Mdl->dmaHandle + offset; ++ } ++ else if (Mdl->pagedMem && !Mdl->contiguous) ++ { ++ /* paged memory is not mapped to kernel space. */ ++ return gcvSTATUS_INVALID_ADDRESS; ++ } ++ else ++ { ++ *Physical = gcmPTR2INT32(virt_to_phys(base)) + offset; ++ } ++ ++ return gcvSTATUS_OK; ++ } ++ ++ /* Walk user maps. */ ++ for (userMap = Os->userMap; userMap != gcvNULL; userMap = userMap->next) ++ { ++ if (((gctINT8_PTR) Logical >= userMap->start) ++ && ((gctINT8_PTR) Logical < userMap->end) ++ ) ++ { ++ *Physical = userMap->physical ++ + (gctUINT32) ((gctINT8_PTR) Logical - userMap->start); ++ ++ return gcvSTATUS_OK; ++ } ++ } ++ ++ if (ProcessID != Os->kernelProcessID) ++ { ++ map = FindMdlMap(Mdl, (gctINT) ProcessID); ++ vBase = (map == gcvNULL) ? gcvNULL : (gctINT8_PTR) map->vmaAddr; ++ ++ /* Is the given address within that range. */ ++ if ((vBase != gcvNULL) ++ && ((gctINT8_PTR) Logical >= vBase) ++ && ((gctINT8_PTR) Logical < vBase + Mdl->numPages * PAGE_SIZE) ++ ) ++ { ++ offset = (gctINT8_PTR) Logical - vBase; ++ ++ if (Mdl->dmaHandle != 0) ++ { ++ /* The memory was from coherent area. */ ++ *Physical = (gctUINT32) Mdl->dmaHandle + offset; ++ } ++ else if (Mdl->pagedMem && !Mdl->contiguous) ++ { ++ *Physical = _NonContiguousToPhys(Mdl->u.nonContiguousPages, offset/PAGE_SIZE); ++ } ++ else ++ { ++ *Physical = page_to_phys(Mdl->u.contiguousPages) + offset; ++ } ++ ++ return gcvSTATUS_OK; ++ } ++ } ++ ++ /* Address not yet found. */ ++ return gcvSTATUS_INVALID_ADDRESS; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetPhysicalAddressProcess ++** ++** Get the physical system address of a corresponding virtual address for a ++** given process. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to gckOS object. ++** ++** gctPOINTER Logical ++** Logical address. ++** ++** gctUINT32 ProcessID ++** Process ID. ++** ++** OUTPUT: ++** ++** gctUINT32 * Address ++** Poinetr to a variable that receives the 32-bit physical adress. ++*/ ++gceSTATUS ++gckOS_GetPhysicalAddressProcess( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ IN gctUINT32 ProcessID, ++ OUT gctUINT32 * Address ++ ) ++{ ++ PLINUX_MDL mdl; ++ gctINT8_PTR base; ++ gckALLOCATOR allocator = gcvNULL; ++ gceSTATUS status = gcvSTATUS_INVALID_ADDRESS; ++ ++ gcmkHEADER_ARG("Os=0x%X Logical=0x%X ProcessID=%d", Os, Logical, ProcessID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ MEMORY_LOCK(Os); ++ ++ /* First try the contiguous memory pool. */ ++ if (Os->device->contiguousMapped) ++ { ++ base = (gctINT8_PTR) Os->device->contiguousBase; ++ ++ if (((gctINT8_PTR) Logical >= base) ++ && ((gctINT8_PTR) Logical < base + Os->device->contiguousSize) ++ ) ++ { ++ /* Convert logical address into physical. */ ++ *Address = Os->device->contiguousVidMem->baseAddress ++ + (gctINT8_PTR) Logical - base; ++ status = gcvSTATUS_OK; ++ } ++ } ++ else ++ { ++ /* Try the contiguous memory pool. */ ++ mdl = (PLINUX_MDL) Os->device->contiguousPhysical; ++ status = _ConvertLogical2Physical(Os, ++ Logical, ++ ProcessID, ++ mdl, ++ Address); ++ } ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Walk all MDLs. */ ++ for (mdl = Os->mdlHead; mdl != gcvNULL; mdl = mdl->next) ++ { ++ /* Try this MDL. */ ++ allocator = mdl->allocator; ++ ++ if (allocator) ++ { ++ status = allocator->ops->LogicalToPhysical( ++ allocator, ++ mdl, ++ Logical, ++ ProcessID, ++ Address ++ ); ++ } ++ else ++ { ++ status = _ConvertLogical2Physical(Os, ++ Logical, ++ ProcessID, ++ mdl, ++ Address); ++ } ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ break; ++ } ++ } ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ gcmkONERROR(status); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Address=0x%08x", *Address); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_MapPhysical ++** ++** Map a physical address into kernel space. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 Physical ++** Physical address of the memory to map. ++** ++** gctSIZE_T Bytes ++** Number of bytes to map. ++** ++** OUTPUT: ++** ++** gctPOINTER * Logical ++** Pointer to a variable that receives the base address of the mapped ++** memory. ++*/ ++gceSTATUS ++gckOS_MapPhysical( ++ IN gckOS Os, ++ IN gctUINT32 Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ gctPOINTER logical; ++ PLINUX_MDL mdl; ++ gctUINT32 physical = Physical; ++ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ MEMORY_LOCK(Os); ++ ++ /* Go through our mapping to see if we know this physical address already. */ ++ mdl = Os->mdlHead; ++ ++ while (mdl != gcvNULL) ++ { ++ if (mdl->dmaHandle != 0) ++ { ++ if ((physical >= mdl->dmaHandle) ++ && (physical < mdl->dmaHandle + mdl->numPages * PAGE_SIZE) ++ ) ++ { ++ *Logical = mdl->addr + (physical - mdl->dmaHandle); ++ break; ++ } ++ } ++ ++ mdl = mdl->next; ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ if (mdl == gcvNULL) ++ { ++ struct page * page = pfn_to_page(physical >> PAGE_SHIFT); ++ ++ if (pfn_valid(page_to_pfn(page))) ++ { ++ gctUINT32 offset = physical & ~PAGE_MASK; ++ struct page ** pages; ++ gctUINT numPages; ++ gctINT i; ++ ++ numPages = GetPageCount(PAGE_ALIGN(offset + Bytes), 0); ++ ++ pages = kmalloc(sizeof(struct page *) * numPages, GFP_KERNEL | gcdNOWARN); ++ ++ if (!pages) ++ { ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ for (i = 0; i < numPages; i++) ++ { ++ pages[i] = nth_page(page, i); ++ } ++ ++ logical = vmap(pages, numPages, 0, gcmkNONPAGED_MEMROY_PROT(PAGE_KERNEL)); ++ ++ kfree(pages); ++ ++ if (logical == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): Failed to vmap", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Out of resources. */ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++ logical += offset; ++ } ++ else ++ { ++ /* Map memory as cached memory. */ ++ request_mem_region(physical, Bytes, "MapRegion"); ++ logical = (gctPOINTER) ioremap_nocache(physical, Bytes); ++ ++ if (logical == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): Failed to ioremap", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Out of resources. */ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ } ++ ++ /* Return pointer to mapped memory. */ ++ *Logical = logical; ++ } ++ ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Logical=0x%X", *Logical); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UnmapPhysical ++** ++** Unmap a previously mapped memory region from kernel memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Logical ++** Pointer to the base address of the memory to unmap. ++** ++** gctSIZE_T Bytes ++** Number of bytes to unmap. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UnmapPhysical( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ PLINUX_MDL mdl; ++ ++ gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ MEMORY_LOCK(Os); ++ ++ mdl = Os->mdlHead; ++ ++ while (mdl != gcvNULL) ++ { ++ if (mdl->addr != gcvNULL) ++ { ++ if (Logical >= (gctPOINTER)mdl->addr ++ && Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->numPages * PAGE_SIZE)) ++ { ++ break; ++ } ++ } ++ ++ mdl = mdl->next; ++ } ++ ++ if (mdl == gcvNULL) ++ { ++ /* Unmap the memory. */ ++ vunmap((void *)((unsigned long)Logical & PAGE_MASK)); ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_CreateMutex ++** ++** Create a new mutex. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** OUTPUT: ++** ++** gctPOINTER * Mutex ++** Pointer to a variable that will hold a pointer to the mutex. ++*/ ++gceSTATUS ++gckOS_CreateMutex( ++ IN gckOS Os, ++ OUT gctPOINTER * Mutex ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Validate the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); ++ ++ /* Allocate the mutex structure. */ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct mutex), Mutex)); ++ ++ /* Initialize the mutex. */ ++ mutex_init(*Mutex); ++ ++ /* Return status. */ ++ gcmkFOOTER_ARG("*Mutex=0x%X", *Mutex); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++gckOS_CreateNamedMutex( ++ IN gckOS Os, ++ IN struct lock_class_key *key, ++ IN const char *name, ++ OUT gctPOINTER * Mutex ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Validate the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); ++ ++ /* Allocate the mutex structure. */ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct mutex), Mutex)); ++ ++ /* Initialize the mutex. */ ++ mutex_init(*Mutex); ++ lockdep_set_class_and_name((struct mutex *)Mutex, key, name); ++ ++ /* Return status. */ ++ gcmkFOOTER_ARG("*Mutex=0x%X", *Mutex); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_DeleteMutex ++** ++** Delete a mutex. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Mutex ++** Pointer to the mute to be deleted. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_DeleteMutex( ++ IN gckOS Os, ++ IN gctPOINTER Mutex ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Mutex=0x%X", Os, Mutex); ++ ++ /* Validate the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); ++ ++ /* Destroy the mutex. */ ++ mutex_destroy((struct mutex *)Mutex); ++ ++ /* Free the mutex structure. */ ++ gcmkONERROR(gckOS_Free(Os, Mutex)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AcquireMutex ++** ++** Acquire a mutex. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Mutex ++** Pointer to the mutex to be acquired. ++** ++** gctUINT32 Timeout ++** Timeout value specified in milliseconds. ++** Specify the value of gcvINFINITE to keep the thread suspended ++** until the mutex has been acquired. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AcquireMutex( ++ IN gckOS Os, ++ IN gctPOINTER Mutex, ++ IN gctUINT32 Timeout ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x Timeout=%u", Os, Mutex, Timeout); ++ ++ /* Validate the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); ++ ++ if (Timeout == gcvINFINITE) ++ { ++ /* Lock the mutex. */ ++ mutex_lock(Mutex); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ for (;;) ++ { ++ /* Try to acquire the mutex. */ ++ if (mutex_trylock(Mutex)) ++ { ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ if (Timeout-- == 0) ++ { ++ break; ++ } ++ ++ /* Wait for 1 millisecond. */ ++ gcmkVERIFY_OK(gckOS_Delay(Os, 1)); ++ } ++ ++ /* Timeout. */ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_TIMEOUT); ++ return gcvSTATUS_TIMEOUT; ++} ++ ++/******************************************************************************* ++** ++** gckOS_ReleaseMutex ++** ++** Release an acquired mutex. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Mutex ++** Pointer to the mutex to be released. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_ReleaseMutex( ++ IN gckOS Os, ++ IN gctPOINTER Mutex ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x", Os, Mutex); ++ ++ /* Validate the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); ++ ++ /* Release the mutex. */ ++ mutex_unlock(Mutex); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomicExchange ++** ++** Atomically exchange a pair of 32-bit values. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** IN OUT gctINT32_PTR Target ++** Pointer to the 32-bit value to exchange. ++** ++** IN gctINT32 NewValue ++** Specifies a new value for the 32-bit value pointed to by Target. ++** ++** OUT gctINT32_PTR OldValue ++** The old value of the 32-bit value pointed to by Target. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomicExchange( ++ IN gckOS Os, ++ IN OUT gctUINT32_PTR Target, ++ IN gctUINT32 NewValue, ++ OUT gctUINT32_PTR OldValue ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=%u", Os, Target, NewValue); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(OldValue != gcvNULL); ++ ++ /* Exchange the pair of 32-bit values. */ ++ *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*OldValue=%u", *OldValue); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomicExchangePtr ++** ++** Atomically exchange a pair of pointers. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** IN OUT gctPOINTER * Target ++** Pointer to the 32-bit value to exchange. ++** ++** IN gctPOINTER NewValue ++** Specifies a new value for the pointer pointed to by Target. ++** ++** OUT gctPOINTER * OldValue ++** The old value of the pointer pointed to by Target. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomicExchangePtr( ++ IN gckOS Os, ++ IN OUT gctPOINTER * Target, ++ IN gctPOINTER NewValue, ++ OUT gctPOINTER * OldValue ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=0x%X", Os, Target, NewValue); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(OldValue != gcvNULL); ++ ++ /* Exchange the pair of pointers. */ ++ *OldValue = (gctPOINTER)(gctUINTPTR_T) atomic_xchg((atomic_t *) Target, (int)(gctUINTPTR_T) NewValue); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*OldValue=0x%X", *OldValue); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomicSetMask ++** ++** Atomically set mask to Atom ++** ++** INPUT: ++** IN OUT gctPOINTER Atom ++** Pointer to the atom to set. ++** ++** IN gctUINT32 Mask ++** Mask to set. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomSetMask( ++ IN gctPOINTER Atom, ++ IN gctUINT32 Mask ++ ) ++{ ++ gctUINT32 oval, nval; ++ ++ gcmkHEADER_ARG("Atom=0x%0x", Atom); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ do ++ { ++ oval = atomic_read((atomic_t *) Atom); ++ nval = oval | Mask; ++ } while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomClearMask ++** ++** Atomically clear mask from Atom ++** ++** INPUT: ++** IN OUT gctPOINTER Atom ++** Pointer to the atom to clear. ++** ++** IN gctUINT32 Mask ++** Mask to clear. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomClearMask( ++ IN gctPOINTER Atom, ++ IN gctUINT32 Mask ++ ) ++{ ++ gctUINT32 oval, nval; ++ ++ gcmkHEADER_ARG("Atom=0x%0x", Atom); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ do ++ { ++ oval = atomic_read((atomic_t *) Atom); ++ nval = oval & ~Mask; ++ } while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomConstruct ++** ++** Create an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** OUTPUT: ++** ++** gctPOINTER * Atom ++** Pointer to a variable receiving the constructed atom. ++*/ ++gceSTATUS ++gckOS_AtomConstruct( ++ IN gckOS Os, ++ OUT gctPOINTER * Atom ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ /* Allocate the atom. */ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom)); ++ ++ /* Initialize the atom. */ ++ atomic_set((atomic_t *) *Atom, 0); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Atom=0x%X", *Atom); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomDestroy ++** ++** Destroy an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom to destroy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomDestroy( ++ IN gckOS Os, ++ OUT gctPOINTER Atom ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ /* Free the atom. */ ++ gcmkONERROR(gcmkOS_SAFE_FREE(Os, Atom)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomGet ++** ++** Get the 32-bit value protected by an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** OUTPUT: ++** ++** gctINT32_PTR Value ++** Pointer to a variable the receives the value of the atom. ++*/ ++gceSTATUS ++gckOS_AtomGet( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ OUT gctINT32_PTR Value ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ /* Return the current value of atom. */ ++ *Value = atomic_read((atomic_t *) Atom); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Value=%d", *Value); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomSet ++** ++** Set the 32-bit value protected by an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** gctINT32 Value ++** The value of the atom. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomSet( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ IN gctINT32 Value ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x Value=%d", Os, Atom); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ /* Set the current value of atom. */ ++ atomic_set((atomic_t *) Atom, Value); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomIncrement ++** ++** Atomically increment the 32-bit integer value inside an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** OUTPUT: ++** ++** gctINT32_PTR Value ++** Pointer to a variable that receives the original value of the atom. ++*/ ++gceSTATUS ++gckOS_AtomIncrement( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ OUT gctINT32_PTR Value ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ /* Increment the atom. */ ++ *Value = atomic_inc_return((atomic_t *) Atom) - 1; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Value=%d", *Value); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AtomDecrement ++** ++** Atomically decrement the 32-bit integer value inside an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** OUTPUT: ++** ++** gctINT32_PTR Value ++** Pointer to a variable that receives the original value of the atom. ++*/ ++gceSTATUS ++gckOS_AtomDecrement( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ OUT gctINT32_PTR Value ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Atom != gcvNULL); ++ ++ /* Decrement the atom. */ ++ *Value = atomic_dec_return((atomic_t *) Atom) + 1; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Value=%d", *Value); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_Delay ++** ++** Delay execution of the current thread for a number of milliseconds. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 Delay ++** Delay to sleep, specified in milliseconds. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_Delay( ++ IN gckOS Os, ++ IN gctUINT32 Delay ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Delay=%u", Os, Delay); ++ ++ if (Delay > 0) ++ { ++ ktime_t delay = ktime_set((Delay / MSEC_PER_SEC), (Delay % MSEC_PER_SEC) * NSEC_PER_MSEC); ++ __set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_hrtimeout(&delay, HRTIMER_MODE_REL); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetTicks ++** ++** Get the number of milliseconds since the system started. ++** ++** INPUT: ++** ++** OUTPUT: ++** ++** gctUINT32_PTR Time ++** Pointer to a variable to get time. ++** ++*/ ++gceSTATUS ++gckOS_GetTicks( ++ OUT gctUINT32_PTR Time ++ ) ++{ ++ gcmkHEADER(); ++ ++ *Time = jiffies_to_msecs(jiffies); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_TicksAfter ++** ++** Compare time values got from gckOS_GetTicks. ++** ++** INPUT: ++** gctUINT32 Time1 ++** First time value to be compared. ++** ++** gctUINT32 Time2 ++** Second time value to be compared. ++** ++** OUTPUT: ++** ++** gctBOOL_PTR IsAfter ++** Pointer to a variable to result. ++** ++*/ ++gceSTATUS ++gckOS_TicksAfter( ++ IN gctUINT32 Time1, ++ IN gctUINT32 Time2, ++ OUT gctBOOL_PTR IsAfter ++ ) ++{ ++ gcmkHEADER(); ++ ++ *IsAfter = time_after((unsigned long)Time1, (unsigned long)Time2); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetTime ++** ++** Get the number of microseconds since the system started. ++** ++** INPUT: ++** ++** OUTPUT: ++** ++** gctUINT64_PTR Time ++** Pointer to a variable to get time. ++** ++*/ ++gceSTATUS ++gckOS_GetTime( ++ OUT gctUINT64_PTR Time ++ ) ++{ ++ struct timeval tv; ++ gcmkHEADER(); ++ ++ /* Return the time of day in microseconds. */ ++ do_gettimeofday(&tv); ++ *Time = (tv.tv_sec * 1000000ULL) + tv.tv_usec; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_MemoryBarrier ++** ++** Make sure the CPU has executed everything up to this point and the data got ++** written to the specified pointer. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Address ++** Address of memory that needs to be barriered. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_MemoryBarrier( ++ IN gckOS Os, ++ IN gctPOINTER Address ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Address=0x%X", Os, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ mb(); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AllocatePagedMemory ++** ++** Allocate memory from the paged pool. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIZE_T Bytes ++** Number of bytes to allocate. ++** ++** OUTPUT: ++** ++** gctPHYS_ADDR * Physical ++** Pointer to a variable that receives the physical address of the ++** memory allocation. ++*/ ++gceSTATUS ++gckOS_AllocatePagedMemory( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPHYS_ADDR * Physical ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ ++ /* Allocate the memory. */ ++ gcmkONERROR(gckOS_AllocatePagedMemoryEx(Os, gcvALLOC_FLAG_NONE, Bytes, gcvNULL, Physical)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Physical=0x%X", *Physical); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AllocatePagedMemoryEx ++** ++** Allocate memory from the paged pool. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 Flag ++** Allocation attribute. ++** ++** gctSIZE_T Bytes ++** Number of bytes to allocate. ++** ++** OUTPUT: ++** ++** gctUINT32 * Gid ++** Save the global ID for the piece of allocated memory. ++** ++** gctPHYS_ADDR * Physical ++** Pointer to a variable that receives the physical address of the ++** memory allocation. ++*/ ++gceSTATUS ++gckOS_AllocatePagedMemoryEx( ++ IN gckOS Os, ++ IN gctUINT32 Flag, ++ IN gctSIZE_T Bytes, ++ OUT gctUINT32 * Gid, ++ OUT gctPHYS_ADDR * Physical ++ ) ++{ ++ gctINT numPages; ++ PLINUX_MDL mdl = gcvNULL; ++ gctSIZE_T bytes; ++ gceSTATUS status = gcvSTATUS_OUT_OF_MEMORY; ++ gckALLOCATOR allocator; ++ ++ gcmkHEADER_ARG("Os=0x%X Flag=%x Bytes=%lu", Os, Flag, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ ++ bytes = gcmALIGN(Bytes, PAGE_SIZE); ++ ++ numPages = GetPageCount(bytes, 0); ++ ++ mdl = _CreateMdl(); ++ if (mdl == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Walk all allocators. */ ++ list_for_each_entry(allocator, &Os->allocatorList, head) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d) flag = %x allocator->capability = %x", ++ __FUNCTION__, __LINE__, Flag, allocator->capability); ++ ++ if ((Flag & allocator->capability) != Flag) ++ { ++ continue; ++ } ++ ++ status = allocator->ops->Alloc(allocator, mdl, numPages, Flag); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ mdl->allocator = allocator; ++ break; ++ } ++ } ++ ++ /* Check status. */ ++ gcmkONERROR(status); ++ ++ mdl->dmaHandle = 0; ++ mdl->addr = 0; ++ mdl->numPages = numPages; ++ mdl->pagedMem = 1; ++ mdl->contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS; ++ ++ if (Gid != gcvNULL) ++ { ++ *Gid = mdl->gid; ++ } ++ ++ MEMORY_LOCK(Os); ++ ++ /* ++ * Add this to a global list. ++ * Will be used by get physical address ++ * and mapuser pointer functions. ++ */ ++ if (!Os->mdlHead) ++ { ++ /* Initialize the queue. */ ++ Os->mdlHead = Os->mdlTail = mdl; ++ } ++ else ++ { ++ /* Add to tail. */ ++ mdl->prev = Os->mdlTail; ++ Os->mdlTail->next = mdl; ++ Os->mdlTail = mdl; ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ /* Return physical address. */ ++ *Physical = (gctPHYS_ADDR) mdl; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Physical=0x%X", *Physical); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (mdl != gcvNULL) ++ { ++ /* Free the memory. */ ++ _DestroyMdl(mdl); ++ } ++ *Physical = gcvNULL; ++ ++ /* Return the status. */ ++ gcmkFOOTER_ARG("Os=0x%X Flag=%x Bytes=%lu", Os, Flag, Bytes); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_FreePagedMemory ++** ++** Free memory allocated from the paged pool. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Physical address of the allocation. ++** ++** gctSIZE_T Bytes ++** Number of bytes of the allocation. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_FreePagedMemory( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ PLINUX_MDL mdl = (PLINUX_MDL) Physical; ++ gckALLOCATOR allocator = (gckALLOCATOR)mdl->allocator; ++ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ MEMORY_LOCK(Os); ++ ++ /* Remove the node from global list. */ ++ if (mdl == Os->mdlHead) ++ { ++ if ((Os->mdlHead = mdl->next) == gcvNULL) ++ { ++ Os->mdlTail = gcvNULL; ++ } ++ } ++ else ++ { ++ mdl->prev->next = mdl->next; ++ ++ if (mdl == Os->mdlTail) ++ { ++ Os->mdlTail = mdl->prev; ++ } ++ else ++ { ++ mdl->next->prev = mdl->prev; ++ } ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ allocator->ops->Free(allocator, mdl); ++ ++ /* Free the structure... */ ++ gcmkVERIFY_OK(_DestroyMdl(mdl)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_LockPages ++** ++** Lock memory allocated from the paged pool. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Physical address of the allocation. ++** ++** gctSIZE_T Bytes ++** Number of bytes of the allocation. ++** ++** gctBOOL Cacheable ++** Cache mode of mapping. ++** ++** OUTPUT: ++** ++** gctPOINTER * Logical ++** Pointer to a variable that receives the address of the mapped ++** memory. ++** ++** gctSIZE_T * PageCount ++** Pointer to a variable that receives the number of pages required for ++** the page table according to the GPU page size. ++*/ ++gceSTATUS ++gckOS_LockPages( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctBOOL Cacheable, ++ OUT gctPOINTER * Logical, ++ OUT gctSIZE_T * PageCount ++ ) ++{ ++ gceSTATUS status; ++ PLINUX_MDL mdl; ++ PLINUX_MDL_MAP mdlMap; ++ gckALLOCATOR allocator; ++ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%u", Os, Physical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(PageCount != gcvNULL); ++ ++ mdl = (PLINUX_MDL) Physical; ++ allocator = mdl->allocator; ++ ++ MEMORY_LOCK(Os); ++ ++ mdlMap = FindMdlMap(mdl, _GetProcessID()); ++ ++ if (mdlMap == gcvNULL) ++ { ++ mdlMap = _CreateMdlMap(mdl, _GetProcessID()); ++ ++ if (mdlMap == gcvNULL) ++ { ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ } ++ ++ if (mdlMap->vmaAddr == gcvNULL) ++ { ++ status = allocator->ops->MapUser(allocator, mdl, mdlMap, Cacheable); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ MEMORY_UNLOCK(Os); ++ ++ gcmkFOOTER_ARG("*status=%d", status); ++ return status; ++ } ++ } ++ ++ mdlMap->count++; ++ ++ /* Convert pointer to MDL. */ ++ *Logical = mdlMap->vmaAddr; ++ ++ /* Return the page number according to the GPU page size. */ ++ gcmkASSERT((PAGE_SIZE / 4096) >= 1); ++ ++ *PageCount = mdl->numPages * (PAGE_SIZE / 4096); ++ ++ MEMORY_UNLOCK(Os); ++ ++ gcmkVERIFY_OK(gckOS_CacheFlush( ++ Os, ++ _GetProcessID(), ++ Physical, ++ gcvINVALID_ADDRESS, ++ (gctPOINTER)mdlMap->vmaAddr, ++ mdl->numPages * PAGE_SIZE ++ )); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Logical=0x%X *PageCount=%lu", *Logical, *PageCount); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_MapPages ++** ++** Map paged memory into a page table. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Physical address of the allocation. ++** ++** gctSIZE_T PageCount ++** Number of pages required for the physical address. ++** ++** gctPOINTER PageTable ++** Pointer to the page table to fill in. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_MapPages( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T PageCount, ++ IN gctPOINTER PageTable ++ ) ++{ ++ return gckOS_MapPagesEx(Os, ++ gcvCORE_MAJOR, ++ Physical, ++ PageCount, ++ 0, ++ PageTable); ++} ++ ++gceSTATUS ++gckOS_MapPagesEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T PageCount, ++ IN gctUINT32 Address, ++ IN gctPOINTER PageTable ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ PLINUX_MDL mdl; ++ gctUINT32* table; ++ gctUINT32 offset; ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ gckMMU mmu; ++ PLINUX_MDL mmuMdl; ++ gctUINT32 bytes; ++ gctPHYS_ADDR pageTablePhysical; ++#endif ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gckKERNEL kernel = Os->device->kernels[Core]; ++ gckMMU mmu; ++#endif ++ gckALLOCATOR allocator; ++ ++ gcmkHEADER_ARG("Os=0x%X Core=%d Physical=0x%X PageCount=%u PageTable=0x%X", ++ Os, Core, Physical, PageCount, PageTable); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(PageCount > 0); ++ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); ++ ++ /* Convert pointer to MDL. */ ++ mdl = (PLINUX_MDL)Physical; ++ ++ allocator = mdl->allocator; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): Physical->0x%X PageCount->0x%X PagedMemory->?%d", ++ __FUNCTION__, __LINE__, ++ (gctUINT32)(gctUINTPTR_T)Physical, ++ (gctUINT32)(gctUINTPTR_T)PageCount, ++ mdl->pagedMem ++ ); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkONERROR(gckKERNEL_GetProcessMMU(kernel, &mmu)); ++#endif ++ ++ table = (gctUINT32 *)PageTable; ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ mmu = Os->device->kernels[Core]->mmu; ++ bytes = PageCount * sizeof(*table); ++ mmuMdl = (PLINUX_MDL)mmu->pageTablePhysical; ++#endif ++ ++ /* Get all the physical addresses and store them in the page table. */ ++ ++ offset = 0; ++ PageCount = PageCount / (PAGE_SIZE / 4096); ++ ++ /* Try to get the user pages so DMA can happen. */ ++ while (PageCount-- > 0) ++ { ++ gctUINT i; ++ gctUINT32 phys = ~0; ++ ++ if (mdl->pagedMem && !mdl->contiguous) ++ { ++ allocator->ops->Physical(allocator, mdl, offset, &phys); ++ } ++ else ++ { ++ if (!mdl->pagedMem) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): we should not get this call for Non Paged Memory!", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ ++ phys = page_to_phys(nth_page(mdl->u.contiguousPages, offset)); ++ } ++ ++ gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, phys, &phys)); ++ ++#ifdef CONFIG_IOMMU_SUPPORT ++ if (Os->iommu) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): Setup mapping in IOMMU %x => %x", ++ __FUNCTION__, __LINE__, ++ Address + (offset * PAGE_SIZE), phys ++ ); ++ ++ /* When use IOMMU, GPU use system PAGE_SIZE. */ ++ gcmkONERROR(gckIOMMU_Map( ++ Os->iommu, Address + (offset * PAGE_SIZE), phys, PAGE_SIZE)); ++ } ++ else ++#endif ++ { ++ ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ for (i = 0; i < (PAGE_SIZE / 4096); i++) ++ { ++ gcmkONERROR( ++ gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu, ++ phys + (i * 4096), ++ table++)); ++ } ++ } ++ else ++#endif ++ { ++ for (i = 0; i < (PAGE_SIZE / 4096); i++) ++ { ++#if gcdPROCESS_ADDRESS_SPACE ++ gctUINT32_PTR pageTableEntry; ++ gckMMU_GetPageEntry(mmu, Address + (offset * 4096), &pageTableEntry); ++ gcmkONERROR( ++ gckMMU_SetPage(mmu, ++ phys + (i * 4096), ++ pageTableEntry)); ++#else ++ gcmkONERROR( ++ gckMMU_SetPage(Os->device->kernels[Core]->mmu, ++ phys + (i * 4096), ++ table++)); ++#endif ++ } ++ } ++ } ++ ++ offset += 1; ++ } ++ ++#if gcdNONPAGED_MEMORY_CACHEABLE ++ /* Get physical address of pageTable */ ++ pageTablePhysical = (gctPHYS_ADDR)(mmuMdl->dmaHandle + ++ ((gctUINT32 *)PageTable - mmu->pageTableLogical)); ++ ++ /* Flush the mmu page table cache. */ ++ gcmkONERROR(gckOS_CacheClean( ++ Os, ++ _GetProcessID(), ++ gcvNULL, ++ pageTablePhysical, ++ PageTable, ++ bytes ++ )); ++#endif ++ ++OnError: ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_UnmapPages( ++ IN gckOS Os, ++ IN gctSIZE_T PageCount, ++ IN gctUINT32 Address ++ ) ++{ ++#ifdef CONFIG_IOMMU_SUPPORT ++ if (Os->iommu) ++ { ++ gcmkVERIFY_OK(gckIOMMU_Unmap( ++ Os->iommu, Address, PageCount * PAGE_SIZE)); ++ } ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UnlockPages ++** ++** Unlock memory allocated from the paged pool. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Physical address of the allocation. ++** ++** gctSIZE_T Bytes ++** Number of bytes of the allocation. ++** ++** gctPOINTER Logical ++** Address of the mapped memory. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UnlockPages( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ) ++{ ++ PLINUX_MDL_MAP mdlMap; ++ PLINUX_MDL mdl = (PLINUX_MDL)Physical; ++ gckALLOCATOR allocator = mdl->allocator; ++ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%u Logical=0x%X", ++ Os, Physical, Bytes, Logical); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ MEMORY_LOCK(Os); ++ ++ mdlMap = mdl->maps; ++ ++ while (mdlMap != gcvNULL) ++ { ++ if ((mdlMap->vmaAddr != gcvNULL) && (_GetProcessID() == mdlMap->pid)) ++ { ++ if (--mdlMap->count == 0) ++ { ++ allocator->ops->UnmapUser( ++ allocator, ++ mdlMap->vmaAddr, ++ mdl->numPages * PAGE_SIZE); ++ ++ mdlMap->vmaAddr = gcvNULL; ++ } ++ } ++ ++ mdlMap = mdlMap->next; ++ } ++ ++ MEMORY_UNLOCK(Os); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++ ++/******************************************************************************* ++** ++** gckOS_AllocateContiguous ++** ++** Allocate memory from the contiguous pool. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctBOOL InUserSpace ++** gcvTRUE if the pages need to be mapped into user space. ++** ++** gctSIZE_T * Bytes ++** Pointer to the number of bytes to allocate. ++** ++** OUTPUT: ++** ++** gctSIZE_T * Bytes ++** Pointer to a variable that receives the number of bytes allocated. ++** ++** gctPHYS_ADDR * Physical ++** Pointer to a variable that receives the physical address of the ++** memory allocation. ++** ++** gctPOINTER * Logical ++** Pointer to a variable that receives the logical address of the ++** memory allocation. ++*/ ++gceSTATUS ++gckOS_AllocateContiguous( ++ IN gckOS Os, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu", ++ Os, InUserSpace, gcmOPT_VALUE(Bytes)); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes != gcvNULL); ++ gcmkVERIFY_ARGUMENT(*Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ ++ /* Same as non-paged memory for now. */ ++ gcmkONERROR(gckOS_AllocateNonPagedMemory(Os, ++ InUserSpace, ++ Bytes, ++ Physical, ++ Logical)); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X", ++ *Bytes, *Physical, *Logical); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_FreeContiguous ++** ++** Free memory allocated from the contiguous pool. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPHYS_ADDR Physical ++** Physical address of the allocation. ++** ++** gctPOINTER Logical ++** Logicval address of the allocation. ++** ++** gctSIZE_T Bytes ++** Number of bytes of the allocation. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_FreeContiguous( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu", ++ Os, Physical, Logical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Physical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ /* Same of non-paged memory for now. */ ++ gcmkONERROR(gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if gcdENABLE_VG ++/****************************************************************************** ++** ++** gckOS_GetKernelLogical ++** ++** Return the kernel logical pointer that corresponods to the specified ++** hardware address. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 Address ++** Hardware physical address. ++** ++** OUTPUT: ++** ++** gctPOINTER * KernelPointer ++** Pointer to a variable receiving the pointer in kernel address space. ++*/ ++gceSTATUS ++gckOS_GetKernelLogical( ++ IN gckOS Os, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * KernelPointer ++ ) ++{ ++ return gckOS_GetKernelLogicalEx(Os, gcvCORE_MAJOR, Address, KernelPointer); ++} ++ ++gceSTATUS ++gckOS_GetKernelLogicalEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * KernelPointer ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%08x", Os, Core, Address); ++ ++ do ++ { ++ gckGALDEVICE device; ++ gckKERNEL kernel; ++ gcePOOL pool; ++ gctUINT32 offset; ++ gctPOINTER logical; ++ ++ /* Extract the pointer to the gckGALDEVICE class. */ ++ device = (gckGALDEVICE) Os->device; ++ ++ /* Kernel shortcut. */ ++ kernel = device->kernels[Core]; ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ gcmkERR_BREAK(gckVGHARDWARE_SplitMemory( ++ kernel->vg->hardware, Address, &pool, &offset ++ )); ++ } ++ else ++#endif ++ { ++ /* Split the memory address into a pool type and offset. */ ++ gcmkERR_BREAK(gckHARDWARE_SplitMemory( ++ kernel->hardware, Address, &pool, &offset ++ )); ++ } ++ ++ /* Dispatch on pool. */ ++ switch (pool) ++ { ++ case gcvPOOL_LOCAL_INTERNAL: ++ /* Internal memory. */ ++ logical = device->internalLogical; ++ break; ++ ++ case gcvPOOL_LOCAL_EXTERNAL: ++ /* External memory. */ ++ logical = device->externalLogical; ++ break; ++ ++ case gcvPOOL_SYSTEM: ++ /* System memory. */ ++ logical = device->contiguousBase; ++ break; ++ ++ default: ++ /* Invalid memory pool. */ ++ gcmkFOOTER(); ++ return gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++ /* Build logical address of specified address. */ ++ * KernelPointer = ((gctUINT8_PTR) logical) + offset; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer); ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Return status. */ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckOS_MapUserPointer ++** ++** Map a pointer from the user process into the kernel address space. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Pointer ++** Pointer in user process space that needs to be mapped. ++** ++** gctSIZE_T Size ++** Number of bytes that need to be mapped. ++** ++** OUTPUT: ++** ++** gctPOINTER * KernelPointer ++** Pointer to a variable receiving the mapped pointer in kernel address ++** space. ++*/ ++gceSTATUS ++gckOS_MapUserPointer( ++ IN gckOS Os, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * KernelPointer ++ ) ++{ ++ gctPOINTER buf = gcvNULL; ++ gctUINT32 len; ++ ++ gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu", Os, Pointer, Size); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); ++ ++ buf = kmalloc(Size, GFP_KERNEL | gcdNOWARN); ++ if (buf == gcvNULL) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): Failed to allocate memory.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ len = copy_from_user(buf, Pointer, Size); ++ if (len != 0) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): Failed to copy data from user.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ if (buf != gcvNULL) ++ { ++ kfree(buf); ++ } ++ ++ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_GENERIC_IO); ++ return gcvSTATUS_GENERIC_IO; ++ } ++ ++ *KernelPointer = buf; ++ ++ gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UnmapUserPointer ++** ++** Unmap a user process pointer from the kernel address space. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Pointer ++** Pointer in user process space that needs to be unmapped. ++** ++** gctSIZE_T Size ++** Number of bytes that need to be unmapped. ++** ++** gctPOINTER KernelPointer ++** Pointer in kernel address space that needs to be unmapped. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UnmapUserPointer( ++ IN gckOS Os, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size, ++ IN gctPOINTER KernelPointer ++ ) ++{ ++ gctUINT32 len; ++ ++ gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu KernelPointer=0x%X", ++ Os, Pointer, Size, KernelPointer); ++ ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); ++ ++ len = copy_to_user(Pointer, KernelPointer, Size); ++ ++ kfree(KernelPointer); ++ ++ if (len != 0) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): Failed to copy data to user.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_GENERIC_IO); ++ return gcvSTATUS_GENERIC_IO; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_QueryNeedCopy ++** ++** Query whether the memory can be accessed or mapped directly or it has to be ++** copied. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 ProcessID ++** Process ID of the current process. ++** ++** OUTPUT: ++** ++** gctBOOL_PTR NeedCopy ++** Pointer to a boolean receiving gcvTRUE if the memory needs a copy or ++** gcvFALSE if the memory can be accessed or mapped dircetly. ++*/ ++gceSTATUS ++gckOS_QueryNeedCopy( ++ IN gckOS Os, ++ IN gctUINT32 ProcessID, ++ OUT gctBOOL_PTR NeedCopy ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X ProcessID=%d", Os, ProcessID); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(NeedCopy != gcvNULL); ++ ++ /* We need to copy data. */ ++ *NeedCopy = gcvTRUE; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*NeedCopy=%d", *NeedCopy); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_CopyFromUserData ++** ++** Copy data from user to kernel memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER KernelPointer ++** Pointer to kernel memory. ++** ++** gctPOINTER Pointer ++** Pointer to user memory. ++** ++** gctSIZE_T Size ++** Number of bytes to copy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_CopyFromUserData( ++ IN gckOS Os, ++ IN gctPOINTER KernelPointer, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu", ++ Os, KernelPointer, Pointer, Size); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ ++ /* Copy data from user. */ ++ if (copy_from_user(KernelPointer, Pointer, Size) != 0) ++ { ++ /* Could not copy all the bytes. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_CopyToUserData ++** ++** Copy data from kernel to user memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER KernelPointer ++** Pointer to kernel memory. ++** ++** gctPOINTER Pointer ++** Pointer to user memory. ++** ++** gctSIZE_T Size ++** Number of bytes to copy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_CopyToUserData( ++ IN gckOS Os, ++ IN gctPOINTER KernelPointer, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu", ++ Os, KernelPointer, Pointer, Size); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ ++ /* Copy data to user. */ ++ if (copy_to_user(Pointer, KernelPointer, Size) != 0) ++ { ++ /* Could not copy all the bytes. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_WriteMemory ++** ++** Write data to a memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER Address ++** Address of the memory to write to. ++** ++** gctUINT32 Data ++** Data for register. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_WriteMemory( ++ IN gckOS Os, ++ IN gctPOINTER Address, ++ IN gctUINT32 Data ++ ) ++{ ++ gceSTATUS status; ++ gcmkHEADER_ARG("Os=0x%X Address=0x%X Data=%u", Os, Address, Data); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ /* Write memory. */ ++ if (access_ok(VERIFY_WRITE, Address, 4)) ++ { ++ /* User address. */ ++ if(put_user(Data, (gctUINT32*)Address)) ++ { ++ gcmkONERROR(gcvSTATUS_INVALID_ADDRESS); ++ } ++ } ++ else ++ { ++ /* Kernel address. */ ++ *(gctUINT32 *)Address = Data; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_MapUserMemory ++** ++** Lock down a user buffer and return an DMA'able address to be used by the ++** hardware to access it. ++** ++** INPUT: ++** ++** gctPOINTER Memory ++** Pointer to memory to lock down. ++** ++** gctSIZE_T Size ++** Size in bytes of the memory to lock down. ++** ++** OUTPUT: ++** ++** gctPOINTER * Info ++** Pointer to variable receiving the information record required by ++** gckOS_UnmapUserMemory. ++** ++** gctUINT32_PTR Address ++** Pointer to a variable that will receive the address DMA'able by the ++** hardware. ++*/ ++gceSTATUS ++gckOS_MapUserMemory( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPOINTER Memory, ++ IN gctUINT32 Physical, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * Info, ++ OUT gctUINT32_PTR Address ++ ) ++{ ++ gceSTATUS status; ++ gctSIZE_T pageCount, i, j; ++ gctUINT32_PTR pageTable; ++ gctUINT32 address = 0, physical = ~0U; ++ gctUINTPTR_T start, end, memory; ++ gctUINT32 offset; ++ gctINT result = 0; ++#if gcdPROCESS_ADDRESS_SPACE ++ gckMMU mmu; ++#endif ++ ++ gcsPageInfo_PTR info = gcvNULL; ++ struct page **pages = gcvNULL; ++ ++ gcmkHEADER_ARG("Os=0x%x Core=%d Memory=0x%x Size=%lu", Os, Core, Memory, Size); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL || Physical != ~0U); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ gcmkVERIFY_ARGUMENT(Info != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ do ++ { ++ gctSIZE_T extraPage; ++ ++ memory = (gctUINTPTR_T) Memory; ++ ++ /* Get the number of required pages. */ ++ end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ start = memory >> PAGE_SHIFT; ++ pageCount = end - start; ++ ++ /* Allocate extra 64 bytes to avoid cache overflow */ ++ extraPage = (((memory + gcmALIGN(Size + 64, 64) + PAGE_SIZE - 1) >> PAGE_SHIFT) > end) ? 1 : 0; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): pageCount: %d.", ++ __FUNCTION__, __LINE__, ++ pageCount ++ ); ++ ++ /* Overflow. */ ++ if ((memory + Size) < memory) ++ { ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); ++ return gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++ MEMORY_MAP_LOCK(Os); ++ ++ /* Allocate the Info struct. */ ++ info = (gcsPageInfo_PTR)kmalloc(sizeof(gcsPageInfo), GFP_KERNEL | gcdNOWARN); ++ ++ if (info == gcvNULL) ++ { ++ status = gcvSTATUS_OUT_OF_MEMORY; ++ break; ++ } ++ ++ info->extraPage = 0; ++ ++ /* Allocate the array of page addresses. */ ++ pages = (struct page **)kmalloc((pageCount + extraPage) * sizeof(struct page *), GFP_KERNEL | gcdNOWARN); ++ ++ if (pages == gcvNULL) ++ { ++ status = gcvSTATUS_OUT_OF_MEMORY; ++ break; ++ } ++ ++ if (Physical != ~0U) ++ { ++ unsigned long pfn = Physical >> PAGE_SHIFT; ++ for (i = 0; i < pageCount; i++) ++ { ++ if (!pfn_valid(pfn + i)) ++ { ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ } ++ ++ for (i = 0; i < pageCount; i++) ++ { ++ pages[i] = pfn_to_page(pfn + i); ++ get_page(pages[i]); ++ } ++ } ++ else ++ { ++ /* Get the user pages. */ ++ down_read(¤t->mm->mmap_sem); ++ ++ result = get_user_pages(current, ++ current->mm, ++ memory & PAGE_MASK, ++ pageCount, ++ 1, ++ 0, ++ pages, ++ gcvNULL ++ ); ++ ++ up_read(¤t->mm->mmap_sem); ++ ++ if (result <=0 || result < pageCount) ++ { ++ struct vm_area_struct *vma; ++ ++ /* Release the pages if any. */ ++ if (result > 0) ++ { ++ for (i = 0; i < result; i++) ++ { ++ if (pages[i] != gcvNULL) ++ { ++ page_cache_release(pages[i]); ++ pages[i] = gcvNULL; ++ } ++ } ++ ++ result = 0; ++ } ++ ++ vma = find_vma(current->mm, memory); ++ ++ if (vma && (vma->vm_flags & VM_PFNMAP)) ++ { ++ pte_t * pte; ++ spinlock_t * ptl; ++ gctUINTPTR_T logical = memory; ++ ++ for (i = 0; i < pageCount; i++) ++ { ++ pgd_t * pgd = pgd_offset(current->mm, logical); ++ pud_t * pud = pud_offset(pgd, logical); ++ unsigned long pfn; ++ ++ if (pud) ++ { ++ pmd_t * pmd = pmd_offset(pud, logical); ++ pte = pte_offset_map_lock(current->mm, pmd, logical, &ptl); ++ if (!pte) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ } ++ else ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ if (pte_present(*pte)) ++ pfn = pte_pfn(*pte); ++ else ++ pfn = ~0UL; ++ pte_unmap_unlock(pte, ptl); ++ ++ if (pfn == ~0UL || !pfn_valid(pfn)) ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ ++ pages[i] = pfn_to_page(pfn); ++ ++ /* Advance to next. */ ++ logical += PAGE_SIZE; ++ } ++ } ++ else ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ /* Check if this memory is contiguous for old mmu. */ ++ if (Os->device->kernels[Core]->hardware->mmuVersion == 0) ++ { ++ for (i = 1; i < pageCount; i++) ++ { ++ if (pages[i] != nth_page(pages[0], i)) ++ { ++ /* Non-contiguous. */ ++ break; ++ } ++ } ++ ++ if (i == pageCount) ++ { ++ /* Contiguous memory. */ ++ physical = page_to_phys(pages[0]) | (memory & ~PAGE_MASK); ++ ++ if (!((physical - Os->device->baseAddress) & 0x80000000)) ++ { ++ kfree(pages); ++ pages = gcvNULL; ++ ++ info->pages = gcvNULL; ++ info->pageTable = gcvNULL; ++ ++ MEMORY_MAP_UNLOCK(Os); ++ ++ *Address = physical - Os->device->baseAddress; ++ *Info = info; ++ ++ gcmkVERIFY_OK( ++ gckOS_CPUPhysicalToGPUPhysical(Os, *Address, Address)); ++ ++ gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x", ++ *Info, *Address); ++ ++ return gcvSTATUS_OK; ++ } ++ } ++ } ++ ++ /* Reference pages. */ ++ for (i = 0; i < pageCount; i++) ++ { ++ if (pfn_valid(page_to_pfn(pages[i]))) ++ { ++ get_page(pages[i]); ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i < pageCount; i++) ++ { ++#ifdef CONFIG_ARM ++ gctUINT32 data; ++ get_user(data, (gctUINT32*)((memory & PAGE_MASK) + i * PAGE_SIZE)); ++#endif ++ ++ /* Flush(clean) the data cache. */ ++ gcmkONERROR(gckOS_CacheFlush(Os, _GetProcessID(), gcvNULL, ++ page_to_phys(pages[i]), ++ (gctPOINTER)(memory & PAGE_MASK) + i*PAGE_SIZE, ++ PAGE_SIZE)); ++ } ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkONERROR(gckKERNEL_GetProcessMMU(Os->device->kernels[Core], &mmu)); ++#endif ++ ++ if (extraPage) ++ { ++ pages[pageCount++] = Os->paddingPage; ++ info->extraPage = 1; ++ } ++ ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ /* Allocate pages inside the page table. */ ++ gcmkERR_BREAK(gckVGMMU_AllocatePages(Os->device->kernels[Core]->vg->mmu, ++ pageCount * (PAGE_SIZE/4096), ++ (gctPOINTER *) &pageTable, ++ &address)); ++ } ++ else ++#endif ++ { ++#if gcdPROCESS_ADDRESS_SPACE ++ /* Allocate pages inside the page table. */ ++ gcmkERR_BREAK(gckMMU_AllocatePages(mmu, ++ pageCount * (PAGE_SIZE/4096), ++ (gctPOINTER *) &pageTable, ++ &address)); ++#else ++ /* Allocate pages inside the page table. */ ++ gcmkERR_BREAK(gckMMU_AllocatePages(Os->device->kernels[Core]->mmu, ++ pageCount * (PAGE_SIZE/4096), ++ (gctPOINTER *) &pageTable, ++ &address)); ++#endif ++ } ++ ++ /* Fill the page table. */ ++ for (i = 0; i < pageCount; i++) ++ { ++ gctUINT32 phys; ++ gctUINT32_PTR tab = pageTable + i * (PAGE_SIZE/4096); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gckMMU_GetPageEntry(mmu, address + i * 4096, &tab); ++#endif ++ phys = page_to_phys(pages[i]); ++ ++#ifdef CONFIG_IOMMU_SUPPORT ++ if (Os->iommu) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): Setup mapping in IOMMU %x => %x", ++ __FUNCTION__, __LINE__, ++ Address + (i * PAGE_SIZE), phys ++ ); ++ ++ gcmkONERROR(gckIOMMU_Map( ++ Os->iommu, address + i * PAGE_SIZE, phys, PAGE_SIZE)); ++ } ++ else ++#endif ++ { ++ ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ gcmkVERIFY_OK( ++ gckOS_CPUPhysicalToGPUPhysical(Os, phys, &phys)); ++ ++ /* Get the physical address from page struct. */ ++ gcmkONERROR( ++ gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu, ++ phys, ++ tab)); ++ } ++ else ++#endif ++ { ++ /* Get the physical address from page struct. */ ++ gcmkONERROR( ++ gckMMU_SetPage(Os->device->kernels[Core]->mmu, ++ phys, ++ tab)); ++ } ++ ++ for (j = 1; j < (PAGE_SIZE/4096); j++) ++ { ++ pageTable[i * (PAGE_SIZE/4096) + j] = pageTable[i * (PAGE_SIZE/4096)] + 4096 * j; ++ } ++ } ++ ++#if !gcdPROCESS_ADDRESS_SPACE ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): pageTable[%d]: 0x%X 0x%X.", ++ __FUNCTION__, __LINE__, ++ i, phys, pageTable[i]); ++#endif ++ } ++ ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ gcmkONERROR(gckVGMMU_Flush(Os->device->kernels[Core]->vg->mmu)); ++ } ++ else ++#endif ++ { ++#if gcdPROCESS_ADDRESS_SPACE ++ info->mmu = mmu; ++ gcmkONERROR(gckMMU_Flush(mmu)); ++#else ++ gcmkONERROR(gckMMU_Flush(Os->device->kernels[Core]->mmu, gcvSURF_TYPE_UNKNOWN)); ++#endif ++ } ++ info->address = address; ++ ++ /* Save pointer to page table. */ ++ info->pageTable = pageTable; ++ info->pages = pages; ++ ++ *Info = (gctPOINTER) info; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): info->pages: 0x%X, info->pageTable: 0x%X, info: 0x%X.", ++ __FUNCTION__, __LINE__, ++ info->pages, ++ info->pageTable, ++ info ++ ); ++ ++ offset = (Physical != ~0U) ++ ? (Physical & ~PAGE_MASK) ++ : (memory & ~PAGE_MASK); ++ ++ /* Return address. */ ++ *Address = address + offset; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): Address: 0x%X.", ++ __FUNCTION__, __LINE__, ++ *Address ++ ); ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++OnError: ++ ++ if (gcmIS_ERROR(status)) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): error occured: %d.", ++ __FUNCTION__, __LINE__, ++ status ++ ); ++ ++ /* Release page array. */ ++ if (result > 0 && pages != gcvNULL) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): error: page table is freed.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ for (i = 0; i < result; i++) ++ { ++ if (pages[i] == gcvNULL) ++ { ++ break; ++ } ++ page_cache_release(pages[i]); ++ } ++ } ++ ++ if (info!= gcvNULL && pages != gcvNULL) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): error: pages is freed.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Free the page table. */ ++ kfree(pages); ++ info->pages = gcvNULL; ++ } ++ ++ /* Release page info struct. */ ++ if (info != gcvNULL) ++ { ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): error: info is freed.", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ /* Free the page info struct. */ ++ kfree(info); ++ *Info = gcvNULL; ++ } ++ } ++ ++ MEMORY_MAP_UNLOCK(Os); ++ ++ /* Return the status. */ ++ if (gcmIS_SUCCESS(status)) ++ { ++ gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x", *Info, *Address); ++ } ++ else ++ { ++ gcmkFOOTER(); ++ } ++ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UnmapUserMemory ++** ++** Unlock a user buffer and that was previously locked down by ++** gckOS_MapUserMemory. ++** ++** INPUT: ++** ++** gctPOINTER Memory ++** Pointer to memory to unlock. ++** ++** gctSIZE_T Size ++** Size in bytes of the memory to unlock. ++** ++** gctPOINTER Info ++** Information record returned by gckOS_MapUserMemory. ++** ++** gctUINT32_PTR Address ++** The address returned by gckOS_MapUserMemory. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UnmapUserMemory( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPOINTER Memory, ++ IN gctSIZE_T Size, ++ IN gctPOINTER Info, ++ IN gctUINT32 Address ++ ) ++{ ++ gceSTATUS status; ++ gctUINTPTR_T memory, start, end; ++ gcsPageInfo_PTR info; ++ gctSIZE_T pageCount, i; ++ struct page **pages; ++ ++ gcmkHEADER_ARG("Os=0x%X Core=%d Memory=0x%X Size=%lu Info=0x%X Address0x%08x", ++ Os, Core, Memory, Size, Info, Address); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Size > 0); ++ gcmkVERIFY_ARGUMENT(Info != gcvNULL); ++ ++ do ++ { ++ info = (gcsPageInfo_PTR) Info; ++ ++ pages = info->pages; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): info=0x%X, pages=0x%X.", ++ __FUNCTION__, __LINE__, ++ info, pages ++ ); ++ ++ /* Invalid page array. */ ++ if (pages == gcvNULL && info->pageTable == gcvNULL) ++ { ++ kfree(info); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ memory = (gctUINTPTR_T)Memory; ++ end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ start = memory >> PAGE_SHIFT; ++ pageCount = end - start; ++ ++ /* Overflow. */ ++ if ((memory + Size) < memory) ++ { ++ gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); ++ return gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): memory: 0x%X, pageCount: %d, pageTable: 0x%X.", ++ __FUNCTION__, __LINE__, ++ memory, pageCount, info->pageTable ++ ); ++ ++ MEMORY_MAP_LOCK(Os); ++ ++ gcmkASSERT(info->pageTable != gcvNULL); ++ ++ if (info->extraPage) ++ { ++ pageCount += 1; ++ } ++ ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ /* Free the pages from the MMU. */ ++ gcmkERR_BREAK(gckVGMMU_FreePages(Os->device->kernels[Core]->vg->mmu, ++ info->pageTable, ++ pageCount * (PAGE_SIZE/4096) ++ )); ++ } ++ else ++#endif ++ { ++ /* Free the pages from the MMU. */ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkERR_BREAK(gckMMU_FreePagesEx(info->mmu, ++ info->address, ++ pageCount * (PAGE_SIZE/4096) ++ )); ++ ++#else ++ gcmkERR_BREAK(gckMMU_FreePages(Os->device->kernels[Core]->mmu, ++ info->pageTable, ++ pageCount * (PAGE_SIZE/4096) ++ )); ++#endif ++ ++ gcmkERR_BREAK(gckOS_UnmapPages( ++ Os, ++ pageCount * (PAGE_SIZE/4096), ++ info->address ++ )); ++ } ++ ++ if (info->extraPage) ++ { ++ pageCount -= 1; ++ info->extraPage = 0; ++ } ++ ++ /* Release the page cache. */ ++ if (pages) ++ { ++ for (i = 0; i < pageCount; i++) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_OS, ++ "%s(%d): pages[%d]: 0x%X.", ++ __FUNCTION__, __LINE__, ++ i, pages[i] ++ ); ++ ++ if (!PageReserved(pages[i])) ++ { ++ SetPageDirty(pages[i]); ++ } ++ ++ if (pfn_valid(page_to_pfn(pages[i]))) ++ { ++ page_cache_release(pages[i]); ++ } ++ } ++ } ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ if (info != gcvNULL) ++ { ++ /* Free the page array. */ ++ if (info->pages != gcvNULL) ++ { ++ kfree(info->pages); ++ } ++ ++ kfree(info); ++ } ++ ++ MEMORY_MAP_UNLOCK(Os); ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetBaseAddress ++** ++** Get the base address for the physical memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** OUTPUT: ++** ++** gctUINT32_PTR BaseAddress ++** Pointer to a variable that will receive the base address. ++*/ ++gceSTATUS ++gckOS_GetBaseAddress( ++ IN gckOS Os, ++ OUT gctUINT32_PTR BaseAddress ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); ++ ++ /* Return base address. */ ++ *BaseAddress = Os->device->baseAddress; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_SuspendInterrupt( ++ IN gckOS Os ++ ) ++{ ++ return gckOS_SuspendInterruptEx(Os, gcvCORE_MAJOR); ++} ++ ++gceSTATUS ++gckOS_SuspendInterruptEx( ++ IN gckOS Os, ++ IN gceCORE Core ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ disable_irq(Os->device->irqLines[Core]); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_ResumeInterrupt( ++ IN gckOS Os ++ ) ++{ ++ return gckOS_ResumeInterruptEx(Os, gcvCORE_MAJOR); ++} ++ ++gceSTATUS ++gckOS_ResumeInterruptEx( ++ IN gckOS Os, ++ IN gceCORE Core ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ enable_irq(Os->device->irqLines[Core]); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_MemCopy( ++ IN gctPOINTER Destination, ++ IN gctCONST_POINTER Source, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Destination=0x%X Source=0x%X Bytes=%lu", ++ Destination, Source, Bytes); ++ ++ gcmkVERIFY_ARGUMENT(Destination != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Source != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ memcpy(Destination, Source, Bytes); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_ZeroMemory( ++ IN gctPOINTER Memory, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gcmkHEADER_ARG("Memory=0x%X Bytes=%lu", Memory, Bytes); ++ ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ memset(Memory, 0, Bytes); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++********************************* Cache Control ******************************** ++*******************************************************************************/ ++ ++/******************************************************************************* ++** gckOS_CacheClean ++** ++** Clean the cache for the specified addresses. The GPU is going to need the ++** data. If the system is allocating memory as non-cachable, this function can ++** be ignored. ++** ++** ARGUMENTS: ++** ++** gckOS Os ++** Pointer to gckOS object. ++** ++** gctUINT32 ProcessID ++** Process ID Logical belongs. ++** ++** gctPHYS_ADDR Handle ++** Physical address handle. If gcvNULL it is video memory. ++** ++** gctPOINTER Physical ++** Physical address to flush. ++** ++** gctPOINTER Logical ++** Logical address to flush. ++** ++** gctSIZE_T Bytes ++** Size of the address range in bytes to flush. ++*/ ++gceSTATUS ++gckOS_CacheClean( ++ IN gckOS Os, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Handle, ++ IN gctUINT32 Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gcsPLATFORM * platform; ++ ++ gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu", ++ Os, ProcessID, Handle, Logical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ platform = Os->device->platform; ++ ++ if (platform && platform->ops->cache) ++ { ++ platform->ops->cache( ++ platform, ++ ProcessID, ++ Handle, ++ Physical, ++ Logical, ++ Bytes, ++ gcvCACHE_CLEAN ++ ); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ dma_sync_single_for_device( ++ Os->device->dev, ++ (dma_addr_t)Physical, ++ Bytes, ++ DMA_TO_DEVICE); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** gckOS_CacheInvalidate ++** ++** Invalidate the cache for the specified addresses. The GPU is going to need ++** data. If the system is allocating memory as non-cachable, this function can ++** be ignored. ++** ++** ARGUMENTS: ++** ++** gckOS Os ++** Pointer to gckOS object. ++** ++** gctUINT32 ProcessID ++** Process ID Logical belongs. ++** ++** gctPHYS_ADDR Handle ++** Physical address handle. If gcvNULL it is video memory. ++** ++** gctPOINTER Logical ++** Logical address to flush. ++** ++** gctSIZE_T Bytes ++** Size of the address range in bytes to flush. ++*/ ++gceSTATUS ++gckOS_CacheInvalidate( ++ IN gckOS Os, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Handle, ++ IN gctUINT32 Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gcsPLATFORM * platform; ++ ++ gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu", ++ Os, ProcessID, Handle, Logical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ platform = Os->device->platform; ++ ++ if (platform && platform->ops->cache) ++ { ++ platform->ops->cache( ++ platform, ++ ProcessID, ++ Handle, ++ Physical, ++ Logical, ++ Bytes, ++ gcvCACHE_INVALIDATE ++ ); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ dma_sync_single_for_device( ++ Os->device->dev, ++ (dma_addr_t)Physical, ++ Bytes, ++ DMA_FROM_DEVICE); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** gckOS_CacheFlush ++** ++** Clean the cache for the specified addresses and invalidate the lines as ++** well. The GPU is going to need and modify the data. If the system is ++** allocating memory as non-cachable, this function can be ignored. ++** ++** ARGUMENTS: ++** ++** gckOS Os ++** Pointer to gckOS object. ++** ++** gctUINT32 ProcessID ++** Process ID Logical belongs. ++** ++** gctPHYS_ADDR Handle ++** Physical address handle. If gcvNULL it is video memory. ++** ++** gctPOINTER Logical ++** Logical address to flush. ++** ++** gctSIZE_T Bytes ++** Size of the address range in bytes to flush. ++*/ ++gceSTATUS ++gckOS_CacheFlush( ++ IN gckOS Os, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Handle, ++ IN gctUINT32 Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gcsPLATFORM * platform; ++ ++ gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu", ++ Os, ProcessID, Handle, Logical, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Logical != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ ++ platform = Os->device->platform; ++ ++ if (platform && platform->ops->cache) ++ { ++ platform->ops->cache( ++ platform, ++ ProcessID, ++ Handle, ++ Physical, ++ Logical, ++ Bytes, ++ gcvCACHE_FLUSH ++ ); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ if (Physical != gcvINVALID_ADDRESS) ++ { ++ dma_sync_single_for_device( ++ Os->device->dev, ++ (dma_addr_t)Physical, ++ Bytes, ++ DMA_BIDIRECTIONAL); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++********************************* Broadcasting ********************************* ++*******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckOS_Broadcast ++** ++** System hook for broadcast events from the kernel driver. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** gceBROADCAST Reason ++** Reason for the broadcast. Can be one of the following values: ++** ++** gcvBROADCAST_GPU_IDLE ++** Broadcasted when the kernel driver thinks the GPU might be ++** idle. This can be used to handle power management. ++** ++** gcvBROADCAST_GPU_COMMIT ++** Broadcasted when any client process commits a command ++** buffer. This can be used to handle power management. ++** ++** gcvBROADCAST_GPU_STUCK ++** Broadcasted when the kernel driver hits the timeout waiting ++** for the GPU. ++** ++** gcvBROADCAST_FIRST_PROCESS ++** First process is trying to connect to the kernel. ++** ++** gcvBROADCAST_LAST_PROCESS ++** Last process has detached from the kernel. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_Broadcast( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gceBROADCAST Reason ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Hardware=0x%X Reason=%d", Os, Hardware, Reason); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ ++ switch (Reason) ++ { ++ case gcvBROADCAST_FIRST_PROCESS: ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached"); ++ break; ++ ++ case gcvBROADCAST_LAST_PROCESS: ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached"); ++ ++ /* Put GPU OFF. */ ++ gcmkONERROR( ++ gckHARDWARE_SetPowerManagementState(Hardware, ++ gcvPOWER_OFF_BROADCAST)); ++ break; ++ ++ case gcvBROADCAST_GPU_IDLE: ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle."); ++ ++ /* Put GPU IDLE. */ ++ gcmkONERROR( ++ gckHARDWARE_SetPowerManagementState(Hardware, ++#if gcdPOWER_SUSPEND_WHEN_IDLE ++ gcvPOWER_SUSPEND_BROADCAST)); ++#else ++ gcvPOWER_IDLE_BROADCAST)); ++#endif ++ ++ /* Add idle process DB. */ ++ gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel, ++ 1, ++ gcvDB_IDLE, ++ gcvNULL, gcvNULL, 0)); ++ break; ++ ++ case gcvBROADCAST_GPU_COMMIT: ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived."); ++ ++ /* Add busy process DB. */ ++ gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel, ++ 0, ++ gcvDB_IDLE, ++ gcvNULL, gcvNULL, 0)); ++ ++ /* Put GPU ON. */ ++ gcmkONERROR( ++ gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON_AUTO)); ++ break; ++ ++ case gcvBROADCAST_GPU_STUCK: ++ gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_GPU_STUCK\n"); ++ gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); ++ break; ++ ++ case gcvBROADCAST_AXI_BUS_ERROR: ++ gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_AXI_BUS_ERROR\n"); ++ gcmkONERROR(gckHARDWARE_DumpGPUState(Hardware)); ++ gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); ++ break; ++ ++ case gcvBROADCAST_OUT_OF_MEMORY: ++ gcmkTRACE_N(gcvLEVEL_INFO, 0, "gcvBROADCAST_OUT_OF_MEMORY\n"); ++ ++ status = _ShrinkMemory(Os); ++ ++ if (status == gcvSTATUS_NOT_SUPPORTED) ++ { ++ goto OnError; ++ } ++ ++ gcmkONERROR(status); ++ ++ break; ++ ++ default: ++ /* Skip unimplemented broadcast. */ ++ break; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_BroadcastHurry ++** ++** The GPU is running too slow. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** gctUINT Urgency ++** The higher the number, the higher the urgency to speed up the GPU. ++** The maximum value is defined by the gcdDYNAMIC_EVENT_THRESHOLD. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_BroadcastHurry( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gctUINT Urgency ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Urgency=%u", Os, Hardware, Urgency); ++ ++ /* Do whatever you need to do to speed up the GPU now. */ ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_BroadcastCalibrateSpeed ++** ++** Calibrate the speed of the GPU. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gckHARDWARE Hardware ++** Pointer to the gckHARDWARE object. ++** ++** gctUINT Idle, Time ++** Idle/Time will give the percentage the GPU is idle, so you can use ++** this to calibrate the working point of the GPU. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_BroadcastCalibrateSpeed( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gctUINT Idle, ++ IN gctUINT Time ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Idle=%u Time=%u", ++ Os, Hardware, Idle, Time); ++ ++ /* Do whatever you need to do to callibrate the GPU speed. */ ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++********************************** Semaphores ********************************** ++*******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckOS_CreateSemaphore ++** ++** Create a semaphore. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** OUTPUT: ++** ++** gctPOINTER * Semaphore ++** Pointer to the variable that will receive the created semaphore. ++*/ ++gceSTATUS ++gckOS_CreateSemaphore( ++ IN gckOS Os, ++ OUT gctPOINTER * Semaphore ++ ) ++{ ++ gceSTATUS status; ++ struct semaphore *sem = gcvNULL; ++ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ /* Allocate the semaphore structure. */ ++ sem = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN); ++ if (sem == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Initialize the semaphore. */ ++ sema_init(sem, 1); ++ ++ /* Return to caller. */ ++ *Semaphore = (gctPOINTER) sem; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_AcquireSemaphore ++** ++** Acquire a semaphore. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctPOINTER Semaphore ++** Pointer to the semaphore thet needs to be acquired. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AcquireSemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%08X Semaphore=0x%08X", Os, Semaphore); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ /* Acquire the semaphore. */ ++ if (down_interruptible((struct semaphore *) Semaphore)) ++ { ++ gcmkONWARNING(gcvSTATUS_INTERRUPTED); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_TryAcquireSemaphore ++** ++** Try to acquire a semaphore. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctPOINTER Semaphore ++** Pointer to the semaphore thet needs to be acquired. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_TryAcquireSemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%x", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ /* Acquire the semaphore. */ ++ if (down_trylock((struct semaphore *) Semaphore)) ++ { ++ /* Timeout. */ ++ status = gcvSTATUS_TIMEOUT; ++ gcmkFOOTER(); ++ return status; ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_ReleaseSemaphore ++** ++** Release a previously acquired semaphore. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctPOINTER Semaphore ++** Pointer to the semaphore thet needs to be released. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_ReleaseSemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ /* Release the semaphore. */ ++ up((struct semaphore *) Semaphore); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_DestroySemaphore ++** ++** Destroy a semaphore. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctPOINTER Semaphore ++** Pointer to the semaphore thet needs to be destroyed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_DestroySemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ /* Free the sempahore structure. */ ++ kfree(Semaphore); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetProcessID ++** ++** Get current process ID. ++** ++** INPUT: ++** ++** Nothing. ++** ++** OUTPUT: ++** ++** gctUINT32_PTR ProcessID ++** Pointer to the variable that receives the process ID. ++*/ ++gceSTATUS ++gckOS_GetProcessID( ++ OUT gctUINT32_PTR ProcessID ++ ) ++{ ++ /* Get process ID. */ ++ if (ProcessID != gcvNULL) ++ { ++ *ProcessID = _GetProcessID(); ++ } ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_GetThreadID ++** ++** Get current thread ID. ++** ++** INPUT: ++** ++** Nothing. ++** ++** OUTPUT: ++** ++** gctUINT32_PTR ThreadID ++** Pointer to the variable that receives the thread ID. ++*/ ++gceSTATUS ++gckOS_GetThreadID( ++ OUT gctUINT32_PTR ThreadID ++ ) ++{ ++ /* Get thread ID. */ ++ if (ThreadID != gcvNULL) ++ { ++ *ThreadID = _GetThreadID(); ++ } ++ ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_SetGPUPower ++** ++** Set the power of the GPU on or off. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gceCORE Core ++** GPU whose power is set. ++** ++** gctBOOL Clock ++** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. ++** ++** gctBOOL Power ++** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_SetGPUPower( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctBOOL Clock, ++ IN gctBOOL Power ++ ) ++{ ++ gcsPLATFORM * platform; ++ ++ gctBOOL powerChange = gcvFALSE; ++ gctBOOL clockChange = gcvFALSE; ++ ++ gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power); ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ platform = Os->device->platform; ++ ++ powerChange = (Power != Os->powerStates[Core]); ++ ++ clockChange = (Clock != Os->clockStates[Core]); ++ ++ if (powerChange && (Power == gcvTRUE)) ++ { ++ if (platform && platform->ops->setPower) ++ { ++ gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power)); ++ } ++ ++ Os->powerStates[Core] = Power; ++ } ++ ++ if (clockChange) ++ { ++ mutex_lock(&Os->registerAccessLocks[Core]); ++ ++ if (platform && platform->ops->setClock) ++ { ++ gcmkVERIFY_OK(platform->ops->setClock(platform, Core, Clock)); ++ } ++ ++ Os->clockStates[Core] = Clock; ++ ++ mutex_unlock(&Os->registerAccessLocks[Core]); ++ } ++ ++ if (powerChange && (Power == gcvFALSE)) ++ { ++ if (platform && platform->ops->setPower) ++ { ++ gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power)); ++ } ++ ++ Os->powerStates[Core] = Power; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_ResetGPU ++** ++** Reset the GPU. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gckCORE Core ++** GPU whose power is set. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_ResetGPU( ++ IN gckOS Os, ++ IN gceCORE Core ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED; ++ gcsPLATFORM * platform; ++ ++ gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core); ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ platform = Os->device->platform; ++ ++ if (platform && platform->ops->reset) ++ { ++ status = platform->ops->reset(platform, Core); ++ } ++ ++ gcmkFOOTER_NO(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_PrepareGPUFrequency ++** ++** Prepare to set GPU frequency and voltage. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gckCORE Core ++** GPU whose frequency and voltage will be set. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_PrepareGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core ++ ) ++{ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_FinishGPUFrequency ++** ++** Finish GPU frequency setting. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gckCORE Core ++** GPU whose frequency and voltage is set. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_FinishGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core ++ ) ++{ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_QueryGPUFrequency ++** ++** Query the current frequency of the GPU. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gckCORE Core ++** GPU whose power is set. ++** ++** gctUINT32 * Frequency ++** Pointer to a gctUINT32 to obtain current frequency, in MHz. ++** ++** gctUINT8 * Scale ++** Pointer to a gctUINT8 to obtain current scale(1 - 64). ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_QueryGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core, ++ OUT gctUINT32 * Frequency, ++ OUT gctUINT8 * Scale ++ ) ++{ ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_SetGPUFrequency ++** ++** Set frequency and voltage of the GPU. ++** ++** 1. DVFS manager gives the target scale of full frequency, BSP must find ++** a real frequency according to this scale and board's configure. ++** ++** 2. BSP should find a suitable voltage for this frequency. ++** ++** 3. BSP must make sure setting take effect before this function returns. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gckCORE Core ++** GPU whose power is set. ++** ++** gctUINT8 Scale ++** Target scale of full frequency, range is [1, 64]. 1 means 1/64 of ++** full frequency and 64 means 64/64 of full frequency. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_SetGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT8 Scale ++ ) ++{ ++ return gcvSTATUS_OK; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Profile --------------------------------------------------------------*/ ++ ++gceSTATUS ++gckOS_GetProfileTick( ++ OUT gctUINT64_PTR Tick ++ ) ++{ ++ struct timespec time; ++ ++ ktime_get_ts(&time); ++ ++ *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL; ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_QueryProfileTickRate( ++ OUT gctUINT64_PTR TickRate ++ ) ++{ ++ struct timespec res; ++ ++ hrtimer_get_res(CLOCK_MONOTONIC, &res); ++ ++ *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL; ++ ++ return gcvSTATUS_OK; ++} ++ ++gctUINT32 ++gckOS_ProfileToMS( ++ IN gctUINT64 Ticks ++ ) ++{ ++ return div_u64(Ticks, 1000000); ++} ++ ++/******************************************************************************\ ++******************************* Signal Management ****************************** ++\******************************************************************************/ ++ ++#undef _GC_OBJ_ZONE ++#define _GC_OBJ_ZONE gcvZONE_SIGNAL ++ ++/******************************************************************************* ++** ++** gckOS_CreateSignal ++** ++** Create a new signal. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctBOOL ManualReset ++** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in ++** order to set the signal to nonsignaled state. ++** If set to gcvFALSE, the signal will automatically be set to ++** nonsignaled state by gckOS_WaitSignal function. ++** ++** OUTPUT: ++** ++** gctSIGNAL * Signal ++** Pointer to a variable receiving the created gctSIGNAL. ++*/ ++gceSTATUS ++gckOS_CreateSignal( ++ IN gckOS Os, ++ IN gctBOOL ManualReset, ++ OUT gctSIGNAL * Signal ++ ) ++{ ++ gceSTATUS status; ++ gcsSIGNAL_PTR signal; ++ ++ gcmkHEADER_ARG("Os=0x%X ManualReset=%d", Os, ManualReset); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ /* Create an event structure. */ ++ signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL | gcdNOWARN); ++ ++ if (signal == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Save the process ID. */ ++ signal->process = (gctHANDLE)(gctUINTPTR_T) _GetProcessID(); ++ signal->manualReset = ManualReset; ++ signal->hardware = gcvNULL; ++ init_completion(&signal->obj); ++ atomic_set(&signal->ref, 1); ++ ++ gcmkONERROR(_AllocateIntegerId(&Os->signalDB, signal, &signal->id)); ++ ++ *Signal = (gctSIGNAL)(gctUINTPTR_T)signal->id; ++ ++ gcmkFOOTER_ARG("*Signal=0x%X", *Signal); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (signal != gcvNULL) ++ { ++ kfree(signal); ++ } ++ ++ gcmkFOOTER_NO(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_SignalQueryHardware( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ OUT gckHARDWARE * Hardware ++ ) ++{ ++ gceSTATUS status; ++ gcsSIGNAL_PTR signal; ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Hardware != gcvNULL); ++ ++ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); ++ ++ *Hardware = signal->hardware; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_SignalSetHardware( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gckHARDWARE Hardware ++ ) ++{ ++ gceSTATUS status; ++ gcsSIGNAL_PTR signal; ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); ++ ++ signal->hardware = Hardware; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_DestroySignal ++** ++** Destroy a signal. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIGNAL Signal ++** Pointer to the gctSIGNAL. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++static gceSTATUS ++gckOS_DestroySignalEx( ++ IN gckOS Os, ++ IN gctSIGNAL Signal ++ ) ++{ ++ gceSTATUS status; ++ gcsSIGNAL_PTR signal; ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); ++ ++ gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal); ++ ++ if (atomic_dec_and_test(&signal->ref)) ++ { ++ gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id)); ++ ++ /* Free the sgianl. */ ++ kfree(signal); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_DestroySignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ gcmkONERROR(gckOS_DestroySignalEx(Os, Signal)); ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex)); ++ acquired = gcvFALSE; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_Signal ++** ++** Set a state of the specified signal. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIGNAL Signal ++** Pointer to the gctSIGNAL. ++** ++** gctBOOL State ++** If gcvTRUE, the signal will be set to signaled state. ++** If gcvFALSE, the signal will be set to nonsignaled state. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++static gceSTATUS ++gckOS_SignalEx( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctBOOL State ++ ) ++{ ++ gceSTATUS status; ++ gcsSIGNAL_PTR signal; ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); ++ ++ gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal); ++ ++ if (State) ++ { ++ /* unbind the signal from hardware. */ ++ signal->hardware = gcvNULL; ++ ++ /* Set the event to a signaled state. */ ++ complete(&signal->obj); ++ } ++ else ++ { ++ /* Set the event to an unsignaled state. */ ++ reinit_completion(&signal->obj); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_Signal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctBOOL State ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ gcmkONERROR(gckOS_SignalEx(Os, Signal, State)); ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex)); ++ acquired = gcvFALSE; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if gcdENABLE_VG ++gceSTATUS ++gckOS_SetSignalVG( ++ IN gckOS Os, ++ IN gctHANDLE Process, ++ IN gctSIGNAL Signal ++ ) ++{ ++ gceSTATUS status; ++ gctINT result; ++ struct task_struct * userTask; ++ struct siginfo info; ++ ++ userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process); ++ ++ if (userTask != gcvNULL) ++ { ++ info.si_signo = 48; ++ info.si_code = __SI_CODE(__SI_RT, SI_KERNEL); ++ info.si_pid = 0; ++ info.si_uid = 0; ++ info.si_ptr = (gctPOINTER) Signal; ++ ++ /* Signals with numbers between 32 and 63 are real-time, ++ send a real-time signal to the user process. */ ++ result = send_sig_info(48, &info, userTask); ++ ++ printk("gckOS_SetSignalVG:0x%x\n", result); ++ /* Error? */ ++ if (result < 0) ++ { ++ status = gcvSTATUS_GENERIC_IO; ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): an error has occurred.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ else ++ { ++ status = gcvSTATUS_OK; ++ } ++ } ++ else ++ { ++ status = gcvSTATUS_GENERIC_IO; ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): an error has occurred.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ ++ /* Return status. */ ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckOS_UserSignal ++** ++** Set the specified signal which is owned by a process to signaled state. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIGNAL Signal ++** Pointer to the gctSIGNAL. ++** ++** gctHANDLE Process ++** Handle of process owning the signal. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_UserSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctHANDLE Process ++ ) ++{ ++ gceSTATUS status; ++ gctSIGNAL signal; ++ gctBOOL acquired = gcvFALSE; ++ gctBOOL user = (Process != gcvNULL); ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d", ++ Os, Signal, (gctINT32)(gctUINTPTR_T)Process); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ if (user) ++ { ++ /* Map the signal into kernel space. */ ++ gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal)); ++ ++ /* Signal. */ ++ gcmkONERROR(gckOS_SignalEx(Os, signal, gcvTRUE)); ++ ++ /* Unmap the signal */ ++ gcmkVERIFY_OK(gckOS_UnmapSignal(Os, Signal)); ++ } else { ++ /* Signal. */ ++ gcmkONERROR(gckOS_SignalEx(Os, Signal, gcvTRUE)); ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER(); ++ return status; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_WaitSignal ++** ++** Wait for a signal to become signaled. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIGNAL Signal ++** Pointer to the gctSIGNAL. ++** ++** gctUINT32 Wait ++** Number of milliseconds to wait. ++** Pass the value of gcvINFINITE for an infinite wait. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_WaitSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctUINT32 Wait ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gcsSIGNAL_PTR signal; ++ ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ ++ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); ++ ++ gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal); ++ ++ might_sleep(); ++ ++ spin_lock_irq(&signal->obj.wait.lock); ++ ++ if (signal->obj.done) ++ { ++ if (!signal->manualReset) ++ { ++ signal->obj.done = 0; ++ } ++ ++ status = gcvSTATUS_OK; ++ } ++ else if (Wait == 0) ++ { ++ status = gcvSTATUS_TIMEOUT; ++ } ++ else ++ { ++ /* Convert wait to milliseconds. */ ++ long timeout = (Wait == gcvINFINITE) ++ ? MAX_SCHEDULE_TIMEOUT ++ : Wait * HZ / 1000; ++ ++ DECLARE_WAITQUEUE(wait, current); ++ wait.flags |= WQ_FLAG_EXCLUSIVE; ++ __add_wait_queue_tail(&signal->obj.wait, &wait); ++ ++ while (gcvTRUE) ++ { ++ if (signal_pending(current)) ++ { ++ /* Interrupt received. */ ++ status = gcvSTATUS_INTERRUPTED; ++ break; ++ } ++ ++ __set_current_state(TASK_INTERRUPTIBLE); ++ spin_unlock_irq(&signal->obj.wait.lock); ++ timeout = schedule_timeout(timeout); ++ spin_lock_irq(&signal->obj.wait.lock); ++ ++ if (signal->obj.done) ++ { ++ if (!signal->manualReset) ++ { ++ signal->obj.done = 0; ++ } ++ ++ status = gcvSTATUS_OK; ++ break; ++ } ++ ++ if (timeout == 0) ++ { ++ ++ status = gcvSTATUS_TIMEOUT; ++ break; ++ } ++ } ++ ++ __remove_wait_queue(&signal->obj.wait, &wait); ++ } ++ ++ spin_unlock_irq(&signal->obj.wait.lock); ++ ++OnError: ++ /* Return status. */ ++ gcmkFOOTER_ARG("Signal=0x%X status=%d", Signal, status); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_MapSignal ++** ++** Map a signal in to the current process space. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIGNAL Signal ++** Pointer to tha gctSIGNAL to map. ++** ++** gctHANDLE Process ++** Handle of process owning the signal. ++** ++** OUTPUT: ++** ++** gctSIGNAL * MappedSignal ++** Pointer to a variable receiving the mapped gctSIGNAL. ++*/ ++gceSTATUS ++gckOS_MapSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctHANDLE Process, ++ OUT gctSIGNAL * MappedSignal ++ ) ++{ ++ gceSTATUS status; ++ gcsSIGNAL_PTR signal; ++ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process); ++ ++ gcmkVERIFY_ARGUMENT(Signal != gcvNULL); ++ gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL); ++ ++ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); ++ ++ if(atomic_inc_return(&signal->ref) <= 1) ++ { ++ /* The previous value is 0, it has been deleted. */ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ *MappedSignal = (gctSIGNAL) Signal; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER_NO(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_UnmapSignal ++** ++** Unmap a signal . ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctSIGNAL Signal ++** Pointer to that gctSIGNAL mapped. ++*/ ++gceSTATUS ++gckOS_UnmapSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal ++ ) ++{ ++ return gckOS_DestroySignalEx(Os, Signal); ++} ++ ++/******************************************************************************* ++** ++** gckOS_CreateUserSignal ++** ++** Create a new signal to be used in the user space. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctBOOL ManualReset ++** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in ++** order to set the signal to nonsignaled state. ++** If set to gcvFALSE, the signal will automatically be set to ++** nonsignaled state by gckOS_WaitSignal function. ++** ++** OUTPUT: ++** ++** gctINT * SignalID ++** Pointer to a variable receiving the created signal's ID. ++*/ ++gceSTATUS ++gckOS_CreateUserSignal( ++ IN gckOS Os, ++ IN gctBOOL ManualReset, ++ OUT gctINT * SignalID ++ ) ++{ ++ gceSTATUS status; ++ gctSIZE_T signal; ++ ++ /* Create a new signal. */ ++ gcmkONERROR(gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal)); ++ *SignalID = (gctINT) signal; ++ ++OnError: ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_DestroyUserSignal ++** ++** Destroy a signal to be used in the user space. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctINT SignalID ++** The signal's ID. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_DestroyUserSignal( ++ IN gckOS Os, ++ IN gctINT SignalID ++ ) ++{ ++ return gckOS_DestroySignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID); ++} ++ ++/******************************************************************************* ++** ++** gckOS_WaitUserSignal ++** ++** Wait for a signal used in the user mode to become signaled. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctINT SignalID ++** Signal ID. ++** ++** gctUINT32 Wait ++** Number of milliseconds to wait. ++** Pass the value of gcvINFINITE for an infinite wait. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_WaitUserSignal( ++ IN gckOS Os, ++ IN gctINT SignalID, ++ IN gctUINT32 Wait ++ ) ++{ ++ return gckOS_WaitSignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, Wait); ++} ++ ++/******************************************************************************* ++** ++** gckOS_SignalUserSignal ++** ++** Set a state of the specified signal to be used in the user space. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctINT SignalID ++** SignalID. ++** ++** gctBOOL State ++** If gcvTRUE, the signal will be set to signaled state. ++** If gcvFALSE, the signal will be set to nonsignaled state. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_SignalUserSignal( ++ IN gckOS Os, ++ IN gctINT SignalID, ++ IN gctBOOL State ++ ) ++{ ++ return gckOS_Signal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, State); ++} ++ ++#if gcdENABLE_VG ++gceSTATUS ++gckOS_CreateSemaphoreVG( ++ IN gckOS Os, ++ OUT gctSEMAPHORE * Semaphore ++ ) ++{ ++ gceSTATUS status; ++ struct semaphore * newSemaphore; ++ ++ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ do ++ { ++ /* Allocate the semaphore structure. */ ++ newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN); ++ if (newSemaphore == gcvNULL) ++ { ++ gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Initialize the semaphore. */ ++ sema_init(newSemaphore, 0); ++ ++ /* Set the handle. */ ++ * Semaphore = (gctSEMAPHORE) newSemaphore; ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++ ++gceSTATUS ++gckOS_IncrementSemaphore( ++ IN gckOS Os, ++ IN gctSEMAPHORE Semaphore ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ /* Increment the semaphore's count. */ ++ up((struct semaphore *) Semaphore); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_DecrementSemaphore( ++ IN gckOS Os, ++ IN gctSEMAPHORE Semaphore ++ ) ++{ ++ gceSTATUS status; ++ gctINT result; ++ ++ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); ++ ++ do ++ { ++ /* Decrement the semaphore's count. If the count is zero, wait ++ until it gets incremented. */ ++ result = down_interruptible((struct semaphore *) Semaphore); ++ ++ /* Signal received? */ ++ if (result != 0) ++ { ++ status = gcvSTATUS_TERMINATE; ++ break; ++ } ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_SetSignal ++** ++** Set the specified signal to signaled state. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctHANDLE Process ++** Handle of process owning the signal. ++** ++** gctSIGNAL Signal ++** Pointer to the gctSIGNAL. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_SetSignal( ++ IN gckOS Os, ++ IN gctHANDLE Process, ++ IN gctSIGNAL Signal ++ ) ++{ ++ gceSTATUS status; ++ gctINT result; ++ struct task_struct * userTask; ++ struct siginfo info; ++ ++ userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process); ++ ++ if (userTask != gcvNULL) ++ { ++ info.si_signo = 48; ++ info.si_code = __SI_CODE(__SI_RT, SI_KERNEL); ++ info.si_pid = 0; ++ info.si_uid = 0; ++ info.si_ptr = (gctPOINTER) Signal; ++ ++ /* Signals with numbers between 32 and 63 are real-time, ++ send a real-time signal to the user process. */ ++ result = send_sig_info(48, &info, userTask); ++ ++ /* Error? */ ++ if (result < 0) ++ { ++ status = gcvSTATUS_GENERIC_IO; ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): an error has occurred.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ else ++ { ++ status = gcvSTATUS_OK; ++ } ++ } ++ else ++ { ++ status = gcvSTATUS_GENERIC_IO; ++ ++ gcmkTRACE( ++ gcvLEVEL_ERROR, ++ "%s(%d): an error has occurred.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++/******************************************************************************\ ++******************************** Thread Object ********************************* ++\******************************************************************************/ ++ ++gceSTATUS ++gckOS_StartThread( ++ IN gckOS Os, ++ IN gctTHREADFUNC ThreadFunction, ++ IN gctPOINTER ThreadParameter, ++ OUT gctTHREAD * Thread ++ ) ++{ ++ gceSTATUS status; ++ struct task_struct * thread; ++ ++ gcmkHEADER_ARG("Os=0x%X ", Os); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Thread != gcvNULL); ++ ++ do ++ { ++ /* Create the thread. */ ++ thread = kthread_create( ++ ThreadFunction, ++ ThreadParameter, ++ "Vivante Kernel Thread" ++ ); ++ ++ /* Failed? */ ++ if (IS_ERR(thread)) ++ { ++ status = gcvSTATUS_GENERIC_IO; ++ break; ++ } ++ ++ /* Start the thread. */ ++ wake_up_process(thread); ++ ++ /* Set the thread handle. */ ++ * Thread = (gctTHREAD) thread; ++ ++ /* Success. */ ++ status = gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ /* Return the status. */ ++ return status; ++} ++ ++gceSTATUS ++gckOS_StopThread( ++ IN gckOS Os, ++ IN gctTHREAD Thread ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Thread != gcvNULL); ++ ++ /* Thread should have already been enabled to terminate. */ ++ kthread_stop((struct task_struct *) Thread); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_VerifyThread( ++ IN gckOS Os, ++ IN gctTHREAD Thread ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Thread != gcvNULL); ++ ++ gcmkFOOTER_NO(); ++ /* Success. */ ++ return gcvSTATUS_OK; ++} ++#endif ++ ++/******************************************************************************\ ++******************************** Software Timer ******************************** ++\******************************************************************************/ ++ ++void ++_TimerFunction( ++ struct work_struct * work ++ ) ++{ ++ gcsOSTIMER_PTR timer = (gcsOSTIMER_PTR)work; ++ ++ gctTIMERFUNCTION function = timer->function; ++ ++ function(timer->data); ++} ++ ++/******************************************************************************* ++** ++** gckOS_CreateTimer ++** ++** Create a software timer. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctTIMERFUNCTION Function. ++** Pointer to a call back function which will be called when timer is ++** expired. ++** ++** gctPOINTER Data. ++** Private data which will be passed to call back function. ++** ++** OUTPUT: ++** ++** gctPOINTER * Timer ++** Pointer to a variable receiving the created timer. ++*/ ++gceSTATUS ++gckOS_CreateTimer( ++ IN gckOS Os, ++ IN gctTIMERFUNCTION Function, ++ IN gctPOINTER Data, ++ OUT gctPOINTER * Timer ++ ) ++{ ++ gceSTATUS status; ++ gcsOSTIMER_PTR pointer; ++ gcmkHEADER_ARG("Os=0x%X Function=0x%X Data=0x%X", Os, Function, Data); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Timer != gcvNULL); ++ ++ gcmkONERROR(gckOS_Allocate(Os, sizeof(gcsOSTIMER), (gctPOINTER)&pointer)); ++ ++ pointer->function = Function; ++ pointer->data = Data; ++ ++ INIT_DELAYED_WORK(&pointer->work, _TimerFunction); ++ ++ *Timer = pointer; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckOS_DestroyTimer ++** ++** Destory a software timer. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctPOINTER Timer ++** Pointer to the timer to be destoryed. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_DestroyTimer( ++ IN gckOS Os, ++ IN gctPOINTER Timer ++ ) ++{ ++ gcsOSTIMER_PTR timer; ++ gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer); ++ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Timer != gcvNULL); ++ ++ timer = (gcsOSTIMER_PTR)Timer; ++ ++ cancel_delayed_work_sync(&timer->work); ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, Timer)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_StartTimer ++** ++** Schedule a software timer. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctPOINTER Timer ++** Pointer to the timer to be scheduled. ++** ++** gctUINT32 Delay ++** Delay in milliseconds. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_StartTimer( ++ IN gckOS Os, ++ IN gctPOINTER Timer, ++ IN gctUINT32 Delay ++ ) ++{ ++ gcsOSTIMER_PTR timer; ++ ++ gcmkHEADER_ARG("Os=0x%X Timer=0x%X Delay=%u", Os, Timer, Delay); ++ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Timer != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Delay != 0); ++ ++ timer = (gcsOSTIMER_PTR)Timer; ++ ++ mod_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay)); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_StopTimer ++** ++** Cancel a unscheduled timer. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to the gckOS object. ++** ++** gctPOINTER Timer ++** Pointer to the timer to be cancel. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_StopTimer( ++ IN gckOS Os, ++ IN gctPOINTER Timer ++ ) ++{ ++ gcsOSTIMER_PTR timer; ++ gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer); ++ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Timer != gcvNULL); ++ ++ timer = (gcsOSTIMER_PTR)Timer; ++ ++ cancel_delayed_work(&timer->work); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_GetProcessNameByPid( ++ IN gctINT Pid, ++ IN gctSIZE_T Length, ++ OUT gctUINT8_PTR String ++ ) ++{ ++ struct task_struct *task; ++ ++ /* Get the task_struct of the task with pid. */ ++ rcu_read_lock(); ++ ++ task = FIND_TASK_BY_PID(Pid); ++ ++ if (task == gcvNULL) ++ { ++ rcu_read_unlock(); ++ return gcvSTATUS_NOT_FOUND; ++ } ++ ++ /* Get name of process. */ ++ strncpy(String, task->comm, Length); ++ ++ rcu_read_unlock(); ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_DumpCallStack( ++ IN gckOS Os ++ ) ++{ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ dump_stack(); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckOS_DetectProcessByName ++** ++** task->comm maybe part of process name, so this function ++** can only be used for debugging. ++** ++** INPUT: ++** ++** gctCONST_POINTER Name ++** Pointer to a string to hold name to be check. If the length ++** of name is longer than TASK_COMM_LEN (16), use part of name ++** to detect. ++** ++** OUTPUT: ++** ++** gcvSTATUS_TRUE if name of current process matches Name. ++** ++*/ ++gceSTATUS ++gckOS_DetectProcessByName( ++ IN gctCONST_POINTER Name ++ ) ++{ ++ char comm[sizeof(current->comm)]; ++ ++ memset(comm, 0, sizeof(comm)); ++ ++ gcmkVERIFY_OK( ++ gckOS_GetProcessNameByPid(_GetProcessID(), sizeof(current->comm), comm)); ++ ++ return strstr(comm, Name) ? gcvSTATUS_TRUE ++ : gcvSTATUS_FALSE; ++} ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ ++gceSTATUS ++gckOS_CreateSyncPoint( ++ IN gckOS Os, ++ OUT gctSYNC_POINT * SyncPoint ++ ) ++{ ++ gceSTATUS status; ++ gcsSYNC_POINT_PTR syncPoint; ++ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ ++ /* Create an sync point structure. */ ++ syncPoint = (gcsSYNC_POINT_PTR) kmalloc( ++ sizeof(gcsSYNC_POINT), GFP_KERNEL | gcdNOWARN); ++ ++ if (syncPoint == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Initialize the sync point. */ ++ atomic_set(&syncPoint->ref, 1); ++ atomic_set(&syncPoint->state, 0); ++ ++ gcmkONERROR(_AllocateIntegerId(&Os->syncPointDB, syncPoint, &syncPoint->id)); ++ ++ *SyncPoint = (gctSYNC_POINT)(gctUINTPTR_T)syncPoint->id; ++ ++ gcmkFOOTER_ARG("*SyncPonint=%d", syncPoint->id); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (syncPoint != gcvNULL) ++ { ++ kfree(syncPoint); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_ReferenceSyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint ++ ) ++{ ++ gceSTATUS status; ++ gcsSYNC_POINT_PTR syncPoint; ++ ++ gcmkHEADER_ARG("Os=0x%X", Os); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL); ++ ++ gcmkONERROR( ++ _QueryIntegerId(&Os->syncPointDB, ++ (gctUINT32)(gctUINTPTR_T)SyncPoint, ++ (gctPOINTER)&syncPoint)); ++ ++ /* Initialize the sync point. */ ++ atomic_inc(&syncPoint->ref); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_DestroySyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint ++ ) ++{ ++ gceSTATUS status; ++ gcsSYNC_POINT_PTR syncPoint; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Os, Os->syncPointMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ gcmkONERROR( ++ _QueryIntegerId(&Os->syncPointDB, ++ (gctUINT32)(gctUINTPTR_T)SyncPoint, ++ (gctPOINTER)&syncPoint)); ++ ++ gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint); ++ ++ if (atomic_dec_and_test(&syncPoint->ref)) ++ { ++ gcmkVERIFY_OK(_DestroyIntegerId(&Os->syncPointDB, syncPoint->id)); ++ ++ /* Free the sgianl. */ ++ syncPoint->timeline = gcvNULL; ++ kfree(syncPoint); ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex)); ++ acquired = gcvFALSE; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_SignalSyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint ++ ) ++{ ++ gceSTATUS status; ++ gcsSYNC_POINT_PTR syncPoint; ++ struct sync_timeline * timeline; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Os, Os->syncPointMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ gcmkONERROR( ++ _QueryIntegerId(&Os->syncPointDB, ++ (gctUINT32)(gctUINTPTR_T)SyncPoint, ++ (gctPOINTER)&syncPoint)); ++ ++ gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint); ++ ++ /* Set signaled state. */ ++ atomic_set(&syncPoint->state, 1); ++ ++ /* Get parent timeline. */ ++ timeline = syncPoint->timeline; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex)); ++ acquired = gcvFALSE; ++ ++ /* Signal timeline. */ ++ if (timeline) ++ { ++ sync_timeline_signal(timeline); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_QuerySyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint, ++ OUT gctBOOL_PTR State ++ ) ++{ ++ gceSTATUS status; ++ gcsSYNC_POINT_PTR syncPoint; ++ ++ gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL); ++ ++ gcmkONERROR( ++ _QueryIntegerId(&Os->syncPointDB, ++ (gctUINT32)(gctUINTPTR_T)SyncPoint, ++ (gctPOINTER)&syncPoint)); ++ ++ gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint); ++ ++ /* Get state. */ ++ *State = atomic_read(&syncPoint->state); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*State=%d", *State); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckOS_CreateSyncTimeline( ++ IN gckOS Os, ++ OUT gctHANDLE * Timeline ++ ) ++{ ++ struct viv_sync_timeline * timeline; ++ ++ /* Create viv sync timeline. */ ++ timeline = viv_sync_timeline_create("viv timeline", Os); ++ ++ if (timeline == gcvNULL) ++ { ++ /* Out of memory. */ ++ return gcvSTATUS_OUT_OF_MEMORY; ++ } ++ ++ *Timeline = (gctHANDLE) timeline; ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_DestroySyncTimeline( ++ IN gckOS Os, ++ IN gctHANDLE Timeline ++ ) ++{ ++ struct viv_sync_timeline * timeline; ++ gcmkASSERT(Timeline != gcvNULL); ++ ++ /* Destroy timeline. */ ++ timeline = (struct viv_sync_timeline *) Timeline; ++ sync_timeline_destroy(&timeline->obj); ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_CreateNativeFence( ++ IN gckOS Os, ++ IN gctHANDLE Timeline, ++ IN gctSYNC_POINT SyncPoint, ++ OUT gctINT * FenceFD ++ ) ++{ ++ int fd = -1; ++ struct viv_sync_timeline *timeline; ++ struct sync_pt * pt = gcvNULL; ++ struct sync_fence * fence; ++ char name[32]; ++ gcsSYNC_POINT_PTR syncPoint; ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Os=0x%X Timeline=0x%X SyncPoint=%d", ++ Os, Timeline, (gctUINT)(gctUINTPTR_T)SyncPoint); ++ ++ gcmkONERROR( ++ _QueryIntegerId(&Os->syncPointDB, ++ (gctUINT32)(gctUINTPTR_T)SyncPoint, ++ (gctPOINTER)&syncPoint)); ++ ++ /* Cast timeline. */ ++ timeline = (struct viv_sync_timeline *) Timeline; ++ ++ fd = get_unused_fd(); ++ ++ if (fd < 0) ++ { ++ /* Out of resources. */ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ /* Create viv_sync_pt. */ ++ pt = viv_sync_pt_create(timeline, SyncPoint); ++ ++ if (pt == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Reference sync_timeline. */ ++ syncPoint->timeline = &timeline->obj; ++ ++ /* Build fence name. */ ++ snprintf(name, 32, "viv sync_fence-%u", (gctUINT)(gctUINTPTR_T)SyncPoint); ++ ++ /* Create sync_fence. */ ++ fence = sync_fence_create(name, pt); ++ ++ if (fence == NULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ /* Install fence to fd. */ ++ sync_fence_install(fence, fd); ++ ++ *FenceFD = fd; ++ gcmkFOOTER_ARG("*FenceFD=%d", fd); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Error roll back. */ ++ if (pt) ++ { ++ sync_pt_free(pt); ++ } ++ ++ if (fd > 0) ++ { ++ put_unused_fd(fd); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++gceSTATUS ++gckOS_CPUPhysicalToGPUPhysical( ++ IN gckOS Os, ++ IN gctUINT32 CPUPhysical, ++ IN gctUINT32_PTR GPUPhysical ++ ) ++{ ++ gcsPLATFORM * platform; ++ gcmkHEADER_ARG("CPUPhysical=0x%X", CPUPhysical); ++ ++ platform = Os->device->platform; ++ ++ if (platform && platform->ops->getGPUPhysical) ++ { ++ gcmkVERIFY_OK( ++ platform->ops->getGPUPhysical(platform, CPUPhysical, GPUPhysical)); ++ } ++ else ++ { ++ *GPUPhysical = CPUPhysical; ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_GPUPhysicalToCPUPhysical( ++ IN gckOS Os, ++ IN gctUINT32 GPUPhysical, ++ IN gctUINT32_PTR CPUPhysical ++ ) ++{ ++ gcmkHEADER_ARG("GPUPhysical=0x%X", GPUPhysical); ++ ++ *CPUPhysical = GPUPhysical; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckOS_PhysicalToPhysicalAddress( ++ IN gckOS Os, ++ IN gctPOINTER Physical, ++ OUT gctUINT32 * PhysicalAddress ++ ) ++{ ++ PLINUX_MDL mdl = (PLINUX_MDL)Physical; ++ gckALLOCATOR allocator = mdl->allocator; ++ ++ if (allocator) ++ { ++ return allocator->ops->Physical(allocator, mdl, 0, PhysicalAddress); ++ } ++ ++ return gcvSTATUS_NOT_SUPPORTED; ++} ++ ++gceSTATUS ++gckOS_QueryOption( ++ IN gckOS Os, ++ IN gctCONST_STRING Option, ++ OUT gctUINT32 * Value ++ ) ++{ ++ gckGALDEVICE device = Os->device; ++ ++ if (!strcmp(Option, "physBase")) ++ { ++ *Value = device->physBase; ++ return gcvSTATUS_OK; ++ } ++ else if (!strcmp(Option, "physSize")) ++ { ++ *Value = device->physSize; ++ return gcvSTATUS_OK; ++ } ++ else if (!strcmp(Option, "mmu")) ++ { ++ *Value = device->mmu; ++ return gcvSTATUS_OK; ++ } ++ ++ return gcvSTATUS_NOT_SUPPORTED; ++} ++ ++static int ++fd_release( ++ struct inode *inode, ++ struct file *file ++ ) ++{ ++ gcsFDPRIVATE_PTR private = (gcsFDPRIVATE_PTR)file->private_data; ++ ++ if (private && private->release) ++ { ++ return private->release(private); ++ } ++ ++ return 0; ++} ++ ++static const struct file_operations fd_fops = { ++ .release = fd_release, ++}; ++ ++gceSTATUS ++gckOS_GetFd( ++ IN gctSTRING Name, ++ IN gcsFDPRIVATE_PTR Private, ++ OUT gctINT *Fd ++ ) ++{ ++ *Fd = anon_inode_getfd(Name, &fd_fops, Private, O_RDWR); ++ ++ if (*Fd < 0) ++ { ++ return gcvSTATUS_OUT_OF_RESOURCES; ++ } ++ ++ return gcvSTATUS_OK; ++} +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_os.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_os.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_os.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_os.h 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,88 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_os_h_ ++#define __gc_hal_kernel_os_h_ ++ ++typedef struct _LINUX_MDL_MAP ++{ ++ gctINT pid; ++ gctPOINTER vmaAddr; ++ gctUINT32 count; ++ struct vm_area_struct * vma; ++ struct _LINUX_MDL_MAP * next; ++} ++LINUX_MDL_MAP; ++ ++typedef struct _LINUX_MDL_MAP * PLINUX_MDL_MAP; ++ ++typedef struct _LINUX_MDL ++{ ++ char * addr; ++ ++ union _pages ++ { ++ /* Pointer to a array of pages. */ ++ struct page * contiguousPages; ++ /* Pointer to a array of pointers to page. */ ++ struct page ** nonContiguousPages; ++ } ++ u; ++ ++#ifdef NO_DMA_COHERENT ++ gctPOINTER kaddr; ++#endif /* NO_DMA_COHERENT */ ++ ++ gctINT numPages; ++ gctINT pagedMem; ++ gctBOOL contiguous; ++ gctBOOL exact; ++ dma_addr_t dmaHandle; ++ PLINUX_MDL_MAP maps; ++ struct _LINUX_MDL * prev; ++ struct _LINUX_MDL * next; ++ ++ /* Pointer to allocator which allocates memory for this mdl. */ ++ void * allocator; ++ ++ /* Private data used by allocator. */ ++ void * priv; ++ ++ uint gid; ++} ++LINUX_MDL, *PLINUX_MDL; ++ ++extern PLINUX_MDL_MAP ++FindMdlMap( ++ IN PLINUX_MDL Mdl, ++ IN gctINT PID ++ ); ++ ++typedef struct _DRIVER_ARGS ++{ ++ gctUINT64 InputBuffer; ++ gctUINT64 InputBufferSize; ++ gctUINT64 OutputBuffer; ++ gctUINT64 OutputBufferSize; ++} ++DRIVER_ARGS; ++ ++#endif /* __gc_hal_kernel_os_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_platform.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_platform.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_platform.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_platform.h 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,270 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef _gc_hal_kernel_platform_h_ ++#define _gc_hal_kernel_platform_h_ ++#include ++ ++typedef struct _gcsMODULE_PARAMETERS ++{ ++ gctINT irqLine; ++ gctUINT registerMemBase; ++ gctUINT registerMemSize; ++ gctINT irqLine2D; ++ gctUINT registerMemBase2D; ++ gctUINT registerMemSize2D; ++ gctINT irqLineVG; ++ gctUINT registerMemBaseVG; ++ gctUINT registerMemSizeVG; ++ gctUINT contiguousSize; ++ gctUINT contiguousBase; ++ gctUINT contiguousRequested; ++ gctUINT bankSize; ++ gctINT fastClear; ++ gctINT compression; ++ gctINT powerManagement; ++ gctINT gpuProfiler; ++ gctINT signal; ++ gctUINT baseAddress; ++ gctUINT physSize; ++ gctUINT logFileSize; ++ gctUINT recovery; ++ gctUINT stuckDump; ++ gctUINT showArgs; ++ gctUINT gpu3DMinClock; ++} ++gcsMODULE_PARAMETERS; ++ ++typedef struct _gcsPLATFORM * gckPLATFORM; ++ ++typedef struct _gcsPLATFORM_OPERATIONS ++{ ++ /******************************************************************************* ++ ** ++ ** needAddDevice ++ ** ++ ** Determine whether platform_device is created by initialization code. ++ ** If platform_device is created by BSP, return gcvFLASE here. ++ */ ++ gctBOOL ++ (*needAddDevice)( ++ IN gckPLATFORM Platform ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** adjustParam ++ ** ++ ** Override content of arguments, if a argument is not changed here, it will ++ ** keep as default value or value set by insmod command line. ++ */ ++ gceSTATUS ++ (*adjustParam)( ++ IN gckPLATFORM Platform, ++ OUT gcsMODULE_PARAMETERS *Args ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** adjustDriver ++ ** ++ ** Override content of platform_driver which will be registered. ++ */ ++ gceSTATUS ++ (*adjustDriver)( ++ IN gckPLATFORM Platform ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** getPower ++ ** ++ ** Prepare power and clock operation. ++ */ ++ gceSTATUS ++ (*getPower)( ++ IN gckPLATFORM Platform ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** putPower ++ ** ++ ** Finish power and clock operation. ++ */ ++ gceSTATUS ++ (*putPower)( ++ IN gckPLATFORM Platform ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** allocPriv ++ ** ++ ** Construct platform private data. ++ */ ++ gceSTATUS ++ (*allocPriv)( ++ IN gckPLATFORM Platform ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** freePriv ++ ** ++ ** free platform private data. ++ */ ++ gceSTATUS ++ (*freePriv)( ++ IN gckPLATFORM Platform ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** setPower ++ ** ++ ** Set power state of specified GPU. ++ ** ++ ** INPUT: ++ ** ++ ** gceCORE GPU ++ ** GPU neeed to config. ++ ** ++ ** gceBOOL Enable ++ ** Enable or disable power. ++ */ ++ gceSTATUS ++ (*setPower)( ++ IN gckPLATFORM Platform, ++ IN gceCORE GPU, ++ IN gctBOOL Enable ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** setClock ++ ** ++ ** Set clock state of specified GPU. ++ ** ++ ** INPUT: ++ ** ++ ** gceCORE GPU ++ ** GPU neeed to config. ++ ** ++ ** gceBOOL Enable ++ ** Enable or disable clock. ++ */ ++ gceSTATUS ++ (*setClock)( ++ IN gckPLATFORM Platform, ++ IN gceCORE GPU, ++ IN gctBOOL Enable ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** reset ++ ** ++ ** Reset GPU outside. ++ ** ++ ** INPUT: ++ ** ++ ** gceCORE GPU ++ ** GPU neeed to reset. ++ */ ++ gceSTATUS ++ (*reset)( ++ IN gckPLATFORM Platform, ++ IN gceCORE GPU ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** getGPUPhysical ++ ** ++ ** Convert CPU physical address to GPU physical address if they are ++ ** different. ++ */ ++ gceSTATUS ++ (*getGPUPhysical)( ++ IN gckPLATFORM Platform, ++ IN gctUINT32 CPUPhysical, ++ OUT gctUINT32_PTR GPUPhysical ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** adjustProt ++ ** ++ ** Override Prot flag when mapping paged memory to userspace. ++ */ ++ gceSTATUS ++ (*adjustProt)( ++ IN struct vm_area_struct * vma ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** shrinkMemory ++ ** ++ ** Do something to collect memory, eg, act as oom killer. ++ */ ++ gceSTATUS ++ (*shrinkMemory)( ++ IN gckPLATFORM Platform ++ ); ++ ++ /******************************************************************************* ++ ** ++ ** cache ++ ** ++ ** Cache operation. ++ */ ++ gceSTATUS ++ (*cache)( ++ IN gckPLATFORM Platform, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Handle, ++ IN gctUINT32 Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes, ++ IN gceCACHEOPERATION Operation ++ ); ++} ++gcsPLATFORM_OPERATIONS; ++ ++typedef struct _gcsPLATFORM ++{ ++ struct platform_device* device; ++ struct platform_driver* driver; ++ ++ gcsPLATFORM_OPERATIONS* ops; ++ ++ void* priv; ++} ++gcsPLATFORM; ++ ++void ++gckPLATFORM_QueryOperations( ++ IN gcsPLATFORM_OPERATIONS ** Operations ++ ); ++ ++#endif +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_power.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_power.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_power.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_power.c 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,347 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_POWER ++ ++/******************************************************************************\ ++************************ Dynamic Voltage Frequency Setting ********************* ++\******************************************************************************/ ++#if gcdDVFS ++static gctUINT32 ++_GetLoadHistory( ++ IN gckDVFS Dvfs, ++ IN gctUINT32 Select, ++ IN gctUINT32 Index ++) ++{ ++ return Dvfs->loads[Index]; ++} ++ ++static void ++_IncreaseScale( ++ IN gckDVFS Dvfs, ++ IN gctUINT32 Load, ++ OUT gctUINT8 *Scale ++ ) ++{ ++ if (Dvfs->currentScale < 32) ++ { ++ *Scale = Dvfs->currentScale + 8; ++ } ++ else ++ { ++ *Scale = Dvfs->currentScale + 8; ++ *Scale = gcmMIN(64, *Scale); ++ } ++} ++ ++static void ++_RecordFrequencyHistory( ++ gckDVFS Dvfs, ++ gctUINT32 Frequency ++ ) ++{ ++ gctUINT32 i = 0; ++ ++ struct _FrequencyHistory *history = Dvfs->frequencyHistory; ++ ++ for (i = 0; i < 16; i++) ++ { ++ if (history->frequency == Frequency) ++ { ++ break; ++ } ++ ++ if (history->frequency == 0) ++ { ++ history->frequency = Frequency; ++ break; ++ } ++ ++ history++; ++ } ++ ++ if (i < 16) ++ { ++ history->count++; ++ } ++} ++ ++static gctUINT32 ++_GetFrequencyHistory( ++ gckDVFS Dvfs, ++ gctUINT32 Frequency ++ ) ++{ ++ gctUINT32 i = 0; ++ ++ struct _FrequencyHistory * history = Dvfs->frequencyHistory; ++ ++ for (i = 0; i < 16; i++) ++ { ++ if (history->frequency == Frequency) ++ { ++ break; ++ } ++ ++ history++; ++ } ++ ++ if (i < 16) ++ { ++ return history->count; ++ } ++ ++ return 0; ++} ++ ++static void ++_Policy( ++ IN gckDVFS Dvfs, ++ IN gctUINT32 Load, ++ OUT gctUINT8 *Scale ++ ) ++{ ++ gctUINT8 load[4], nextLoad; ++ gctUINT8 scale; ++ ++ /* Last 4 history. */ ++ load[0] = (Load & 0xFF); ++ load[1] = (Load & 0xFF00) >> 8; ++ load[2] = (Load & 0xFF0000) >> 16; ++ load[3] = (Load & 0xFF000000) >> 24; ++ ++ /* Determine target scale. */ ++ if (load[0] > 54) ++ { ++ _IncreaseScale(Dvfs, Load, &scale); ++ } ++ else ++ { ++ nextLoad = (load[0] + load[1] + load[2] + load[3])/4; ++ ++ scale = Dvfs->currentScale * (nextLoad) / 54; ++ ++ scale = gcmMAX(1, scale); ++ scale = gcmMIN(64, scale); ++ } ++ ++ Dvfs->totalConfig++; ++ ++ Dvfs->loads[(load[0]-1)/8]++; ++ ++ *Scale = scale; ++ ++ ++ if (Dvfs->totalConfig % 100 == 0) ++ { ++ gcmkPRINT("======================================================="); ++ gcmkPRINT("GPU Load: %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d", ++ 8, 16, 24, 32, 40, 48, 56, 64); ++ gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d", ++ _GetLoadHistory(Dvfs,2, 0), ++ _GetLoadHistory(Dvfs,2, 1), ++ _GetLoadHistory(Dvfs,2, 2), ++ _GetLoadHistory(Dvfs,2, 3), ++ _GetLoadHistory(Dvfs,2, 4), ++ _GetLoadHistory(Dvfs,2, 5), ++ _GetLoadHistory(Dvfs,2, 6), ++ _GetLoadHistory(Dvfs,2, 7) ++ ); ++ ++ gcmkPRINT("Frequency(MHz) %-8d %-8d %-8d %-8d %-8d", ++ 58, 120, 240, 360, 480); ++ gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d", ++ _GetFrequencyHistory(Dvfs, 58), ++ _GetFrequencyHistory(Dvfs,120), ++ _GetFrequencyHistory(Dvfs,240), ++ _GetFrequencyHistory(Dvfs,360), ++ _GetFrequencyHistory(Dvfs,480) ++ ); ++ } ++} ++ ++static void ++_TimerFunction( ++ gctPOINTER Data ++ ) ++{ ++ gceSTATUS status; ++ gckDVFS dvfs = (gckDVFS) Data; ++ gckHARDWARE hardware = dvfs->hardware; ++ gctUINT32 value; ++ gctUINT32 frequency; ++ gctUINT8 scale; ++ gctUINT32 t1, t2, consumed; ++ ++ gckOS_GetTicks(&t1); ++ ++ gcmkONERROR(gckHARDWARE_QueryLoad(hardware, &value)); ++ ++ /* determine target sacle. */ ++ _Policy(dvfs, value, &scale); ++ ++ /* Set frequency and voltage. */ ++ gcmkONERROR(gckOS_SetGPUFrequency(hardware->os, hardware->core, scale)); ++ ++ /* Query real frequency. */ ++ gcmkONERROR( ++ gckOS_QueryGPUFrequency(hardware->os, ++ hardware->core, ++ &frequency, ++ &dvfs->currentScale)); ++ ++ _RecordFrequencyHistory(dvfs, frequency); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_POWER, ++ "Current frequency = %d", ++ frequency); ++ ++ /* Set period. */ ++ gcmkONERROR(gckHARDWARE_SetDVFSPeroid(hardware, frequency)); ++ ++OnError: ++ /* Determine next querying time. */ ++ gckOS_GetTicks(&t2); ++ ++ consumed = gcmMIN(((long)t2 - (long)t1), 5); ++ ++ if (dvfs->stop == gcvFALSE) ++ { ++ gcmkVERIFY_OK(gckOS_StartTimer(hardware->os, ++ dvfs->timer, ++ dvfs->pollingTime - consumed)); ++ } ++ ++ return; ++} ++ ++gceSTATUS ++gckDVFS_Construct( ++ IN gckHARDWARE Hardware, ++ OUT gckDVFS * Dvfs ++ ) ++{ ++ gceSTATUS status; ++ gctPOINTER pointer; ++ gckDVFS dvfs = gcvNULL; ++ gckOS os = Hardware->os; ++ ++ gcmkHEADER_ARG("Hardware=0x%X", Hardware); ++ ++ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); ++ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL); ++ ++ /* Allocate a gckDVFS manager. */ ++ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckDVFS), &pointer)); ++ ++ gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckDVFS)); ++ ++ dvfs = pointer; ++ ++ /* Initialization. */ ++ dvfs->hardware = Hardware; ++ dvfs->pollingTime = gcdDVFS_POLLING_TIME; ++ dvfs->os = Hardware->os; ++ dvfs->currentScale = 64; ++ ++ /* Create a polling timer. */ ++ gcmkONERROR(gckOS_CreateTimer(os, _TimerFunction, pointer, &dvfs->timer)); ++ ++ /* Initialize frequency and voltage adjustment helper. */ ++ gcmkONERROR(gckOS_PrepareGPUFrequency(os, Hardware->core)); ++ ++ /* Return result. */ ++ *Dvfs = dvfs; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (dvfs) ++ { ++ if (dvfs->timer) ++ { ++ gcmkVERIFY_OK(gckOS_DestroyTimer(os, dvfs->timer)); ++ } ++ ++ gcmkOS_SAFE_FREE(os, dvfs); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckDVFS_Destroy( ++ IN gckDVFS Dvfs ++ ) ++{ ++ gcmkHEADER_ARG("Dvfs=0x%X", Dvfs); ++ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL); ++ ++ /* Deinitialize helper fuunction. */ ++ gcmkVERIFY_OK(gckOS_FinishGPUFrequency(Dvfs->os, Dvfs->hardware->core)); ++ ++ /* DestroyTimer. */ ++ gcmkVERIFY_OK(gckOS_DestroyTimer(Dvfs->os, Dvfs->timer)); ++ ++ gcmkOS_SAFE_FREE(Dvfs->os, Dvfs); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckDVFS_Start( ++ IN gckDVFS Dvfs ++ ) ++{ ++ gcmkHEADER_ARG("Dvfs=0x%X", Dvfs); ++ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL); ++ ++ gckHARDWARE_InitDVFS(Dvfs->hardware); ++ ++ Dvfs->stop = gcvFALSE; ++ ++ gckOS_StartTimer(Dvfs->os, Dvfs->timer, Dvfs->pollingTime); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckDVFS_Stop( ++ IN gckDVFS Dvfs ++ ) ++{ ++ gcmkHEADER_ARG("Dvfs=0x%X", Dvfs); ++ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL); ++ ++ Dvfs->stop = gcvTRUE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++#endif +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_precomp.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_precomp.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_precomp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_precomp.h 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,29 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_precomp_h_ ++#define __gc_hal_kernel_precomp_h_ ++ ++#include "gc_hal.h" ++#include "gc_hal_driver.h" ++#include "gc_hal_kernel.h" ++ ++#endif /* __gc_hal_kernel_precomp_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_probe.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_probe.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_probe.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_probe.c 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,1253 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include ++#include ++ ++#include "gc_hal_kernel_linux.h" ++#include "gc_hal_driver.h" ++ ++#include ++ ++#ifdef CONFIG_PXA_DVFM ++# include ++# include ++#endif ++ ++ ++/* Zone used for header/footer. */ ++#define _GC_OBJ_ZONE gcvZONE_DRIVER ++ ++MODULE_DESCRIPTION("Vivante Graphics Driver"); ++MODULE_LICENSE("GPL"); ++ ++static struct class* gpuClass; ++ ++static gcsPLATFORM platform; ++ ++static gckGALDEVICE galDevice; ++ ++static uint major = 199; ++module_param(major, uint, 0644); ++ ++static int irqLine = -1; ++module_param(irqLine, int, 0644); ++ ++static ulong registerMemBase = 0x80000000; ++module_param(registerMemBase, ulong, 0644); ++ ++static ulong registerMemSize = 2 << 10; ++module_param(registerMemSize, ulong, 0644); ++ ++static int irqLine2D = -1; ++module_param(irqLine2D, int, 0644); ++ ++static ulong registerMemBase2D = 0x00000000; ++module_param(registerMemBase2D, ulong, 0644); ++ ++static ulong registerMemSize2D = 2 << 10; ++module_param(registerMemSize2D, ulong, 0644); ++ ++static int irqLineVG = -1; ++module_param(irqLineVG, int, 0644); ++ ++static ulong registerMemBaseVG = 0x00000000; ++module_param(registerMemBaseVG, ulong, 0644); ++ ++static ulong registerMemSizeVG = 2 << 10; ++module_param(registerMemSizeVG, ulong, 0644); ++ ++#ifndef gcdDEFAULT_CONTIGUOUS_SIZE ++#define gcdDEFAULT_CONTIGUOUS_SIZE (4 << 20) ++#endif ++static ulong contiguousSize = gcdDEFAULT_CONTIGUOUS_SIZE; ++module_param(contiguousSize, ulong, 0644); ++ ++static ulong contiguousBase = 0; ++module_param(contiguousBase, ulong, 0644); ++ ++static ulong bankSize = 0; ++module_param(bankSize, ulong, 0644); ++ ++static int fastClear = -1; ++module_param(fastClear, int, 0644); ++ ++static int compression = -1; ++module_param(compression, int, 0644); ++ ++static int powerManagement = -1; ++module_param(powerManagement, int, 0644); ++ ++static int gpuProfiler = 0; ++module_param(gpuProfiler, int, 0644); ++ ++static int signal = 48; ++module_param(signal, int, 0644); ++ ++static ulong baseAddress = 0; ++module_param(baseAddress, ulong, 0644); ++ ++static ulong physSize = 0; ++module_param(physSize, ulong, 0644); ++ ++static uint logFileSize = 0; ++module_param(logFileSize,uint, 0644); ++ ++static uint recovery = 1; ++module_param(recovery, uint, 0644); ++MODULE_PARM_DESC(recovery, "Recover GPU from stuck (1: Enable, 0: Disable)"); ++ ++/* Middle needs about 40KB buffer, Maximal may need more than 200KB buffer. */ ++static uint stuckDump = 1; ++module_param(stuckDump, uint, 0644); ++MODULE_PARM_DESC(stuckDump, "Level of stuck dump content (1: Minimal, 2: Middle, 3: Maximal)"); ++ ++static int showArgs = 0; ++module_param(showArgs, int, 0644); ++ ++static int mmu = 1; ++module_param(mmu, int, 0644); ++ ++static int gpu3DMinClock = 1; ++ ++static int contiguousRequested = 0; ++ ++static int drv_open( ++ struct inode* inode, ++ struct file* filp ++ ); ++ ++static int drv_release( ++ struct inode* inode, ++ struct file* filp ++ ); ++ ++static long drv_ioctl( ++ struct file* filp, ++ unsigned int ioctlCode, ++ unsigned long arg ++ ); ++ ++static int drv_mmap( ++ struct file* filp, ++ struct vm_area_struct* vma ++ ); ++ ++static struct file_operations driver_fops = ++{ ++ .owner = THIS_MODULE, ++ .open = drv_open, ++ .release = drv_release, ++ .unlocked_ioctl = drv_ioctl, ++#ifdef HAVE_COMPAT_IOCTL ++ .compat_ioctl = drv_ioctl, ++#endif ++ .mmap = drv_mmap, ++}; ++ ++void ++_UpdateModuleParam( ++ gcsMODULE_PARAMETERS *Param ++ ) ++{ ++ irqLine = Param->irqLine ; ++ registerMemBase = Param->registerMemBase; ++ registerMemSize = Param->registerMemSize; ++ irqLine2D = Param->irqLine2D ; ++ registerMemBase2D = Param->registerMemBase2D; ++ registerMemSize2D = Param->registerMemSize2D; ++ irqLineVG = Param->irqLineVG; ++ registerMemBaseVG = Param->registerMemBaseVG; ++ registerMemSizeVG = Param->registerMemSizeVG; ++ contiguousSize = Param->contiguousSize; ++ contiguousBase = Param->contiguousBase; ++ bankSize = Param->bankSize; ++ fastClear = Param->fastClear; ++ compression = Param->compression; ++ powerManagement = Param->powerManagement; ++ gpuProfiler = Param->gpuProfiler; ++ signal = Param->signal; ++ baseAddress = Param->baseAddress; ++ physSize = Param->physSize; ++ logFileSize = Param->logFileSize; ++ recovery = Param->recovery; ++ stuckDump = Param->stuckDump; ++ showArgs = Param->showArgs; ++ contiguousRequested = Param->contiguousRequested; ++ gpu3DMinClock = Param->gpu3DMinClock; ++} ++ ++void ++gckOS_DumpParam( ++ void ++ ) ++{ ++ printk("Galcore options:\n"); ++ printk(" irqLine = %d\n", irqLine); ++ printk(" registerMemBase = 0x%08lX\n", registerMemBase); ++ printk(" registerMemSize = 0x%08lX\n", registerMemSize); ++ ++ if (irqLine2D != -1) ++ { ++ printk(" irqLine2D = %d\n", irqLine2D); ++ printk(" registerMemBase2D = 0x%08lX\n", registerMemBase2D); ++ printk(" registerMemSize2D = 0x%08lX\n", registerMemSize2D); ++ } ++ ++ if (irqLineVG != -1) ++ { ++ printk(" irqLineVG = %d\n", irqLineVG); ++ printk(" registerMemBaseVG = 0x%08lX\n", registerMemBaseVG); ++ printk(" registerMemSizeVG = 0x%08lX\n", registerMemSizeVG); ++ } ++ ++ printk(" contiguousSize = %ld\n", contiguousSize); ++ printk(" contiguousBase = 0x%08lX\n", contiguousBase); ++ printk(" bankSize = 0x%08lX\n", bankSize); ++ printk(" fastClear = %d\n", fastClear); ++ printk(" compression = %d\n", compression); ++ printk(" signal = %d\n", signal); ++ printk(" powerManagement = %d\n", powerManagement); ++ printk(" baseAddress = 0x%08lX\n", baseAddress); ++ printk(" physSize = 0x%08lX\n", physSize); ++ printk(" logFileSize = %d KB \n", logFileSize); ++ printk(" recovery = %d\n", recovery); ++ printk(" stuckDump = %d\n", stuckDump); ++ printk(" gpuProfiler = %d\n", gpuProfiler); ++} ++ ++int drv_open( ++ struct inode* inode, ++ struct file* filp ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL attached = gcvFALSE; ++ gcsHAL_PRIVATE_DATA_PTR data = gcvNULL; ++ gctINT i; ++ ++ gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp); ++ ++ if (filp == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): filp is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ data = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL | __GFP_NOWARN); ++ ++ if (data == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): private_data is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ data->device = galDevice; ++ data->mappedMemory = gcvNULL; ++ data->contiguousLogical = gcvNULL; ++ gcmkONERROR(gckOS_GetProcessID(&data->pidOpen)); ++ ++ /* Attached the process. */ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (galDevice->kernels[i] != gcvNULL) ++ { ++ gcmkONERROR(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvTRUE)); ++ } ++ } ++ attached = gcvTRUE; ++ ++ if (!galDevice->contiguousMapped) ++ { ++ if (galDevice->contiguousPhysical != gcvNULL) ++ { ++ gcmkONERROR(gckOS_MapMemory( ++ galDevice->os, ++ galDevice->contiguousPhysical, ++ galDevice->contiguousSize, ++ &data->contiguousLogical ++ )); ++ } ++ } ++ ++ filp->private_data = data; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return 0; ++ ++OnError: ++ if (data != gcvNULL) ++ { ++ if (data->contiguousLogical != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_UnmapMemory( ++ galDevice->os, ++ galDevice->contiguousPhysical, ++ galDevice->contiguousSize, ++ data->contiguousLogical ++ )); ++ } ++ ++ kfree(data); ++ } ++ ++ if (attached) ++ { ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (galDevice->kernels[i] != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvFALSE)); ++ } ++ } ++ } ++ ++ gcmkFOOTER(); ++ return -ENOTTY; ++} ++ ++int drv_release( ++ struct inode* inode, ++ struct file* filp ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_PRIVATE_DATA_PTR data; ++ gckGALDEVICE device; ++ gctINT i; ++ ++ gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp); ++ ++ if (filp == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): filp is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ data = filp->private_data; ++ ++ if (data == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): private_data is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ device = data->device; ++ ++ if (device == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): device is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ if (!device->contiguousMapped) ++ { ++ if (data->contiguousLogical != gcvNULL) ++ { ++ gcmkONERROR(gckOS_UnmapMemoryEx( ++ galDevice->os, ++ galDevice->contiguousPhysical, ++ galDevice->contiguousSize, ++ data->contiguousLogical, ++ data->pidOpen ++ )); ++ ++ data->contiguousLogical = gcvNULL; ++ } ++ } ++ ++ /* A process gets detached. */ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (galDevice->kernels[i] != gcvNULL) ++ { ++ gcmkONERROR(gckKERNEL_AttachProcessEx(galDevice->kernels[i], gcvFALSE, data->pidOpen)); ++ } ++ } ++ ++ kfree(data); ++ filp->private_data = NULL; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return 0; ++ ++OnError: ++ gcmkFOOTER(); ++ return -ENOTTY; ++} ++ ++long drv_ioctl( ++ struct file* filp, ++ unsigned int ioctlCode, ++ unsigned long arg ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE iface; ++ gctUINT32 copyLen; ++ DRIVER_ARGS drvArgs; ++ gckGALDEVICE device; ++ gcsHAL_PRIVATE_DATA_PTR data; ++ gctINT32 i, count; ++ gckVIDMEM_NODE nodeObject; ++ ++ gcmkHEADER_ARG( ++ "filp=0x%08X ioctlCode=0x%08X arg=0x%08X", ++ filp, ioctlCode, arg ++ ); ++ ++ if (filp == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): filp is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ data = filp->private_data; ++ ++ if (data == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): private_data is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ device = data->device; ++ ++ if (device == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): device is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ if ((ioctlCode != IOCTL_GCHAL_INTERFACE) ++ && (ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE) ++ ) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): unknown command %d\n", ++ __FUNCTION__, __LINE__, ++ ioctlCode ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Get the drvArgs. */ ++ copyLen = copy_from_user( ++ &drvArgs, (void *) arg, sizeof(DRIVER_ARGS) ++ ); ++ ++ if (copyLen != 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): error copying of the input arguments.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Now bring in the gcsHAL_INTERFACE structure. */ ++ if ((drvArgs.InputBufferSize != sizeof(gcsHAL_INTERFACE)) ++ || (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE)) ++ ) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): input or/and output structures are invalid.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ copyLen = copy_from_user( ++ &iface, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_INTERFACE) ++ ); ++ ++ if (copyLen != 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): error copying of input HAL interface.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ if (iface.command == gcvHAL_CHIP_INFO) ++ { ++ count = 0; ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (device->kernels[i] != gcvNULL) ++ { ++#if gcdENABLE_VG ++ if (i == gcvCORE_VG) ++ { ++ iface.u.ChipInfo.types[count] = gcvHARDWARE_VG; ++ } ++ else ++#endif ++ { ++ gcmkVERIFY_OK(gckHARDWARE_GetType(device->kernels[i]->hardware, ++ &iface.u.ChipInfo.types[count])); ++ } ++ count++; ++ } ++ } ++ ++ iface.u.ChipInfo.count = count; ++ iface.status = status = gcvSTATUS_OK; ++ } ++ else ++ { ++ if (iface.hardwareType > 7) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): unknown hardwareType %d\n", ++ __FUNCTION__, __LINE__, ++ iface.hardwareType ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++#if gcdENABLE_VG ++ if (device->coreMapping[iface.hardwareType] == gcvCORE_VG) ++ { ++ status = gckVGKERNEL_Dispatch(device->kernels[gcvCORE_VG], ++ (ioctlCode == IOCTL_GCHAL_INTERFACE), ++ &iface); ++ } ++ else ++#endif ++ { ++ status = gckKERNEL_Dispatch(device->kernels[device->coreMapping[iface.hardwareType]], ++ (ioctlCode == IOCTL_GCHAL_INTERFACE), ++ &iface); ++ } ++ } ++ ++ /* Redo system call after pending signal is handled. */ ++ if (status == gcvSTATUS_INTERRUPTED) ++ { ++ gcmkFOOTER(); ++ return -ERESTARTSYS; ++ } ++ ++ if (gcmIS_SUCCESS(status) && (iface.command == gcvHAL_LOCK_VIDEO_MEMORY)) ++ { ++ gcuVIDMEM_NODE_PTR node; ++ gctUINT32 processID; ++ ++ gckOS_GetProcessID(&processID); ++ ++ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(device->kernels[device->coreMapping[iface.hardwareType]], ++ processID, ++ (gctUINT32)iface.u.LockVideoMemory.node, ++ &nodeObject)); ++ node = nodeObject->node; ++ ++ /* Special case for mapped memory. */ ++ if ((data->mappedMemory != gcvNULL) ++ && (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ++ ) ++ { ++ /* Compute offset into mapped memory. */ ++ gctUINT32 offset ++ = (gctUINT8 *) gcmUINT64_TO_PTR(iface.u.LockVideoMemory.memory) ++ - (gctUINT8 *) device->contiguousBase; ++ ++ /* Compute offset into user-mapped region. */ ++ iface.u.LockVideoMemory.memory = ++ gcmPTR_TO_UINT64((gctUINT8 *) data->mappedMemory + offset); ++ } ++ } ++ ++ /* Copy data back to the user. */ ++ copyLen = copy_to_user( ++ gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface, sizeof(gcsHAL_INTERFACE) ++ ); ++ ++ if (copyLen != 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): error copying of output HAL interface.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return 0; ++ ++OnError: ++ gcmkFOOTER(); ++ return -ENOTTY; ++} ++ ++static int drv_mmap( ++ struct file* filp, ++ struct vm_area_struct* vma ++ ) ++{ ++ gceSTATUS status = gcvSTATUS_OK; ++ gcsHAL_PRIVATE_DATA_PTR data; ++ gckGALDEVICE device; ++ ++ gcmkHEADER_ARG("filp=0x%08X vma=0x%08X", filp, vma); ++ ++ if (filp == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): filp is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ data = filp->private_data; ++ ++ if (data == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): private_data is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ device = data->device; ++ ++ if (device == gcvNULL) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): device is NULL\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++#if !gcdPAGED_MEMORY_CACHEABLE ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ vma->vm_flags |= gcdVM_FLAGS; ++#endif ++ vma->vm_pgoff = 0; ++ ++ if (device->contiguousMapped) ++ { ++ unsigned long size = vma->vm_end - vma->vm_start; ++ int ret = 0; ++ ++ if (size > device->contiguousSize) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Invalid mapping size.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ ++ ret = io_remap_pfn_range( ++ vma, ++ vma->vm_start, ++ device->requestedContiguousBase >> PAGE_SHIFT, ++ size, ++ vma->vm_page_prot ++ ); ++ ++ if (ret != 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): io_remap_pfn_range failed %d\n", ++ __FUNCTION__, __LINE__, ++ ret ++ ); ++ ++ data->mappedMemory = gcvNULL; ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ data->mappedMemory = (gctPOINTER) vma->vm_start; ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return 0; ++ } ++ ++OnError: ++ gcmkFOOTER(); ++ return -ENOTTY; ++} ++ ++ ++static int drv_init(struct platform_device *pdev) ++{ ++ int ret; ++ int result = -EINVAL; ++ gceSTATUS status; ++ gckGALDEVICE device = gcvNULL; ++ struct class* device_class = gcvNULL; ++ ++ gcsDEVICE_CONSTRUCT_ARGS args = { ++ .recovery = recovery, ++ .stuckDump = stuckDump, ++ .gpu3DMinClock = gpu3DMinClock, ++ .contiguousRequested = contiguousRequested, ++ .platform = &platform, ++ .mmu = mmu, ++ }; ++ ++ gcmkHEADER(); ++ ++ printk(KERN_INFO "Galcore version %d.%d.%d.%d\n", ++ gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD); ++ ++#if !VIVANTE_PROFILER_PM ++ /* when enable gpu profiler, we need to turn off gpu powerMangement */ ++ if (gpuProfiler) ++ { ++ powerManagement = 0; ++ } ++#endif ++ ++ if (showArgs) ++ { ++ gckOS_DumpParam(); ++ } ++ ++ if (logFileSize != 0) ++ { ++ gckDEBUGFS_Initialize(); ++ } ++ ++ /* Create the GAL device. */ ++ status = gckGALDEVICE_Construct( ++ irqLine, ++ registerMemBase, registerMemSize, ++ irqLine2D, ++ registerMemBase2D, registerMemSize2D, ++ irqLineVG, ++ registerMemBaseVG, registerMemSizeVG, ++ contiguousBase, contiguousSize, ++ bankSize, fastClear, compression, baseAddress, physSize, signal, ++ logFileSize, ++ powerManagement, ++ gpuProfiler, ++ &args, ++ &pdev->dev, ++ &device ++ ); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Failed to create the GAL device: status=%d\n", ++ __FUNCTION__, __LINE__, status); ++ ++ goto OnError; ++ } ++ ++ /* Start the GAL device. */ ++ gcmkONERROR(gckGALDEVICE_Start(device)); ++ ++ if ((physSize != 0) ++ && (device->kernels[gcvCORE_MAJOR] != gcvNULL) ++ && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0)) ++ { ++ /* Reset the base address */ ++ device->baseAddress = 0; ++ } ++ ++ /* Register the character device. */ ++ ret = register_chrdev(major, DEVICE_NAME, &driver_fops); ++ ++ if (ret < 0) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Could not allocate major number for mmap.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ ++ if (major == 0) ++ { ++ major = ret; ++ } ++ ++ /* Create the device class. */ ++ device_class = class_create(THIS_MODULE, "graphics_class"); ++ ++ if (IS_ERR(device_class)) ++ { ++ gcmkTRACE_ZONE( ++ gcvLEVEL_ERROR, gcvZONE_DRIVER, ++ "%s(%d): Failed to create the class.\n", ++ __FUNCTION__, __LINE__ ++ ); ++ ++ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); ++ } ++ ++ device_create(device_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); ++ ++ galDevice = device; ++ gpuClass = device_class; ++ ++ gcmkTRACE_ZONE( ++ gcvLEVEL_INFO, gcvZONE_DRIVER, ++ "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n", ++ __FUNCTION__, __LINE__, ++ irqLine, contiguousSize, registerMemBase ++ ); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return 0; ++ ++OnError: ++ /* Roll back. */ ++ if (device_class != gcvNULL) ++ { ++ device_destroy(device_class, MKDEV(major, 0)); ++ class_destroy(device_class); ++ } ++ ++ if (device != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckGALDEVICE_Stop(device)); ++ gcmkVERIFY_OK(gckGALDEVICE_Destroy(device)); ++ } ++ ++ gcmkFOOTER(); ++ return result; ++} ++ ++static void drv_exit(void) ++{ ++ gcmkHEADER(); ++ ++ gcmkASSERT(gpuClass != gcvNULL); ++ device_destroy(gpuClass, MKDEV(major, 0)); ++ class_destroy(gpuClass); ++ ++ unregister_chrdev(major, DEVICE_NAME); ++ ++ gcmkVERIFY_OK(gckGALDEVICE_Stop(galDevice)); ++ gcmkVERIFY_OK(gckGALDEVICE_Destroy(galDevice)); ++ ++ if(gckDEBUGFS_IsEnabled()) ++ { ++ gckDEBUGFS_Terminate(); ++ } ++ ++ gcmkFOOTER_NO(); ++} ++ ++static int gpu_probe(struct platform_device *pdev) ++{ ++ int ret = -ENODEV; ++ gcsMODULE_PARAMETERS moduleParam = { ++ .irqLine = irqLine, ++ .registerMemBase = registerMemBase, ++ .registerMemSize = registerMemSize, ++ .irqLine2D = irqLine2D, ++ .registerMemBase2D = registerMemBase2D, ++ .registerMemSize2D = registerMemSize2D, ++ .irqLineVG = irqLineVG, ++ .registerMemBaseVG = registerMemBaseVG, ++ .registerMemSizeVG = registerMemSizeVG, ++ .contiguousSize = contiguousSize, ++ .contiguousBase = contiguousBase, ++ .bankSize = bankSize, ++ .fastClear = fastClear, ++ .compression = compression, ++ .powerManagement = powerManagement, ++ .gpuProfiler = gpuProfiler, ++ .signal = signal, ++ .baseAddress = baseAddress, ++ .physSize = physSize, ++ .logFileSize = logFileSize, ++ .recovery = recovery, ++ .stuckDump = stuckDump, ++ .showArgs = showArgs, ++ .gpu3DMinClock = gpu3DMinClock, ++ }; ++ ++ gcmkHEADER(); ++ ++ platform.device = pdev; ++ ++ if (platform.ops->getPower) ++ { ++ if (gcmIS_ERROR(platform.ops->getPower(&platform))) ++ { ++ gcmkFOOTER_NO(); ++ return ret; ++ } ++ } ++ ++ if (platform.ops->adjustParam) ++ { ++ /* Override default module param. */ ++ platform.ops->adjustParam(&platform, &moduleParam); ++ ++ /* Update module param because drv_init() uses them directly. */ ++ _UpdateModuleParam(&moduleParam); ++ } ++ ++ ret = drv_init(pdev); ++ ++ if (!ret) ++ { ++ platform_set_drvdata(pdev, galDevice); ++ ++ gcmkFOOTER_NO(); ++ return ret; ++ } ++ ++ gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret); ++ return ret; ++} ++ ++static int gpu_remove(struct platform_device *pdev) ++{ ++ gcmkHEADER(); ++ ++ drv_exit(); ++ ++ if (platform.ops->putPower) ++ { ++ platform.ops->putPower(&platform); ++ } ++ ++ gcmkFOOTER_NO(); ++ return 0; ++} ++ ++static int gpu_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ gceSTATUS status; ++ gckGALDEVICE device; ++ gctINT i; ++ ++ device = platform_get_drvdata(dev); ++ ++ if (!device) ++ { ++ return -1; ++ } ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (device->kernels[i] != gcvNULL) ++ { ++ /* Store states. */ ++#if gcdENABLE_VG ++ if (i == gcvCORE_VG) ++ { ++ status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]); ++ } ++ else ++#endif ++ { ++ status = gckHARDWARE_QueryPowerManagementState(device->kernels[i]->hardware, &device->statesStored[i]); ++ } ++ ++ if (gcmIS_ERROR(status)) ++ { ++ return -1; ++ } ++ ++#if gcdENABLE_VG ++ if (i == gcvCORE_VG) ++ { ++ status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_OFF); ++ } ++ else ++#endif ++ { ++ status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_OFF); ++ } ++ ++ if (gcmIS_ERROR(status)) ++ { ++ return -1; ++ } ++ ++ } ++ } ++ ++ return 0; ++} ++ ++static int gpu_resume(struct platform_device *dev) ++{ ++ gceSTATUS status; ++ gckGALDEVICE device; ++ gctINT i; ++ gceCHIPPOWERSTATE statesStored; ++ ++ device = platform_get_drvdata(dev); ++ ++ if (!device) ++ { ++ return -1; ++ } ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ if (device->kernels[i] != gcvNULL) ++ { ++#if gcdENABLE_VG ++ if (i == gcvCORE_VG) ++ { ++ status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_ON); ++ } ++ else ++#endif ++ { ++ status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_ON); ++ } ++ ++ if (gcmIS_ERROR(status)) ++ { ++ return -1; ++ } ++ ++ /* Convert global state to crossponding internal state. */ ++ switch(device->statesStored[i]) ++ { ++ case gcvPOWER_OFF: ++ statesStored = gcvPOWER_OFF_BROADCAST; ++ break; ++ case gcvPOWER_IDLE: ++ statesStored = gcvPOWER_IDLE_BROADCAST; ++ break; ++ case gcvPOWER_SUSPEND: ++ statesStored = gcvPOWER_SUSPEND_BROADCAST; ++ break; ++ case gcvPOWER_ON: ++ statesStored = gcvPOWER_ON_AUTO; ++ break; ++ default: ++ statesStored = device->statesStored[i]; ++ break; ++ } ++ ++ /* Restore states. */ ++#if gcdENABLE_VG ++ if (i == gcvCORE_VG) ++ { ++ status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, statesStored); ++ } ++ else ++#endif ++ { ++ status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, statesStored); ++ } ++ ++ if (gcmIS_ERROR(status)) ++ { ++ return -1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#if defined(CONFIG_PM) ++static int gpu_runtime_suspend(struct device *dev) ++{ ++ pm_message_t state={0}; ++ return gpu_suspend(to_platform_device(dev), state); ++} ++ ++static int gpu_runtime_resume(struct device *dev) ++{ ++ return gpu_resume(to_platform_device(dev)); ++} ++ ++static const struct dev_pm_ops gpu_pm_ops = { ++ SET_RUNTIME_PM_OPS(gpu_runtime_suspend, gpu_runtime_resume, NULL) ++}; ++#endif ++ ++static struct platform_driver gpu_driver = { ++ .probe = gpu_probe, ++ .remove = gpu_remove, ++ ++ .driver = { ++ .name = DEVICE_NAME, ++ .pm = &gpu_pm_ops, ++ } ++}; ++ ++static int __init gpu_init(void) ++{ ++ int ret = 0; ++ ++ memset(&platform, 0, sizeof(gcsPLATFORM)); ++ ++ gckPLATFORM_QueryOperations(&platform.ops); ++ ++ if (platform.ops == gcvNULL) ++ { ++ printk(KERN_ERR "galcore: No platform specific operations.\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ if (platform.ops->allocPriv) ++ { ++ /* Allocate platform private data. */ ++ if (gcmIS_ERROR(platform.ops->allocPriv(&platform))) ++ { ++ ret = -ENOMEM; ++ goto out; ++ } ++ } ++ ++ if (platform.ops->needAddDevice ++ && platform.ops->needAddDevice(&platform)) ++ { ++ /* Allocate device */ ++ platform.device = platform_device_alloc(DEVICE_NAME, -1); ++ if (!platform.device) ++ { ++ printk(KERN_ERR "galcore: platform_device_alloc failed.\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* Add device */ ++ ret = platform_device_add(platform.device); ++ if (ret) ++ { ++ printk(KERN_ERR "galcore: platform_device_add failed.\n"); ++ goto put_dev; ++ } ++ } ++ ++ platform.driver = &gpu_driver; ++ ++ if (platform.ops->adjustDriver) ++ { ++ /* Override default platform_driver struct. */ ++ platform.ops->adjustDriver(&platform); ++ } ++ ++ ret = platform_driver_register(&gpu_driver); ++ if (!ret) ++ { ++ goto out; ++ } ++ ++ platform_device_del(platform.device); ++put_dev: ++ platform_device_put(platform.device); ++ ++out: ++ return ret; ++} ++ ++static void __exit gpu_exit(void) ++{ ++ platform_driver_unregister(&gpu_driver); ++ ++ if (platform.ops->needAddDevice ++ && platform.ops->needAddDevice(&platform)) ++ { ++ platform_device_unregister(platform.device); ++ } ++ ++ if (platform.priv) ++ { ++ /* Free platform private data. */ ++ platform.ops->freePriv(&platform); ++ } ++} ++ ++module_init(gpu_init); ++module_exit(gpu_exit); +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_sync.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_sync.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_sync.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_sync.c 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,177 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include ++#include ++ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "gc_hal_kernel_sync.h" ++ ++static struct sync_pt * ++viv_sync_pt_dup( ++ struct sync_pt * sync_pt ++ ) ++{ ++ gceSTATUS status; ++ struct viv_sync_pt *pt; ++ struct viv_sync_pt *src; ++ struct viv_sync_timeline *obj; ++ ++ src = (struct viv_sync_pt *) sync_pt; ++ obj = (struct viv_sync_timeline *) sync_pt->parent; ++ ++ /* Create the new sync_pt. */ ++ pt = (struct viv_sync_pt *) ++ sync_pt_create(&obj->obj, sizeof(struct viv_sync_pt)); ++ ++ pt->stamp = src->stamp; ++ pt->sync = src->sync; ++ ++ /* Reference sync point. */ ++ status = gckOS_ReferenceSyncPoint(obj->os, pt->sync); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ sync_pt_free((struct sync_pt *)pt); ++ return NULL; ++ } ++ ++ return (struct sync_pt *)pt; ++} ++ ++static int ++viv_sync_pt_has_signaled( ++ struct sync_pt * sync_pt ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL state; ++ struct viv_sync_pt * pt; ++ struct viv_sync_timeline * obj; ++ ++ pt = (struct viv_sync_pt *)sync_pt; ++ obj = (struct viv_sync_timeline *)sync_pt->parent; ++ ++ status = gckOS_QuerySyncPoint(obj->os, pt->sync, &state); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ /* Error. */ ++ return -1; ++ } ++ ++ return state; ++} ++ ++static int ++viv_sync_pt_compare( ++ struct sync_pt * a, ++ struct sync_pt * b ++ ) ++{ ++ int ret; ++ struct viv_sync_pt * pt1 = (struct viv_sync_pt *) a; ++ struct viv_sync_pt * pt2 = (struct viv_sync_pt *) b; ++ ++ ret = (pt1->stamp < pt2->stamp) ? -1 ++ : (pt1->stamp == pt2->stamp) ? 0 ++ : 1; ++ ++ return ret; ++} ++ ++static void ++viv_sync_pt_free( ++ struct sync_pt * sync_pt ++ ) ++{ ++ struct viv_sync_pt * pt; ++ struct viv_sync_timeline * obj; ++ ++ pt = (struct viv_sync_pt *) sync_pt; ++ obj = (struct viv_sync_timeline *) sync_pt->parent; ++ ++ gckOS_DestroySyncPoint(obj->os, pt->sync); ++} ++ ++static struct sync_timeline_ops viv_timeline_ops = ++{ ++ .driver_name = "viv_sync", ++ .dup = viv_sync_pt_dup, ++ .has_signaled = viv_sync_pt_has_signaled, ++ .compare = viv_sync_pt_compare, ++ .free_pt = viv_sync_pt_free, ++}; ++ ++struct viv_sync_timeline * ++viv_sync_timeline_create( ++ const char * name, ++ gckOS os ++ ) ++{ ++ struct viv_sync_timeline * obj; ++ ++ obj = (struct viv_sync_timeline *) ++ sync_timeline_create(&viv_timeline_ops, sizeof(struct viv_sync_timeline), name); ++ ++ obj->os = os; ++ obj->stamp = 0; ++ ++ return obj; ++} ++ ++struct sync_pt * ++viv_sync_pt_create( ++ struct viv_sync_timeline * obj, ++ gctSYNC_POINT SyncPoint ++ ) ++{ ++ gceSTATUS status; ++ struct viv_sync_pt * pt; ++ ++ pt = (struct viv_sync_pt *) ++ sync_pt_create(&obj->obj, sizeof(struct viv_sync_pt)); ++ ++ pt->stamp = obj->stamp++; ++ pt->sync = SyncPoint; ++ ++ /* Dup signal. */ ++ status = gckOS_ReferenceSyncPoint(obj->os, SyncPoint); ++ ++ if (gcmIS_ERROR(status)) ++ { ++ sync_pt_free((struct sync_pt *)pt); ++ return NULL; ++ } ++ ++ return (struct sync_pt *) pt; ++} ++ ++#endif +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_sync.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_sync.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_sync.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_sync.h 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,72 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_sync_h_ ++#define __gc_hal_kernel_sync_h_ ++ ++#include ++ ++/* sync.h is in drivers/staging/android/ for now. */ ++#include ++ ++#include ++#include ++ ++struct viv_sync_timeline ++{ ++ /* Parent object. */ ++ struct sync_timeline obj; ++ ++ /* Timestamp when sync_pt is created. */ ++ gctUINT stamp; ++ ++ /* Pointer to os struct. */ ++ gckOS os; ++}; ++ ++ ++struct viv_sync_pt ++{ ++ /* Parent object. */ ++ struct sync_pt pt; ++ ++ /* Reference sync point*/ ++ gctSYNC_POINT sync; ++ ++ /* Timestamp when sync_pt is created. */ ++ gctUINT stamp; ++}; ++ ++/* Create viv_sync_timeline object. */ ++struct viv_sync_timeline * ++viv_sync_timeline_create( ++ const char * Name, ++ gckOS Os ++ ); ++ ++/* Create viv_sync_pt object. */ ++struct sync_pt * ++viv_sync_pt_create( ++ struct viv_sync_timeline * Obj, ++ gctSYNC_POINT SyncPoint ++ ); ++ ++#endif /* __gc_hal_kernel_sync_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_vg.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_vg.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_vg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_vg.c 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,831 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#if gcdENABLE_VG ++ ++#define _GC_OBJ_ZONE gcvZONE_VG ++ ++/******************************************************************************\ ++******************************* gckKERNEL API Code ****************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckKERNEL_Construct ++** ++** Construct a new gckKERNEL object. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** IN gctPOINTER Context ++** Pointer to a driver defined context. ++** ++** OUTPUT: ++** ++** gckKERNEL * Kernel ++** Pointer to a variable that will hold the pointer to the gckKERNEL ++** object. ++*/ ++gceSTATUS gckVGKERNEL_Construct( ++ IN gckOS Os, ++ IN gctPOINTER Context, ++ IN gckKERNEL inKernel, ++ OUT gckVGKERNEL * Kernel ++ ) ++{ ++ gceSTATUS status; ++ gckVGKERNEL kernel = gcvNULL; ++ ++ gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); ++ ++ do ++ { ++ /* Allocate the gckKERNEL object. */ ++ gcmkERR_BREAK(gckOS_Allocate( ++ Os, ++ sizeof(struct _gckVGKERNEL), ++ (gctPOINTER *) &kernel ++ )); ++ ++ /* Initialize the gckKERNEL object. */ ++ kernel->object.type = gcvOBJ_KERNEL; ++ kernel->os = Os; ++ kernel->context = Context; ++ kernel->hardware = gcvNULL; ++ kernel->interrupt = gcvNULL; ++ kernel->command = gcvNULL; ++ kernel->mmu = gcvNULL; ++ kernel->kernel = inKernel; ++ ++ /* Construct the gckVGHARDWARE object. */ ++ gcmkERR_BREAK(gckVGHARDWARE_Construct( ++ Os, &kernel->hardware ++ )); ++ ++ /* Set pointer to gckKERNEL object in gckVGHARDWARE object. */ ++ kernel->hardware->kernel = kernel; ++ ++ /* Construct the gckVGINTERRUPT object. */ ++ gcmkERR_BREAK(gckVGINTERRUPT_Construct( ++ kernel, &kernel->interrupt ++ )); ++ ++ /* Construct the gckVGCOMMAND object. */ ++ gcmkERR_BREAK(gckVGCOMMAND_Construct( ++ kernel, gcmKB2BYTES(8), gcmKB2BYTES(2), &kernel->command ++ )); ++ ++ /* Construct the gckVGMMU object. */ ++ gcmkERR_BREAK(gckVGMMU_Construct( ++ kernel, gcmKB2BYTES(32), &kernel->mmu ++ )); ++ ++ /* Return pointer to the gckKERNEL object. */ ++ *Kernel = kernel; ++ ++ gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); ++ /* Success. */ ++ return gcvSTATUS_OK; ++ } ++ while (gcvFALSE); ++ ++ /* Roll back. */ ++ if (kernel != gcvNULL) ++ { ++ if (kernel->mmu != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckVGMMU_Destroy(kernel->mmu)); ++ } ++ ++ if (kernel->command != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckVGCOMMAND_Destroy(kernel->command)); ++ } ++ ++ if (kernel->interrupt != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckVGINTERRUPT_Destroy(kernel->interrupt)); ++ } ++ ++ if (kernel->hardware != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckVGHARDWARE_Destroy(kernel->hardware)); ++ } ++ ++ gcmkVERIFY_OK(gckOS_Free(Os, kernel)); ++ } ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_Destroy ++** ++** Destroy an gckKERNEL object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object to destroy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS gckVGKERNEL_Destroy( ++ IN gckVGKERNEL Kernel ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Kernel=0x%x", Kernel); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ do ++ { ++ /* Destroy the gckVGMMU object. */ ++ if (Kernel->mmu != gcvNULL) ++ { ++ gcmkERR_BREAK(gckVGMMU_Destroy(Kernel->mmu)); ++ Kernel->mmu = gcvNULL; ++ } ++ ++ /* Destroy the gckVGCOMMAND object. */ ++ if (Kernel->command != gcvNULL) ++ { ++ gcmkERR_BREAK(gckVGCOMMAND_Destroy(Kernel->command)); ++ Kernel->command = gcvNULL; ++ } ++ ++ /* Destroy the gckVGINTERRUPT object. */ ++ if (Kernel->interrupt != gcvNULL) ++ { ++ gcmkERR_BREAK(gckVGINTERRUPT_Destroy(Kernel->interrupt)); ++ Kernel->interrupt = gcvNULL; ++ } ++ ++ /* Destroy the gckVGHARDWARE object. */ ++ if (Kernel->hardware != gcvNULL) ++ { ++ gcmkERR_BREAK(gckVGHARDWARE_Destroy(Kernel->hardware)); ++ Kernel->hardware = gcvNULL; ++ } ++ ++ /* Mark the gckKERNEL object as unknown. */ ++ Kernel->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckKERNEL object. */ ++ gcmkERR_BREAK(gckOS_Free(Kernel->os, Kernel)); ++ } ++ while (gcvFALSE); ++ ++ gcmkFOOTER(); ++ ++ /* Return status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_AllocateLinearMemory ++** ++** Function walks all required memory pools and allocates the requested ++** amount of video memory. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcePOOL * Pool ++** Pointer the desired memory pool. ++** ++** gctSIZE_T Bytes ++** Number of bytes to allocate. ++** ++** gctSIZE_T Alignment ++** Required buffer alignment. ++** ++** gceSURF_TYPE Type ++** Surface type. ++** ++** OUTPUT: ++** ++** gcePOOL * Pool ++** Pointer to the actual pool where the memory was allocated. ++** ++** gcuVIDMEM_NODE_PTR * Node ++** Allocated node. ++*/ ++gceSTATUS ++gckVGKERNEL_AllocateLinearMemory( ++ IN gckKERNEL Kernel, ++ IN OUT gcePOOL * Pool, ++ IN gctSIZE_T Bytes, ++ IN gctUINT32 Alignment, ++ IN gceSURF_TYPE Type, ++ OUT gcuVIDMEM_NODE_PTR * Node ++ ) ++{ ++ gcePOOL pool; ++ gceSTATUS status; ++ gckVIDMEM videoMemory; ++ ++ /* Get initial pool. */ ++ switch (pool = *Pool) ++ { ++ case gcvPOOL_DEFAULT: ++ case gcvPOOL_LOCAL: ++ pool = gcvPOOL_LOCAL_INTERNAL; ++ break; ++ ++ case gcvPOOL_UNIFIED: ++ pool = gcvPOOL_SYSTEM; ++ break; ++ ++ default: ++ break; ++ } ++ ++ do ++ { ++ /* Verify the number of bytes to allocate. */ ++ if (Bytes == 0) ++ { ++ status = gcvSTATUS_INVALID_ARGUMENT; ++ break; ++ } ++ ++ if (pool == gcvPOOL_VIRTUAL) ++ { ++ /* Create a gcuVIDMEM_NODE for virtual memory. */ ++ gcmkERR_BREAK(gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node)); ++ ++ /* Success. */ ++ break; ++ } ++ ++ else ++ { ++ /* Get pointer to gckVIDMEM object for pool. */ ++ status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory); ++ ++ if (status == gcvSTATUS_OK) ++ { ++ /* Allocate memory. */ ++ status = gckVIDMEM_AllocateLinear(Kernel, ++ videoMemory, ++ Bytes, ++ Alignment, ++ Type, ++ (*Pool == gcvPOOL_SYSTEM), ++ Node); ++ ++ if (status == gcvSTATUS_OK) ++ { ++ /* Memory allocated. */ ++ break; ++ } ++ } ++ } ++ ++ if (pool == gcvPOOL_LOCAL_INTERNAL) ++ { ++ /* Advance to external memory. */ ++ pool = gcvPOOL_LOCAL_EXTERNAL; ++ } ++ else if (pool == gcvPOOL_LOCAL_EXTERNAL) ++ { ++ /* Advance to contiguous system memory. */ ++ pool = gcvPOOL_SYSTEM; ++ } ++ else if (pool == gcvPOOL_SYSTEM) ++ { ++ /* Advance to virtual memory. */ ++ pool = gcvPOOL_VIRTUAL; ++ } ++ else ++ { ++ /* Out of pools. */ ++ break; ++ } ++ } ++ /* Loop only for multiple selection pools. */ ++ while ((*Pool == gcvPOOL_DEFAULT) ++ || (*Pool == gcvPOOL_LOCAL) ++ || (*Pool == gcvPOOL_UNIFIED) ++ ); ++ ++ if (gcmIS_SUCCESS(status)) ++ { ++ /* Return pool used for allocation. */ ++ *Pool = pool; ++ } ++ ++ /* Return status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_Dispatch ++** ++** Dispatch a command received from the user HAL layer. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that defines the command to ++** be dispatched. ++** ++** OUTPUT: ++** ++** gcsHAL_INTERFACE * Interface ++** Pointer to a gcsHAL_INTERFACE structure that receives any data to be ++** returned. ++*/ ++gceSTATUS gckVGKERNEL_Dispatch( ++ IN gckKERNEL Kernel, ++ IN gctBOOL FromUser, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ) ++{ ++ gceSTATUS status; ++ gcsHAL_INTERFACE * kernelInterface = Interface; ++ gctUINT32 processID; ++ gckKERNEL kernel = Kernel; ++ gctPOINTER info = gcvNULL; ++ gctPHYS_ADDR physical = gcvNULL; ++ gctPOINTER logical = gcvNULL; ++ gctSIZE_T bytes = 0; ++ ++ gcmkHEADER_ARG("Kernel=0x%x Interface=0x%x ", Kernel, Interface); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Interface != gcvNULL); ++ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ /* Dispatch on command. */ ++ switch (Interface->command) ++ { ++ case gcvHAL_QUERY_VIDEO_MEMORY: ++ /* Query video memory size. */ ++ gcmkERR_BREAK(gckKERNEL_QueryVideoMemory( ++ Kernel, kernelInterface ++ )); ++ break; ++ ++ case gcvHAL_QUERY_CHIP_IDENTITY: ++ /* Query chip identity. */ ++ gcmkERR_BREAK(gckVGHARDWARE_QueryChipIdentity( ++ Kernel->vg->hardware, ++ &kernelInterface->u.QueryChipIdentity.chipModel, ++ &kernelInterface->u.QueryChipIdentity.chipRevision, ++ &kernelInterface->u.QueryChipIdentity.chipFeatures, ++ &kernelInterface->u.QueryChipIdentity.chipMinorFeatures, ++ &kernelInterface->u.QueryChipIdentity.chipMinorFeatures2 ++ )); ++ break; ++ ++ case gcvHAL_QUERY_COMMAND_BUFFER: ++ /* Query command buffer information. */ ++ gcmkERR_BREAK(gckKERNEL_QueryCommandBuffer( ++ Kernel, ++ &kernelInterface->u.QueryCommandBuffer.information ++ )); ++ break; ++ case gcvHAL_ALLOCATE_NON_PAGED_MEMORY: ++ bytes = (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes; ++ /* Allocate non-paged memory. */ ++ gcmkERR_BREAK(gckOS_AllocateNonPagedMemory( ++ Kernel->os, ++ gcvTRUE, ++ &bytes, ++ &physical, ++ &logical ++ )); ++ ++ kernelInterface->u.AllocateNonPagedMemory.bytes = bytes; ++ kernelInterface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical); ++ kernelInterface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical); ++ break; ++ ++ case gcvHAL_FREE_NON_PAGED_MEMORY: ++ physical = gcmNAME_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.physical); ++ ++ /* Unmap user logical out of physical memory first. */ ++ gcmkERR_BREAK(gckOS_UnmapUserLogical( ++ Kernel->os, ++ physical, ++ (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes, ++ gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical) ++ )); ++ ++ /* Free non-paged memory. */ ++ gcmkERR_BREAK(gckOS_FreeNonPagedMemory( ++ Kernel->os, ++ (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes, ++ physical, ++ gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical) ++ )); ++ ++ gcmRELEASE_NAME(kernelInterface->u.AllocateNonPagedMemory.physical); ++ break; ++ ++ case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY: ++ bytes = (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes; ++ /* Allocate contiguous memory. */ ++ gcmkERR_BREAK(gckOS_AllocateContiguous( ++ Kernel->os, ++ gcvTRUE, ++ &bytes, ++ &physical, ++ &logical ++ )); ++ ++ kernelInterface->u.AllocateNonPagedMemory.bytes = bytes; ++ kernelInterface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical); ++ kernelInterface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical); ++ break; ++ ++ case gcvHAL_FREE_CONTIGUOUS_MEMORY: ++ physical = gcmNAME_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.physical); ++ /* Unmap user logical out of physical memory first. */ ++ gcmkERR_BREAK(gckOS_UnmapUserLogical( ++ Kernel->os, ++ physical, ++ (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes, ++ gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical) ++ )); ++ ++ /* Free contiguous memory. */ ++ gcmkERR_BREAK(gckOS_FreeContiguous( ++ Kernel->os, ++ physical, ++ gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical), ++ (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes ++ )); ++ ++ gcmRELEASE_NAME(kernelInterface->u.AllocateNonPagedMemory.physical); ++ break; ++ ++ case gcvHAL_ALLOCATE_VIDEO_MEMORY: ++ gcmkERR_BREAK(gcvSTATUS_NOT_SUPPORTED); ++ break; ++ ++ case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY: ++ /* Allocate memory. */ ++ gcmkERR_BREAK(gckKERNEL_AllocateLinearMemory( ++ Kernel, processID, ++ &kernelInterface->u.AllocateLinearVideoMemory.pool, ++ kernelInterface->u.AllocateLinearVideoMemory.bytes, ++ kernelInterface->u.AllocateLinearVideoMemory.alignment, ++ kernelInterface->u.AllocateLinearVideoMemory.type, ++ kernelInterface->u.AllocateLinearVideoMemory.flag, ++ &kernelInterface->u.AllocateLinearVideoMemory.node ++ )); ++ ++ break; ++ ++ case gcvHAL_RELEASE_VIDEO_MEMORY: ++ /* Free video memory. */ ++ gcmkERR_BREAK(gckKERNEL_ReleaseVideoMemory( ++ Kernel, processID, ++ (gctUINT32)kernelInterface->u.ReleaseVideoMemory.node ++ )); ++ ++ break; ++ ++ case gcvHAL_MAP_MEMORY: ++ /* Map memory. */ ++ gcmkERR_BREAK(gckKERNEL_MapMemory( ++ Kernel, ++ gcmINT2PTR(kernelInterface->u.MapMemory.physical), ++ (gctSIZE_T) kernelInterface->u.MapMemory.bytes, ++ &logical ++ )); ++ kernelInterface->u.MapMemory.logical = gcmPTR_TO_UINT64(logical); ++ break; ++ ++ case gcvHAL_UNMAP_MEMORY: ++ /* Unmap memory. */ ++ gcmkERR_BREAK(gckKERNEL_UnmapMemory( ++ Kernel, ++ gcmINT2PTR(kernelInterface->u.MapMemory.physical), ++ (gctSIZE_T) kernelInterface->u.MapMemory.bytes, ++ gcmUINT64_TO_PTR(kernelInterface->u.MapMemory.logical) ++ )); ++ break; ++ ++ case gcvHAL_MAP_USER_MEMORY: ++ /* Map user memory to DMA. */ ++ gcmkERR_BREAK(gckOS_MapUserMemory( ++ Kernel->os, ++ gcvCORE_VG, ++ gcmUINT64_TO_PTR(kernelInterface->u.MapUserMemory.memory), ++ kernelInterface->u.MapUserMemory.physical, ++ (gctSIZE_T) kernelInterface->u.MapUserMemory.size, ++ &info, ++ &kernelInterface->u.MapUserMemory.address ++ )); ++ ++ kernelInterface->u.MapUserMemory.info = gcmPTR_TO_NAME(info); ++ ++ /* Clear temp storage. */ ++ info = gcvNULL; ++ break; ++ ++ case gcvHAL_UNMAP_USER_MEMORY: ++ /* Unmap user memory. */ ++ gcmkERR_BREAK(gckOS_UnmapUserMemory( ++ Kernel->os, ++ gcvCORE_VG, ++ gcmUINT64_TO_PTR(kernelInterface->u.UnmapUserMemory.memory), ++ (gctSIZE_T) kernelInterface->u.UnmapUserMemory.size, ++ gcmNAME_TO_PTR(kernelInterface->u.UnmapUserMemory.info), ++ kernelInterface->u.UnmapUserMemory.address ++ )); ++ ++ gcmRELEASE_NAME(kernelInterface->u.UnmapUserMemory.info); ++ break; ++ ++ case gcvHAL_LOCK_VIDEO_MEMORY: ++ gcmkONERROR(gckKERNEL_LockVideoMemory(Kernel, gcvCORE_VG, processID, FromUser, Interface)); ++ break; ++ ++ case gcvHAL_UNLOCK_VIDEO_MEMORY: ++ gcmkONERROR(gckKERNEL_UnlockVideoMemory(Kernel, processID, Interface)); ++ break; ++ ++ case gcvHAL_USER_SIGNAL: ++ /* Dispatch depends on the user signal subcommands. */ ++ switch(Interface->u.UserSignal.command) ++ { ++ case gcvUSER_SIGNAL_CREATE: ++ /* Create a signal used in the user space. */ ++ gcmkERR_BREAK( ++ gckOS_CreateUserSignal(Kernel->os, ++ Interface->u.UserSignal.manualReset, ++ &Interface->u.UserSignal.id)); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_SIGNAL, ++ gcmINT2PTR(Interface->u.UserSignal.id), ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvUSER_SIGNAL_DESTROY: ++ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( ++ Kernel, ++ processID, gcvDB_SIGNAL, ++ gcmINT2PTR(Interface->u.UserSignal.id))); ++ ++ /* Destroy the signal. */ ++ gcmkERR_BREAK( ++ gckOS_DestroyUserSignal(Kernel->os, ++ Interface->u.UserSignal.id)); ++ ++ break; ++ ++ case gcvUSER_SIGNAL_SIGNAL: ++ /* Signal the signal. */ ++ gcmkERR_BREAK( ++ gckOS_SignalUserSignal(Kernel->os, ++ Interface->u.UserSignal.id, ++ Interface->u.UserSignal.state)); ++ break; ++ ++ case gcvUSER_SIGNAL_WAIT: ++ /* Wait on the signal. */ ++ status = gckOS_WaitUserSignal(Kernel->os, ++ Interface->u.UserSignal.id, ++ Interface->u.UserSignal.wait); ++ break; ++ ++ default: ++ /* Invalid user signal command. */ ++ gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT); ++ } ++ break; ++ ++ case gcvHAL_COMMIT: ++ /* Commit a command and context buffer. */ ++ gcmkERR_BREAK(gckVGCOMMAND_Commit( ++ Kernel->vg->command, ++ gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.context), ++ gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.queue), ++ kernelInterface->u.VGCommit.entryCount, ++ gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.taskTable) ++ )); ++ break; ++ case gcvHAL_VERSION: ++ kernelInterface->u.Version.major = gcvVERSION_MAJOR; ++ kernelInterface->u.Version.minor = gcvVERSION_MINOR; ++ kernelInterface->u.Version.patch = gcvVERSION_PATCH; ++ kernelInterface->u.Version.build = gcvVERSION_BUILD; ++ status = gcvSTATUS_OK; ++ break; ++ ++ case gcvHAL_GET_BASE_ADDRESS: ++ /* Get base address. */ ++ gcmkERR_BREAK( ++ gckOS_GetBaseAddress(Kernel->os, ++ &kernelInterface->u.GetBaseAddress.baseAddress)); ++ break; ++ case gcvHAL_IMPORT_VIDEO_MEMORY: ++ gcmkONERROR(gckVIDMEM_NODE_Import(Kernel, ++ Interface->u.ImportVideoMemory.name, ++ &Interface->u.ImportVideoMemory.handle)); ++ gcmkONERROR(gckKERNEL_AddProcessDB(Kernel, ++ processID, gcvDB_VIDEO_MEMORY, ++ gcmINT2PTR(Interface->u.ImportVideoMemory.handle), ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvHAL_NAME_VIDEO_MEMORY: ++ gcmkONERROR(gckVIDMEM_NODE_Name(Kernel, ++ Interface->u.NameVideoMemory.handle, ++ &Interface->u.NameVideoMemory.name)); ++ break; ++ ++ case gcvHAL_DATABASE: ++ gcmkONERROR(gckKERNEL_QueryDatabase(Kernel, processID, Interface)); ++ break; ++ case gcvHAL_SHBUF: ++ { ++ gctSHBUF shBuf; ++ gctPOINTER uData; ++ gctUINT32 bytes; ++ ++ switch (Interface->u.ShBuf.command) ++ { ++ case gcvSHBUF_CREATE: ++ bytes = Interface->u.ShBuf.bytes; ++ ++ /* Create. */ ++ gcmkONERROR(gckKERNEL_CreateShBuffer(Kernel, bytes, &shBuf)); ++ ++ Interface->u.ShBuf.id = gcmPTR_TO_UINT64(shBuf); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, ++ gcvDB_SHBUF, ++ shBuf, ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvSHBUF_DESTROY: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ ++ /* Check db first to avoid illegal destroy in the process. */ ++ gcmkONERROR( ++ gckKERNEL_RemoveProcessDB(Kernel, ++ processID, ++ gcvDB_SHBUF, ++ shBuf)); ++ ++ gcmkONERROR(gckKERNEL_DestroyShBuffer(Kernel, shBuf)); ++ break; ++ ++ case gcvSHBUF_MAP: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ ++ /* Map for current process access. */ ++ gcmkONERROR(gckKERNEL_MapShBuffer(Kernel, shBuf)); ++ ++ gcmkVERIFY_OK( ++ gckKERNEL_AddProcessDB(Kernel, ++ processID, ++ gcvDB_SHBUF, ++ shBuf, ++ gcvNULL, ++ 0)); ++ break; ++ ++ case gcvSHBUF_WRITE: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data); ++ bytes = Interface->u.ShBuf.bytes; ++ ++ /* Write. */ ++ gcmkONERROR( ++ gckKERNEL_WriteShBuffer(Kernel, shBuf, uData, bytes)); ++ break; ++ ++ case gcvSHBUF_READ: ++ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id); ++ uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data); ++ bytes = Interface->u.ShBuf.bytes; ++ ++ /* Read. */ ++ gcmkONERROR( ++ gckKERNEL_ReadShBuffer(Kernel, ++ shBuf, ++ uData, ++ bytes, ++ &bytes)); ++ ++ /* Return copied size. */ ++ Interface->u.ShBuf.bytes = bytes; ++ break; ++ ++ default: ++ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); ++ break; ++ } ++ } ++ break; ++ default: ++ /* Invalid command. */ ++ status = gcvSTATUS_INVALID_ARGUMENT; ++ } ++ ++OnError: ++ /* Save status. */ ++ kernelInterface->status = status; ++ ++ gcmkFOOTER(); ++ ++ /* Return the status. */ ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckKERNEL_QueryCommandBuffer ++** ++** Query command buffer attributes. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckVGHARDWARE object. ++** ++** OUTPUT: ++** ++** gcsCOMMAND_BUFFER_INFO_PTR Information ++** Pointer to the information structure to receive buffer attributes. ++*/ ++gceSTATUS ++gckKERNEL_QueryCommandBuffer( ++ IN gckKERNEL Kernel, ++ OUT gcsCOMMAND_BUFFER_INFO_PTR Information ++ ) ++{ ++ gceSTATUS status; ++ ++ gcmkHEADER_ARG("Kernel=0x%x *Pool=0x%x", ++ Kernel, Information); ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Get the information. */ ++ status = gckVGCOMMAND_QueryCommandBuffer(Kernel->vg->command, Information); ++ ++ gcmkFOOTER(); ++ /* Return status. */ ++ return status; ++} ++ ++#endif /* gcdENABLE_VG */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_vg.h linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_vg.h +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_vg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_vg.h 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,85 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_vg_h_ ++#define __gc_hal_kernel_vg_h_ ++ ++#include "gc_hal.h" ++#include "gc_hal_driver.h" ++#include "gc_hal_kernel_hardware.h" ++ ++/******************************************************************************\ ++********************************** Structures ********************************** ++\******************************************************************************/ ++ ++/* gckKERNEL object. */ ++struct _gckVGKERNEL ++{ ++ /* Object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gckOS object. */ ++ gckOS os; ++ ++ /* Pointer to gckHARDWARE object. */ ++ gckVGHARDWARE hardware; ++ ++ /* Pointer to gckINTERRUPT object. */ ++ gckVGINTERRUPT interrupt; ++ ++ /* Pointer to gckCOMMAND object. */ ++ gckVGCOMMAND command; ++ ++ /* Pointer to context. */ ++ gctPOINTER context; ++ ++ /* Pointer to gckMMU object. */ ++ gckVGMMU mmu; ++ ++ gckKERNEL kernel; ++}; ++ ++/* gckMMU object. */ ++struct _gckVGMMU ++{ ++ /* The object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to gckOS object. */ ++ gckOS os; ++ ++ /* Pointer to gckHARDWARE object. */ ++ gckVGHARDWARE hardware; ++ ++ /* The page table mutex. */ ++ gctPOINTER mutex; ++ ++ /* Page table information. */ ++ gctSIZE_T pageTableSize; ++ gctPHYS_ADDR pageTablePhysical; ++ gctPOINTER pageTableLogical; ++ ++ /* Allocation index. */ ++ gctUINT32 entryCount; ++ gctUINT32 entry; ++}; ++ ++#endif /* __gc_hal_kernel_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_video_memory.c linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_video_memory.c +--- linux-3.14.72.orig/drivers/gpu/galcore/gc_hal_kernel_video_memory.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/gc_hal_kernel_video_memory.c 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1,2734 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_precomp.h" ++ ++#define _GC_OBJ_ZONE gcvZONE_VIDMEM ++ ++/******************************************************************************\ ++******************************* Private Functions ****************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** _Split ++** ++** Split a node on the required byte boundary. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to the node to split. ++** ++** gctSIZE_T Bytes ++** Number of bytes to keep in the node. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++** RETURNS: ++** ++** gctBOOL ++** gcvTRUE if the node was split successfully, or gcvFALSE if there is an ++** error. ++** ++*/ ++static gctBOOL ++_Split( ++ IN gckOS Os, ++ IN gcuVIDMEM_NODE_PTR Node, ++ IN gctSIZE_T Bytes ++ ) ++{ ++ gcuVIDMEM_NODE_PTR node; ++ gctPOINTER pointer = gcvNULL; ++ ++ /* Make sure the byte boundary makes sense. */ ++ if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes)) ++ { ++ return gcvFALSE; ++ } ++ ++ /* Allocate a new gcuVIDMEM_NODE object. */ ++ if (gcmIS_ERROR(gckOS_Allocate(Os, ++ gcmSIZEOF(gcuVIDMEM_NODE), ++ &pointer))) ++ { ++ /* Error. */ ++ return gcvFALSE; ++ } ++ ++ node = pointer; ++ ++ /* Initialize gcuVIDMEM_NODE structure. */ ++ node->VidMem.offset = Node->VidMem.offset + Bytes; ++ node->VidMem.bytes = Node->VidMem.bytes - Bytes; ++ node->VidMem.alignment = 0; ++ node->VidMem.locked = 0; ++ node->VidMem.memory = Node->VidMem.memory; ++ node->VidMem.pool = Node->VidMem.pool; ++ node->VidMem.physical = Node->VidMem.physical; ++ ++ /* Insert node behind specified node. */ ++ node->VidMem.next = Node->VidMem.next; ++ node->VidMem.prev = Node; ++ Node->VidMem.next = node->VidMem.next->VidMem.prev = node; ++ ++ /* Insert free node behind specified node. */ ++ node->VidMem.nextFree = Node->VidMem.nextFree; ++ node->VidMem.prevFree = Node; ++ Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node; ++ ++ /* Adjust size of specified node. */ ++ Node->VidMem.bytes = Bytes; ++ ++ /* Success. */ ++ return gcvTRUE; ++} ++ ++/******************************************************************************* ++** ++** _Merge ++** ++** Merge two adjacent nodes together. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to the first of the two nodes to merge. ++** ++** OUTPUT: ++** ++** Nothing. ++** ++*/ ++static gceSTATUS ++_Merge( ++ IN gckOS Os, ++ IN gcuVIDMEM_NODE_PTR Node ++ ) ++{ ++ gcuVIDMEM_NODE_PTR node; ++ gceSTATUS status; ++ ++ /* Save pointer to next node. */ ++ node = Node->VidMem.next; ++ ++ /* This is a good time to make sure the heap is not corrupted. */ ++ if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset) ++ { ++ /* Corrupted heap. */ ++ gcmkASSERT( ++ Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset); ++ return gcvSTATUS_HEAP_CORRUPTED; ++ } ++ ++ /* Adjust byte count. */ ++ Node->VidMem.bytes += node->VidMem.bytes; ++ ++ /* Unlink next node from linked list. */ ++ Node->VidMem.next = node->VidMem.next; ++ Node->VidMem.nextFree = node->VidMem.nextFree; ++ ++ Node->VidMem.next->VidMem.prev = ++ Node->VidMem.nextFree->VidMem.prevFree = Node; ++ ++ /* Free next node. */ ++ status = gcmkOS_SAFE_FREE(Os, node); ++ return status; ++} ++ ++/******************************************************************************\ ++******************************* gckVIDMEM API Code ****************************** ++\******************************************************************************/ ++ ++/******************************************************************************* ++** ++** gckVIDMEM_ConstructVirtual ++** ++** Construct a new gcuVIDMEM_NODE union for virtual memory. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctSIZE_T Bytes ++** Number of byte to allocate. ++** ++** OUTPUT: ++** ++** gcuVIDMEM_NODE_PTR * Node ++** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer. ++*/ ++gceSTATUS ++gckVIDMEM_ConstructVirtual( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Flag, ++ IN gctSIZE_T Bytes, ++ OUT gcuVIDMEM_NODE_PTR * Node ++ ) ++{ ++ gckOS os; ++ gceSTATUS status; ++ gcuVIDMEM_NODE_PTR node = gcvNULL; ++ gctPOINTER pointer = gcvNULL; ++ gctINT i; ++ ++ gcmkHEADER_ARG("Kernel=0x%x Flag=%x Bytes=%lu", Kernel, Flag, Bytes); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Node != gcvNULL); ++ ++ /* Extract the gckOS object pointer. */ ++ os = Kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Allocate an gcuVIDMEM_NODE union. */ ++ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer)); ++ ++ node = pointer; ++ ++ /* Initialize gcuVIDMEM_NODE union for virtual memory. */ ++ node->Virtual.kernel = Kernel; ++ node->Virtual.contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS; ++ node->Virtual.logical = gcvNULL; ++#if gcdENABLE_VG ++ node->Virtual.kernelVirtual = gcvNULL; ++#endif ++ ++ for (i = 0; i < gcdMAX_GPU_COUNT; i++) ++ { ++ node->Virtual.lockeds[i] = 0; ++ node->Virtual.pageTables[i] = gcvNULL; ++ node->Virtual.lockKernels[i] = gcvNULL; ++ } ++ ++ gcmkONERROR(gckOS_GetProcessID(&node->Virtual.processID)); ++ ++ /* Allocate the virtual memory. */ ++ gcmkONERROR( ++ gckOS_AllocatePagedMemoryEx(os, ++ Flag, ++ node->Virtual.bytes = Bytes, ++ &node->Virtual.gid, ++ &node->Virtual.physical)); ++ ++ /* Return pointer to the gcuVIDMEM_NODE union. */ ++ *Node = node; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Created virtual node 0x%x for %u bytes @ 0x%x", ++ node, Bytes, node->Virtual.physical); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Node=0x%x", *Node); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (node != gcvNULL) ++ { ++ /* Free the structure. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_DestroyVirtual ++** ++** Destroy an gcuVIDMEM_NODE union for virtual memory. ++** ++** INPUT: ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to a gcuVIDMEM_NODE union. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckVIDMEM_DestroyVirtual( ++ IN gcuVIDMEM_NODE_PTR Node ++ ) ++{ ++ gckOS os; ++ ++ gcmkHEADER_ARG("Node=0x%x", Node); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); ++ ++ /* Extact the gckOS object pointer. */ ++ os = Node->Virtual.kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Delete the gcuVIDMEM_NODE union. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, Node)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_Construct ++** ++** Construct a new gckVIDMEM object. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 BaseAddress ++** Base address for the video memory heap. ++** ++** gctSIZE_T Bytes ++** Number of bytes in the video memory heap. ++** ++** gctSIZE_T Threshold ++** Minimum number of bytes beyond am allocation before the node is ++** split. Can be used as a minimum alignment requirement. ++** ++** gctSIZE_T BankSize ++** Number of bytes per physical memory bank. Used by bank ++** optimization. ++** ++** OUTPUT: ++** ++** gckVIDMEM * Memory ++** Pointer to a variable that will hold the pointer to the gckVIDMEM ++** object. ++*/ ++gceSTATUS ++gckVIDMEM_Construct( ++ IN gckOS Os, ++ IN gctUINT32 BaseAddress, ++ IN gctSIZE_T Bytes, ++ IN gctSIZE_T Threshold, ++ IN gctSIZE_T BankSize, ++ OUT gckVIDMEM * Memory ++ ) ++{ ++ gckVIDMEM memory = gcvNULL; ++ gceSTATUS status; ++ gcuVIDMEM_NODE_PTR node; ++ gctINT i, banks = 0; ++ gctPOINTER pointer = gcvNULL; ++ gctUINT32 heapBytes; ++ gctUINT32 bankSize; ++ ++ gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu " ++ "BankSize=%lu", ++ Os, BaseAddress, Bytes, Threshold, BankSize); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Memory != gcvNULL); ++ ++ gcmkSAFECASTSIZET(heapBytes, Bytes); ++ gcmkSAFECASTSIZET(bankSize, BankSize); ++ ++ /* Allocate the gckVIDMEM object. */ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct _gckVIDMEM), &pointer)); ++ ++ memory = pointer; ++ ++ /* Initialize the gckVIDMEM object. */ ++ memory->object.type = gcvOBJ_VIDMEM; ++ memory->os = Os; ++ ++ /* Set video memory heap information. */ ++ memory->baseAddress = BaseAddress; ++ memory->bytes = heapBytes; ++ memory->freeBytes = heapBytes; ++ memory->threshold = Threshold; ++ memory->mutex = gcvNULL; ++ ++ BaseAddress = 0; ++ ++ /* Walk all possible banks. */ ++ for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i) ++ { ++ gctUINT32 bytes; ++ ++ if (BankSize == 0) ++ { ++ /* Use all bytes for the first bank. */ ++ bytes = heapBytes; ++ } ++ else ++ { ++ /* Compute number of bytes for this bank. */ ++ bytes = gcmALIGN(BaseAddress + 1, bankSize) - BaseAddress; ++ ++ if (bytes > heapBytes) ++ { ++ /* Make sure we don't exceed the total number of bytes. */ ++ bytes = heapBytes; ++ } ++ } ++ ++ if (bytes == 0) ++ { ++ /* Mark heap is not used. */ ++ memory->sentinel[i].VidMem.next = ++ memory->sentinel[i].VidMem.prev = ++ memory->sentinel[i].VidMem.nextFree = ++ memory->sentinel[i].VidMem.prevFree = gcvNULL; ++ continue; ++ } ++ ++ /* Allocate one gcuVIDMEM_NODE union. */ ++ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer)); ++ ++ node = pointer; ++ ++ /* Initialize gcuVIDMEM_NODE union. */ ++ node->VidMem.memory = memory; ++ ++ node->VidMem.next = ++ node->VidMem.prev = ++ node->VidMem.nextFree = ++ node->VidMem.prevFree = &memory->sentinel[i]; ++ ++ node->VidMem.offset = BaseAddress; ++ node->VidMem.bytes = bytes; ++ node->VidMem.alignment = 0; ++ node->VidMem.physical = 0; ++ node->VidMem.pool = gcvPOOL_UNKNOWN; ++ ++ node->VidMem.locked = 0; ++ ++#if gcdENABLE_VG ++ node->VidMem.kernelVirtual = gcvNULL; ++#endif ++ ++ /* Initialize the linked list of nodes. */ ++ memory->sentinel[i].VidMem.next = ++ memory->sentinel[i].VidMem.prev = ++ memory->sentinel[i].VidMem.nextFree = ++ memory->sentinel[i].VidMem.prevFree = node; ++ ++ /* Mark sentinel. */ ++ memory->sentinel[i].VidMem.bytes = 0; ++ ++ /* Adjust address for next bank. */ ++ BaseAddress += bytes; ++ heapBytes -= bytes; ++ banks ++; ++ } ++ ++ /* Assign all the bank mappings. */ ++ memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1; ++ memory->mapping[gcvSURF_BITMAP] = banks - 1; ++ if (banks > 1) --banks; ++ memory->mapping[gcvSURF_DEPTH] = banks - 1; ++ memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1; ++ if (banks > 1) --banks; ++ memory->mapping[gcvSURF_TEXTURE] = banks - 1; ++ if (banks > 1) --banks; ++ memory->mapping[gcvSURF_VERTEX] = banks - 1; ++ if (banks > 1) --banks; ++ memory->mapping[gcvSURF_INDEX] = banks - 1; ++ if (banks > 1) --banks; ++ memory->mapping[gcvSURF_TILE_STATUS] = banks - 1; ++ if (banks > 1) --banks; ++ memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0; ++ ++#if gcdENABLE_VG ++ memory->mapping[gcvSURF_IMAGE] = 0; ++ memory->mapping[gcvSURF_MASK] = 0; ++ memory->mapping[gcvSURF_SCISSOR] = 0; ++#endif ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "[GALCORE] INDEX: bank %d", ++ memory->mapping[gcvSURF_INDEX]); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "[GALCORE] VERTEX: bank %d", ++ memory->mapping[gcvSURF_VERTEX]); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "[GALCORE] TEXTURE: bank %d", ++ memory->mapping[gcvSURF_TEXTURE]); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "[GALCORE] RENDER_TARGET: bank %d", ++ memory->mapping[gcvSURF_RENDER_TARGET]); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "[GALCORE] DEPTH: bank %d", ++ memory->mapping[gcvSURF_DEPTH]); ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "[GALCORE] TILE_STATUS: bank %d", ++ memory->mapping[gcvSURF_TILE_STATUS]); ++ ++ /* Allocate the mutex. */ ++ gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex)); ++ ++ /* Return pointer to the gckVIDMEM object. */ ++ *Memory = memory; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Memory=0x%x", *Memory); ++ return gcvSTATUS_OK; ++ ++OnError: ++ /* Roll back. */ ++ if (memory != gcvNULL) ++ { ++ if (memory->mutex != gcvNULL) ++ { ++ /* Delete the mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex)); ++ } ++ ++ for (i = 0; i < banks; ++i) ++ { ++ /* Free the heap. */ ++ gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL); ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory->sentinel[i].VidMem.next)); ++ } ++ ++ /* Free the object. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_Destroy ++** ++** Destroy an gckVIDMEM object. ++** ++** INPUT: ++** ++** gckVIDMEM Memory ++** Pointer to an gckVIDMEM object to destroy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckVIDMEM_Destroy( ++ IN gckVIDMEM Memory ++ ) ++{ ++ gcuVIDMEM_NODE_PTR node, next; ++ gctINT i; ++ ++ gcmkHEADER_ARG("Memory=0x%x", Memory); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); ++ ++ /* Walk all sentinels. */ ++ for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) ++ { ++ /* Bail out of the heap is not used. */ ++ if (Memory->sentinel[i].VidMem.next == gcvNULL) ++ { ++ break; ++ } ++ ++ /* Walk all the nodes until we reach the sentinel. */ ++ for (node = Memory->sentinel[i].VidMem.next; ++ node->VidMem.bytes != 0; ++ node = next) ++ { ++ /* Save pointer to the next node. */ ++ next = node->VidMem.next; ++ ++ /* Free the node. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, node)); ++ } ++ } ++ ++ /* Free the mutex. */ ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex)); ++ ++ /* Mark the object as unknown. */ ++ Memory->object.type = gcvOBJ_UNKNOWN; ++ ++ /* Free the gckVIDMEM object. */ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, Memory)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++#if gcdENABLE_BANK_ALIGNMENT ++ ++#if !gcdBANK_BIT_START ++#error gcdBANK_BIT_START not defined. ++#endif ++ ++#if !gcdBANK_BIT_END ++#error gcdBANK_BIT_END not defined. ++#endif ++/******************************************************************************* ++** _GetSurfaceBankAlignment ++** ++** Return the required offset alignment required to the make BaseAddress ++** aligned properly. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to gcoOS object. ++** ++** gceSURF_TYPE Type ++** Type of allocation. ++** ++** gctUINT32 BaseAddress ++** Base address of current video memory node. ++** ++** OUTPUT: ++** ++** gctUINT32_PTR AlignmentOffset ++** Pointer to a variable that will hold the number of bytes to skip in ++** the current video memory node in order to make the alignment bank ++** aligned. ++*/ ++static gceSTATUS ++_GetSurfaceBankAlignment( ++ IN gckKERNEL Kernel, ++ IN gceSURF_TYPE Type, ++ IN gctUINT32 BaseAddress, ++ OUT gctUINT32_PTR AlignmentOffset ++ ) ++{ ++ gctUINT32 bank; ++ /* To retrieve the bank. */ ++ static const gctUINT32 bankMask = (0xFFFFFFFF << gcdBANK_BIT_START) ++ ^ (0xFFFFFFFF << (gcdBANK_BIT_END + 1)); ++ ++ /* To retrieve the bank and all the lower bytes. */ ++ static const gctUINT32 byteMask = ~(0xFFFFFFFF << (gcdBANK_BIT_END + 1)); ++ ++ gcmkHEADER_ARG("Type=%d BaseAddress=0x%x ", Type, BaseAddress); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(AlignmentOffset != gcvNULL); ++ ++ switch (Type) ++ { ++ case gcvSURF_RENDER_TARGET: ++ bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START); ++ ++ /* Align to the first bank. */ ++ *AlignmentOffset = (bank == 0) ? ++ 0 : ++ ((1 << (gcdBANK_BIT_END + 1)) + 0) - (BaseAddress & byteMask); ++ break; ++ ++ case gcvSURF_DEPTH: ++ bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START); ++ ++ /* Align to the third bank. */ ++ *AlignmentOffset = (bank == 2) ? ++ 0 : ++ ((1 << (gcdBANK_BIT_END + 1)) + (2 << gcdBANK_BIT_START)) - (BaseAddress & byteMask); ++ ++ /* Minimum 256 byte alignment needed for fast_msaa. */ ++ if ((gcdBANK_CHANNEL_BIT > 7) || ++ ((gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_FAST_MSAA) != gcvSTATUS_TRUE) && ++ (gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_SMALL_MSAA) != gcvSTATUS_TRUE))) ++ { ++ /* Add a channel offset at the channel bit. */ ++ *AlignmentOffset += (1 << gcdBANK_CHANNEL_BIT); ++ } ++ break; ++ ++ default: ++ /* no alignment needed. */ ++ *AlignmentOffset = 0; ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER_ARG("*AlignmentOffset=%u", *AlignmentOffset); ++ return gcvSTATUS_OK; ++} ++#endif ++ ++static gcuVIDMEM_NODE_PTR ++_FindNode( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM Memory, ++ IN gctINT Bank, ++ IN gctSIZE_T Bytes, ++ IN gceSURF_TYPE Type, ++ IN OUT gctUINT32_PTR Alignment ++ ) ++{ ++ gcuVIDMEM_NODE_PTR node; ++ gctUINT32 alignment; ++ ++#if gcdENABLE_BANK_ALIGNMENT ++ gctUINT32 bankAlignment; ++ gceSTATUS status; ++#endif ++ ++ if (Memory->sentinel[Bank].VidMem.nextFree == gcvNULL) ++ { ++ /* No free nodes left. */ ++ return gcvNULL; ++ } ++ ++#if gcdENABLE_BANK_ALIGNMENT ++ /* Walk all free nodes until we have one that is big enough or we have ++ ** reached the sentinel. */ ++ for (node = Memory->sentinel[Bank].VidMem.nextFree; ++ node->VidMem.bytes != 0; ++ node = node->VidMem.nextFree) ++ { ++ if (node->VidMem.bytes < Bytes) ++ { ++ continue; ++ } ++ ++ gcmkONERROR(_GetSurfaceBankAlignment( ++ Kernel, ++ Type, ++ node->VidMem.memory->baseAddress + node->VidMem.offset, ++ &bankAlignment)); ++ ++ bankAlignment = gcmALIGN(bankAlignment, *Alignment); ++ ++ /* Compute number of bytes to skip for alignment. */ ++ alignment = (*Alignment == 0) ++ ? 0 ++ : (*Alignment - (node->VidMem.offset % *Alignment)); ++ ++ if (alignment == *Alignment) ++ { ++ /* Node is already aligned. */ ++ alignment = 0; ++ } ++ ++ if (node->VidMem.bytes >= Bytes + alignment + bankAlignment) ++ { ++ /* This node is big enough. */ ++ *Alignment = alignment + bankAlignment; ++ return node; ++ } ++ } ++#endif ++ ++ /* Walk all free nodes until we have one that is big enough or we have ++ reached the sentinel. */ ++ for (node = Memory->sentinel[Bank].VidMem.nextFree; ++ node->VidMem.bytes != 0; ++ node = node->VidMem.nextFree) ++ { ++ gctUINT offset; ++ ++ gctINT modulo; ++ ++ gcmkSAFECASTSIZET(offset, node->VidMem.offset); ++ ++ modulo = gckMATH_ModuloInt(offset, *Alignment); ++ ++ /* Compute number of bytes to skip for alignment. */ ++ alignment = (*Alignment == 0) ? 0 : (*Alignment - modulo); ++ ++ if (alignment == *Alignment) ++ { ++ /* Node is already aligned. */ ++ alignment = 0; ++ } ++ ++ if (node->VidMem.bytes >= Bytes + alignment) ++ { ++ /* This node is big enough. */ ++ *Alignment = alignment; ++ return node; ++ } ++ } ++ ++#if gcdENABLE_BANK_ALIGNMENT ++OnError: ++#endif ++ /* Not enough memory. */ ++ return gcvNULL; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_AllocateLinear ++** ++** Allocate linear memory from the gckVIDMEM object. ++** ++** INPUT: ++** ++** gckVIDMEM Memory ++** Pointer to an gckVIDMEM object. ++** ++** gctSIZE_T Bytes ++** Number of bytes to allocate. ++** ++** gctUINT32 Alignment ++** Byte alignment for allocation. ++** ++** gceSURF_TYPE Type ++** Type of surface to allocate (use by bank optimization). ++** ++** gctBOOL Specified ++** If user must use this pool, it should set Specified to gcvTRUE, ++** otherwise allocator may reserve some memory for other usage, such ++** as small block size allocation request. ++** ++** OUTPUT: ++** ++** gcuVIDMEM_NODE_PTR * Node ++** Pointer to a variable that will hold the allocated memory node. ++*/ ++gceSTATUS ++gckVIDMEM_AllocateLinear( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM Memory, ++ IN gctSIZE_T Bytes, ++ IN gctUINT32 Alignment, ++ IN gceSURF_TYPE Type, ++ IN gctBOOL Specified, ++ OUT gcuVIDMEM_NODE_PTR * Node ++ ) ++{ ++ gceSTATUS status; ++ gcuVIDMEM_NODE_PTR node; ++ gctUINT32 alignment; ++ gctINT bank, i; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d", ++ Memory, Bytes, Alignment, Type); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); ++ gcmkVERIFY_ARGUMENT(Bytes > 0); ++ gcmkVERIFY_ARGUMENT(Node != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Type < gcvSURF_NUM_TYPES); ++ ++ /* Acquire the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); ++ ++ acquired = gcvTRUE; ++ ++ if (Bytes > Memory->freeBytes) ++ { ++ /* Not enough memory. */ ++ status = gcvSTATUS_OUT_OF_MEMORY; ++ goto OnError; ++ } ++ ++#if gcdSMALL_BLOCK_SIZE ++ if ((Memory->freeBytes < (Memory->bytes/gcdRATIO_FOR_SMALL_MEMORY)) ++ && (Bytes >= gcdSMALL_BLOCK_SIZE) ++ && (Specified == gcvFALSE) ++ ) ++ { ++ /* The left memory is for small memory.*/ ++ status = gcvSTATUS_OUT_OF_MEMORY; ++ goto OnError; ++ } ++#endif ++ ++ /* Find the default bank for this surface type. */ ++ gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping)); ++ bank = Memory->mapping[Type]; ++ alignment = Alignment; ++ ++ /* Find a free node in the default bank. */ ++ node = _FindNode(Kernel, Memory, bank, Bytes, Type, &alignment); ++ ++ /* Out of memory? */ ++ if (node == gcvNULL) ++ { ++ /* Walk all lower banks. */ ++ for (i = bank - 1; i >= 0; --i) ++ { ++ /* Find a free node inside the current bank. */ ++ node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment); ++ if (node != gcvNULL) ++ { ++ break; ++ } ++ } ++ } ++ ++ if (node == gcvNULL) ++ { ++ /* Walk all upper banks. */ ++ for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i) ++ { ++ if (Memory->sentinel[i].VidMem.nextFree == gcvNULL) ++ { ++ /* Abort when we reach unused banks. */ ++ break; ++ } ++ ++ /* Find a free node inside the current bank. */ ++ node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment); ++ if (node != gcvNULL) ++ { ++ break; ++ } ++ } ++ } ++ ++ if (node == gcvNULL) ++ { ++ /* Out of memory. */ ++ status = gcvSTATUS_OUT_OF_MEMORY; ++ goto OnError; ++ } ++ ++ /* Do we have an alignment? */ ++ if (alignment > 0) ++ { ++ /* Split the node so it is aligned. */ ++ if (_Split(Memory->os, node, alignment)) ++ { ++ /* Successful split, move to aligned node. */ ++ node = node->VidMem.next; ++ ++ /* Remove alignment. */ ++ alignment = 0; ++ } ++ } ++ ++ /* Do we have enough memory after the allocation to split it? */ ++ if (node->VidMem.bytes - Bytes > Memory->threshold) ++ { ++ /* Adjust the node size. */ ++ _Split(Memory->os, node, Bytes); ++ } ++ ++ /* Remove the node from the free list. */ ++ node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree; ++ node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree; ++ node->VidMem.nextFree = ++ node->VidMem.prevFree = gcvNULL; ++ ++ /* Fill in the information. */ ++ node->VidMem.alignment = alignment; ++ node->VidMem.memory = Memory; ++ ++ /* Adjust the number of free bytes. */ ++ Memory->freeBytes -= node->VidMem.bytes; ++ ++#if gcdENABLE_VG ++ node->VidMem.kernelVirtual = gcvNULL; ++#endif ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); ++ ++ /* Return the pointer to the node. */ ++ *Node = node; ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Allocated %u bytes @ 0x%x [0x%08X]", ++ node->VidMem.bytes, node, node->VidMem.offset); ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Node=0x%x", *Node); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_Free ++** ++** Free an allocated video memory node. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to a gcuVIDMEM_NODE object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckVIDMEM_Free( ++ IN gckKERNEL Kernel, ++ IN gcuVIDMEM_NODE_PTR Node ++ ) ++{ ++ gceSTATUS status; ++ gckKERNEL kernel = gcvNULL; ++ gckVIDMEM memory = gcvNULL; ++ gcuVIDMEM_NODE_PTR node; ++ gctBOOL mutexAcquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Node=0x%x", Node); ++ ++ /* Verify the arguments. */ ++ if ((Node == gcvNULL) ++ || (Node->VidMem.memory == gcvNULL) ++ ) ++ { ++ /* Invalid object. */ ++ gcmkONERROR(gcvSTATUS_INVALID_OBJECT); ++ } ++ ++ /**************************** Video Memory ********************************/ ++ ++ if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ++ { ++ /* Extract pointer to gckVIDMEM object owning the node. */ ++ memory = Node->VidMem.memory; ++ ++ /* Acquire the mutex. */ ++ gcmkONERROR( ++ gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE)); ++ ++ mutexAcquired = gcvTRUE; ++ ++#if gcdENABLE_VG ++ if (Node->VidMem.kernelVirtual) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "%s(%d) Unmap %x from kernel space.", ++ __FUNCTION__, __LINE__, ++ Node->VidMem.kernelVirtual); ++ ++ gcmkVERIFY_OK( ++ gckOS_UnmapPhysical(memory->os, ++ Node->VidMem.kernelVirtual, ++ Node->VidMem.bytes)); ++ ++ Node->VidMem.kernelVirtual = gcvNULL; ++ } ++#endif ++ ++ /* Check if Node is already freed. */ ++ if (Node->VidMem.nextFree) ++ { ++ /* Node is alread freed. */ ++ gcmkONERROR(gcvSTATUS_INVALID_DATA); ++ } ++ ++ /* Update the number of free bytes. */ ++ memory->freeBytes += Node->VidMem.bytes; ++ ++ /* Find the next free node. */ ++ for (node = Node->VidMem.next; ++ node != gcvNULL && node->VidMem.nextFree == gcvNULL; ++ node = node->VidMem.next) ; ++ ++ /* Insert this node in the free list. */ ++ Node->VidMem.nextFree = node; ++ Node->VidMem.prevFree = node->VidMem.prevFree; ++ ++ Node->VidMem.prevFree->VidMem.nextFree = ++ node->VidMem.prevFree = Node; ++ ++ /* Is the next node a free node and not the sentinel? */ ++ if ((Node->VidMem.next == Node->VidMem.nextFree) ++ && (Node->VidMem.next->VidMem.bytes != 0) ++ ) ++ { ++ /* Merge this node with the next node. */ ++ gcmkONERROR(_Merge(memory->os, node = Node)); ++ gcmkASSERT(node->VidMem.nextFree != node); ++ gcmkASSERT(node->VidMem.prevFree != node); ++ } ++ ++ /* Is the previous node a free node and not the sentinel? */ ++ if ((Node->VidMem.prev == Node->VidMem.prevFree) ++ && (Node->VidMem.prev->VidMem.bytes != 0) ++ ) ++ { ++ /* Merge this node with the previous node. */ ++ gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev)); ++ gcmkASSERT(node->VidMem.nextFree != node); ++ gcmkASSERT(node->VidMem.prevFree != node); ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex)); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Node 0x%x is freed.", ++ Node); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ } ++ ++ /*************************** Virtual Memory *******************************/ ++ ++ /* Get gckKERNEL object. */ ++ kernel = Node->Virtual.kernel; ++ ++ /* Verify the gckKERNEL object pointer. */ ++ gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL); ++ ++#if gcdENABLE_VG ++ if (Node->Virtual.kernelVirtual) ++ { ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "%s(%d) Unmap %x from kernel space.", ++ __FUNCTION__, __LINE__, ++ Node->Virtual.kernelVirtual); ++ ++ gcmkVERIFY_OK( ++ gckOS_UnmapPhysical(kernel->os, ++ Node->Virtual.kernelVirtual, ++ Node->Virtual.bytes)); ++ ++ Node->Virtual.kernelVirtual = gcvNULL; ++ } ++#endif ++ ++ /* Free the virtual memory. */ ++ gcmkVERIFY_OK(gckOS_FreePagedMemory(kernel->os, ++ Node->Virtual.physical, ++ Node->Virtual.bytes)); ++ ++ /* Destroy the gcuVIDMEM_NODE union. */ ++ gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node)); ++ ++ /* Success. */ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (mutexAcquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex( ++ memory->os, memory->mutex ++ )); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if !gcdPROCESS_ADDRESS_SPACE ++/******************************************************************************* ++** ++** _NeedVirtualMapping ++** ++** Whether setup GPU page table for video node. ++** ++** INPUT: ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to a gcuVIDMEM_NODE union. ++** ++** gceCORE Core ++** Id of current GPU. ++** ++** OUTPUT: ++** gctBOOL * NeedMapping ++** A pointer hold the result whether Node should be mapping. ++*/ ++static gceSTATUS ++_NeedVirtualMapping( ++ IN gckKERNEL Kernel, ++ IN gceCORE Core, ++ IN gcuVIDMEM_NODE_PTR Node, ++ OUT gctBOOL * NeedMapping ++) ++{ ++ gceSTATUS status; ++ gctUINT32 phys; ++ gctUINT32 end; ++ gcePOOL pool; ++ gctUINT32 offset; ++ gctUINT32 baseAddress; ++ gctUINT32 bytes; ++ ++ gcmkHEADER_ARG("Node=0x%X", Node); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Node != gcvNULL); ++ gcmkVERIFY_ARGUMENT(NeedMapping != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Core < gcdMAX_GPU_COUNT); ++ ++ if (Node->Virtual.contiguous) ++ { ++#if gcdENABLE_VG ++ if (Core == gcvCORE_VG) ++ { ++ *NeedMapping = gcvFALSE; ++ } ++ else ++#endif ++ { ++ /* Convert logical address into a physical address. */ ++ gcmkONERROR(gckOS_UserLogicalToPhysical( ++ Kernel->os, Node->Virtual.logical, &phys ++ )); ++ ++ gcmkONERROR(gckOS_GetBaseAddress(Kernel->os, &baseAddress)); ++ ++ gcmkASSERT(phys >= baseAddress); ++ ++ /* Subtract baseAddress to get a GPU address used for programming. */ ++ phys -= baseAddress; ++ ++ /* If part of region is belong to gcvPOOL_VIRTUAL, ++ ** whole region has to be mapped. */ ++ gcmkSAFECASTSIZET(bytes, Node->Virtual.bytes); ++ end = phys + bytes - 1; ++ ++ gcmkONERROR(gckHARDWARE_SplitMemory( ++ Kernel->hardware, end, &pool, &offset ++ )); ++ ++ *NeedMapping = (pool == gcvPOOL_VIRTUAL); ++ } ++ } ++ else ++ { ++ *NeedMapping = gcvTRUE; ++ } ++ ++ gcmkFOOTER_ARG("*NeedMapping=%d", *NeedMapping); ++ return gcvSTATUS_OK; ++ ++OnError: ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gcsGPU_MAP_PTR ++_FindGPUMap( ++ IN gcsGPU_MAP_PTR Head, ++ IN gctINT ProcessID ++ ) ++{ ++ gcsGPU_MAP_PTR map = Head; ++ ++ while (map) ++ { ++ if (map->pid == ProcessID) ++ { ++ return map; ++ } ++ ++ map = map->next; ++ } ++ ++ return gcvNULL; ++} ++ ++gcsGPU_MAP_PTR ++_CreateGPUMap( ++ IN gckOS Os, ++ IN gcsGPU_MAP_PTR *Head, ++ IN gcsGPU_MAP_PTR *Tail, ++ IN gctINT ProcessID ++ ) ++{ ++ gcsGPU_MAP_PTR gpuMap; ++ gctPOINTER pointer = gcvNULL; ++ ++ gckOS_Allocate(Os, sizeof(gcsGPU_MAP), &pointer); ++ ++ if (pointer == gcvNULL) ++ { ++ return gcvNULL; ++ } ++ ++ gpuMap = pointer; ++ ++ gckOS_ZeroMemory(pointer, sizeof(gcsGPU_MAP)); ++ ++ gpuMap->pid = ProcessID; ++ ++ if (!*Head) ++ { ++ *Head = *Tail = gpuMap; ++ } ++ else ++ { ++ gpuMap->prev = *Tail; ++ (*Tail)->next = gpuMap; ++ *Tail = gpuMap; ++ } ++ ++ return gpuMap; ++} ++ ++void ++_DestroyGPUMap( ++ IN gckOS Os, ++ IN gcsGPU_MAP_PTR *Head, ++ IN gcsGPU_MAP_PTR *Tail, ++ IN gcsGPU_MAP_PTR gpuMap ++ ) ++{ ++ ++ if (gpuMap == *Head) ++ { ++ if ((*Head = gpuMap->next) == gcvNULL) ++ { ++ *Tail = gcvNULL; ++ } ++ } ++ else ++ { ++ gpuMap->prev->next = gpuMap->next; ++ if (gpuMap == *Tail) ++ { ++ *Tail = gpuMap->prev; ++ } ++ else ++ { ++ gpuMap->next->prev = gpuMap->prev; ++ } ++ } ++ ++ gcmkOS_SAFE_FREE(Os, gpuMap); ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckVIDMEM_Lock ++** ++** Lock a video memory node and return its hardware specific address. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to a gcuVIDMEM_NODE union. ++** ++** OUTPUT: ++** ++** gctUINT32 * Address ++** Pointer to a variable that will hold the hardware specific address. ++** ++** gctUINT32 * PhysicalAddress ++** Pointer to a variable that will hold the bus address of a contiguous ++** video node. ++*/ ++gceSTATUS ++gckVIDMEM_Lock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ IN gctBOOL Cacheable, ++ OUT gctUINT32 * Address, ++ OUT gctUINT32 * Gid, ++ OUT gctUINT64 * PhysicalAddress ++ ) ++{ ++ gceSTATUS status; ++ gctBOOL acquired = gcvFALSE; ++ gctBOOL locked = gcvFALSE; ++ gckOS os = gcvNULL; ++#if !gcdPROCESS_ADDRESS_SPACE ++ gctBOOL needMapping = gcvFALSE; ++#endif ++ gctUINT32 baseAddress; ++ gctUINT32 physicalAddress; ++ gcuVIDMEM_NODE_PTR node = Node->node; ++ ++ gcmkHEADER_ARG("Node=0x%x", Node); ++ ++ /* Verify the arguments. */ ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Extract the gckOS object pointer. */ ++ os = Kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ if ((node == gcvNULL) ++ || (node->VidMem.memory == gcvNULL) ++ ) ++ { ++ /* Invalid object. */ ++ gcmkONERROR(gcvSTATUS_INVALID_OBJECT); ++ } ++ ++ /* Grab the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(os, Node->mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /**************************** Video Memory ********************************/ ++ ++ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ++ { ++ gctUINT32 offset; ++ ++ if (Cacheable == gcvTRUE) ++ { ++ gcmkONERROR(gcvSTATUS_INVALID_REQUEST); ++ } ++ ++ /* Increment the lock count. */ ++ node->VidMem.locked ++; ++ ++ /* Return the physical address of the node. */ ++ gcmkSAFECASTSIZET(offset, node->VidMem.offset); ++ ++ *Address = node->VidMem.memory->baseAddress ++ + offset ++ + node->VidMem.alignment; ++ ++ physicalAddress = *Address; ++ ++ /* Get hardware specific address. */ ++#if gcdENABLE_VG ++ if (Kernel->vg == gcvNULL) ++#endif ++ { ++ if (Kernel->hardware->mmuVersion == 0) ++ { ++ /* Convert physical to GPU address for old mmu. */ ++ gcmkONERROR(gckOS_GetBaseAddress(Kernel->os, &baseAddress)); ++ gcmkASSERT(*Address > baseAddress); ++ *Address -= baseAddress; ++ } ++ } ++ ++ gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical( ++ Kernel->os, ++ *Address, ++ Address ++ )); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Locked node 0x%x (%d) @ 0x%08X", ++ node, ++ node->VidMem.locked, ++ *Address); ++ } ++ ++ /*************************** Virtual Memory *******************************/ ++ ++ else ++ { ++ ++ *Gid = node->Virtual.gid; ++ ++#if gcdPAGED_MEMORY_CACHEABLE ++ /* Force video memory cacheable. */ ++ Cacheable = gcvTRUE; ++#endif ++ ++ gcmkONERROR( ++ gckOS_LockPages(os, ++ node->Virtual.physical, ++ node->Virtual.bytes, ++ Cacheable, ++ &node->Virtual.logical, ++ &node->Virtual.pageCount)); ++ ++ gcmkONERROR(gckOS_GetPhysicalAddress( ++ os, ++ node->Virtual.logical, ++ &physicalAddress ++ )); ++ ++#if gcdENABLE_VG ++ node->Virtual.physicalAddress = physicalAddress; ++#endif ++ ++#if !gcdPROCESS_ADDRESS_SPACE ++ /* Increment the lock count. */ ++ if (node->Virtual.lockeds[Kernel->core] ++ == 0) ++ { ++ locked = gcvTRUE; ++ ++ gcmkONERROR(_NeedVirtualMapping(Kernel, Kernel->core, node, &needMapping)); ++ ++ if (needMapping == gcvFALSE) ++ { ++ /* Get hardware specific address. */ ++#if gcdENABLE_VG ++ if (Kernel->vg != gcvNULL) ++ { ++ gcmkONERROR(gckVGHARDWARE_ConvertLogical( ++ Kernel->vg->hardware, ++ node->Virtual.logical, ++ gcvTRUE, ++ &node->Virtual.addresses[Kernel->core])); ++ } ++ else ++#endif ++ { ++ gcmkONERROR(gckHARDWARE_ConvertLogical( ++ Kernel->hardware, ++ node->Virtual.logical, ++ gcvTRUE, ++ &node->Virtual.addresses[Kernel->core])); ++ } ++ } ++ else ++ { ++#if gcdENABLE_VG ++ if (Kernel->vg != gcvNULL) ++ { ++ /* Allocate pages inside the MMU. */ ++ gcmkONERROR( ++ gckVGMMU_AllocatePages(Kernel->vg->mmu, ++ node->Virtual.pageCount, ++ &node->Virtual.pageTables[Kernel->core], ++ &node->Virtual.addresses[Kernel->core])); ++ } ++ else ++#endif ++ { ++ /* Allocate pages inside the MMU. */ ++ gcmkONERROR( ++ gckMMU_AllocatePagesEx(Kernel->mmu, ++ node->Virtual.pageCount, ++ node->Virtual.type, ++ &node->Virtual.pageTables[Kernel->core], ++ &node->Virtual.addresses[Kernel->core])); ++ } ++ ++ node->Virtual.lockKernels[Kernel->core] = Kernel; ++ ++ /* Map the pages. */ ++ gcmkONERROR( ++ gckOS_MapPagesEx(os, ++ Kernel->core, ++ node->Virtual.physical, ++ node->Virtual.pageCount, ++ node->Virtual.addresses[Kernel->core], ++ node->Virtual.pageTables[Kernel->core])); ++ ++#if gcdENABLE_VG ++ if (Kernel->core == gcvCORE_VG) ++ { ++ gcmkONERROR(gckVGMMU_Flush(Kernel->vg->mmu)); ++ } ++ else ++#endif ++ { ++ gcmkONERROR(gckMMU_Flush(Kernel->mmu, node->Virtual.type)); ++ } ++ } ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Mapped virtual node 0x%x to 0x%08X", ++ node, ++ node->Virtual.addresses[Kernel->core]); ++ } ++ ++ /* Return hardware address. */ ++ *Address = node->Virtual.addresses[Kernel->core]; ++#endif ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex)); ++ ++ *PhysicalAddress = (gctUINT64)physicalAddress; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Address=%08x", *Address); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (locked) ++ { ++ if (node->Virtual.pageTables[Kernel->core] != gcvNULL) ++ { ++#if gcdENABLE_VG ++ if (Kernel->vg != gcvNULL) ++ { ++ /* Free the pages from the MMU. */ ++ gcmkVERIFY_OK( ++ gckVGMMU_FreePages(Kernel->vg->mmu, ++ node->Virtual.pageTables[Kernel->core], ++ node->Virtual.pageCount)); ++ } ++ else ++#endif ++ { ++ /* Free the pages from the MMU. */ ++ gcmkVERIFY_OK( ++ gckMMU_FreePages(Kernel->mmu, ++ node->Virtual.pageTables[Kernel->core], ++ node->Virtual.pageCount)); ++ } ++ node->Virtual.pageTables[Kernel->core] = gcvNULL; ++ node->Virtual.lockKernels[Kernel->core] = gcvNULL; ++ } ++ ++ /* Unlock the pages. */ ++ gcmkVERIFY_OK( ++ gckOS_UnlockPages(os, ++ node->Virtual.physical, ++ node->Virtual.bytes, ++ node->Virtual.logical ++ )); ++ ++ node->Virtual.lockeds[Kernel->core]--; ++ } ++ ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_Unlock ++** ++** Unlock a video memory node. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to a locked gcuVIDMEM_NODE union. ++** ++** gceSURF_TYPE Type ++** Type of surface to unlock. ++** ++** gctBOOL * Asynchroneous ++** Pointer to a variable specifying whether the surface should be ++** unlocked asynchroneously or not. ++** ++** OUTPUT: ++** ++** gctBOOL * Asynchroneous ++** Pointer to a variable receiving the number of bytes used in the ++** command buffer specified by 'Commands'. If gcvNULL, there is no ++** command buffer. ++*/ ++gceSTATUS ++gckVIDMEM_Unlock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ IN gceSURF_TYPE Type, ++ IN OUT gctBOOL * Asynchroneous ++ ) ++{ ++ gceSTATUS status; ++ gckOS os = gcvNULL; ++ gctBOOL acquired = gcvFALSE; ++ gcuVIDMEM_NODE_PTR node = Node->node; ++ ++ gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d", ++ Node, Type, gcmOPT_VALUE(Asynchroneous)); ++ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ ++ /* Get the gckOS object pointer. */ ++ os = Kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Verify the arguments. */ ++ if ((node == gcvNULL) ++ || (node->VidMem.memory == gcvNULL) ++ ) ++ { ++ /* Invalid object. */ ++ gcmkONERROR(gcvSTATUS_INVALID_OBJECT); ++ } ++ ++ /* Grab the mutex. */ ++ gcmkONERROR(gckOS_AcquireMutex(os, Node->mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /**************************** Video Memory ********************************/ ++ ++ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ++ { ++ if (node->VidMem.locked <= 0) ++ { ++ /* The surface was not locked. */ ++ status = gcvSTATUS_MEMORY_UNLOCKED; ++ goto OnError; ++ } ++ ++ if (Asynchroneous != gcvNULL) ++ { ++ /* Schedule an event to sync with GPU. */ ++ *Asynchroneous = gcvTRUE; ++ } ++ else ++ { ++ /* Decrement the lock count. */ ++ node->VidMem.locked --; ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Unlocked node 0x%x (%d)", ++ node, ++ node->VidMem.locked); ++ } ++ ++ /*************************** Virtual Memory *******************************/ ++ ++ else ++ { ++ ++ ++ if (Asynchroneous == gcvNULL) ++ { ++#if !gcdPROCESS_ADDRESS_SPACE ++ if (node->Virtual.lockeds[Kernel->core] == 0) ++ { ++ status = gcvSTATUS_MEMORY_UNLOCKED; ++ goto OnError; ++ } ++ ++ /* Decrement lock count. */ ++ -- node->Virtual.lockeds[Kernel->core]; ++ ++ /* See if we can unlock the resources. */ ++ if (node->Virtual.lockeds[Kernel->core] == 0) ++ { ++ /* Free the page table. */ ++ if (node->Virtual.pageTables[Kernel->core] != gcvNULL) ++ { ++#if gcdENABLE_VG ++ if (Kernel->vg != gcvNULL) ++ { ++ gcmkONERROR( ++ gckVGMMU_FreePages(Kernel->vg->mmu, ++ node->Virtual.pageTables[Kernel->core], ++ node->Virtual.pageCount)); ++ } ++ else ++#endif ++ { ++ gcmkONERROR( ++ gckMMU_FreePages(Kernel->mmu, ++ node->Virtual.pageTables[Kernel->core], ++ node->Virtual.pageCount)); ++ } ++ ++ gcmkONERROR(gckOS_UnmapPages( ++ Kernel->os, ++ node->Virtual.pageCount, ++ node->Virtual.addresses[Kernel->core] ++ )); ++ ++ /* Mark page table as freed. */ ++ node->Virtual.pageTables[Kernel->core] = gcvNULL; ++ node->Virtual.lockKernels[Kernel->core] = gcvNULL; ++ } ++ } ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Unmapped virtual node 0x%x from 0x%08X", ++ node, node->Virtual.addresses[Kernel->core]); ++#endif ++ ++ } ++ ++ else ++ { ++ gcmkONERROR( ++ gckOS_UnlockPages(os, ++ node->Virtual.physical, ++ node->Virtual.bytes, ++ node->Virtual.logical)); ++ ++ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, ++ "Scheduled unlock for virtual node 0x%x", ++ node); ++ ++ /* Schedule the surface to be unlocked. */ ++ *Asynchroneous = gcvTRUE; ++ } ++ } ++ ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex)); ++ acquired = gcvFALSE; ++ ++ /* Success. */ ++ gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous)); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ /* Release the mutex. */ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex)); ++ } ++ ++ /* Return the status. */ ++ gcmkFOOTER(); ++ return status; ++} ++ ++#if gcdPROCESS_ADDRESS_SPACE ++gceSTATUS ++gckVIDMEM_Node_Lock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ OUT gctUINT32 *Address ++ ) ++{ ++ gceSTATUS status; ++ gckOS os; ++ gcuVIDMEM_NODE_PTR node = Node->node; ++ gcsGPU_MAP_PTR gpuMap; ++ gctPHYS_ADDR physical = gcvNULL; ++ gctUINT32 phys = gcvINVALID_ADDRESS; ++ gctUINT32 processID; ++ gcsLOCK_INFO_PTR lockInfo; ++ gctUINT32 pageCount; ++ gckMMU mmu; ++ gctUINT32 i; ++ gctUINT32_PTR pageTableEntry; ++ gctUINT32 offset = 0; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Node = %x", Node); ++ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Node != gcvNULL); ++ gcmkVERIFY_ARGUMENT(Address != gcvNULL); ++ ++ os = Kernel->os; ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu)); ++ ++ gcmkONERROR(gckOS_AcquireMutex(os, Node->mapMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Get map information for current process. */ ++ gpuMap = _FindGPUMap(Node->mapHead, processID); ++ ++ if (gpuMap == gcvNULL) ++ { ++ gpuMap = _CreateGPUMap(os, &Node->mapHead, &Node->mapTail, processID); ++ ++ if (gpuMap == gcvNULL) ++ { ++ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); ++ } ++ } ++ ++ lockInfo = &gpuMap->lockInfo; ++ ++ if (lockInfo->lockeds[Kernel->core] ++ == 0) ++ { ++ /* Get necessary information. */ ++ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ++ { ++ phys = node->VidMem.memory->baseAddress ++ + node->VidMem.offset ++ + node->VidMem.alignment; ++ ++ /* GPU page table use 4K page. */ ++ pageCount = ((phys + node->VidMem.bytes + 4096 - 1) >> 12) ++ - (phys >> 12); ++ ++ offset = phys & 0xFFF; ++ } ++ else ++ { ++ pageCount = node->Virtual.pageCount; ++ physical = node->Virtual.physical; ++ } ++ ++ /* Allocate pages inside the MMU. */ ++ gcmkONERROR(gckMMU_AllocatePages( ++ mmu, ++ pageCount, ++ &lockInfo->pageTables[Kernel->core], ++ &lockInfo->GPUAddresses[Kernel->core])); ++ ++ /* Record MMU from which pages are allocated. */ ++ lockInfo->lockMmus[Kernel->core] = mmu; ++ ++ pageTableEntry = lockInfo->pageTables[Kernel->core]; ++ ++ /* Fill page table entries. */ ++ if (phys != gcvINVALID_ADDRESS) ++ { ++ gctUINT32 address = lockInfo->GPUAddresses[Kernel->core]; ++ for (i = 0; i < pageCount; i++) ++ { ++ gckMMU_GetPageEntry(mmu, address, &pageTableEntry); ++ gckMMU_SetPage(mmu, phys & 0xFFFFF000, pageTableEntry); ++ phys += 4096; ++ address += 4096; ++ pageTableEntry += 1; ++ } ++ } ++ else ++ { ++ gctUINT32 address = lockInfo->GPUAddresses[Kernel->core]; ++ gcmkASSERT(physical != gcvNULL); ++ gcmkONERROR(gckOS_MapPagesEx(os, ++ Kernel->core, ++ physical, ++ pageCount, ++ address, ++ pageTableEntry)); ++ } ++ ++ gcmkONERROR(gckMMU_Flush(mmu)); ++ } ++ ++ *Address = lockInfo->GPUAddresses[Kernel->core] + offset; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mapMutex)); ++ acquired = gcvFALSE; ++ ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mapMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckVIDMEM_NODE_Unlock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ IN gctUINT32 ProcessID ++ ) ++{ ++ gceSTATUS status; ++ gcsGPU_MAP_PTR gpuMap; ++ gcsLOCK_INFO_PTR lockInfo; ++ gckMMU mmu; ++ gcuVIDMEM_NODE_PTR node; ++ gctUINT32 pageCount; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%08X, Node = %x, ProcessID=%d", ++ Kernel, Node, ProcessID); ++ ++ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); ++ gcmkVERIFY_ARGUMENT(Node != gcvNULL); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Node->mapMutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Get map information for current process. */ ++ gpuMap = _FindGPUMap(Node->mapHead, ProcessID); ++ ++ if (gpuMap == gcvNULL) ++ { ++ /* No mapping for this process. */ ++ gcmkONERROR(gcvSTATUS_INVALID_DATA); ++ } ++ ++ lockInfo = &gpuMap->lockInfo; ++ ++ if (--lockInfo->lockeds[Kernel->core] == 0) ++ { ++ node = Node->node; ++ ++ /* Get necessary information. */ ++ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ++ { ++ gctUINT32 phys = node->VidMem.memory->baseAddress ++ + node->VidMem.offset ++ + node->VidMem.alignment; ++ ++ /* GPU page table use 4K page. */ ++ pageCount = ((phys + node->VidMem.bytes + 4096 - 1) >> 12) ++ - (phys >> 12); ++ } ++ else ++ { ++ pageCount = node->Virtual.pageCount; ++ } ++ ++ /* Get MMU which allocates pages. */ ++ mmu = lockInfo->lockMmus[Kernel->core]; ++ ++ /* Free virtual spaces in page table. */ ++ gcmkVERIFY_OK(gckMMU_FreePagesEx( ++ mmu, ++ lockInfo->GPUAddresses[Kernel->core], ++ pageCount ++ )); ++ ++ _DestroyGPUMap(Kernel->os, &Node->mapHead, &Node->mapTail, gpuMap); ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Node->mapMutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Node->mapMutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++#endif ++ ++/******************************************************************************* ++** ++** gckVIDMEM_HANDLE_Allocate ++** ++** Allocate a handle for a gckVIDMEM_NODE object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gckVIDMEM_NODE Node ++** Pointer to a gckVIDMEM_NODE object. ++** ++** OUTPUT: ++** ++** gctUINT32 * Handle ++** Pointer to a variable receiving a handle represent this ++** gckVIDMEM_NODE in userspace. ++*/ ++static gceSTATUS ++gckVIDMEM_HANDLE_Allocate( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ OUT gctUINT32 * Handle ++ ) ++{ ++ gceSTATUS status; ++ gctUINT32 processID = 0; ++ gctPOINTER pointer = gcvNULL; ++ gctPOINTER handleDatabase = gcvNULL; ++ gctPOINTER mutex = gcvNULL; ++ gctUINT32 handle = 0; ++ gckVIDMEM_HANDLE handleObject = gcvNULL; ++ gckOS os = Kernel->os; ++ ++ gcmkHEADER_ARG("Kernel=0x%X, Node=0x%X", Kernel, Node); ++ ++ gcmkVERIFY_OBJECT(os, gcvOBJ_OS); ++ ++ /* Allocate a gckVIDMEM_HANDLE object. */ ++ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_HANDLE), &pointer)); ++ ++ gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_HANDLE))); ++ ++ handleObject = pointer; ++ ++ gcmkONERROR(gckOS_AtomConstruct(os, &handleObject->reference)); ++ ++ /* Set default reference count to 1. */ ++ gckOS_AtomSet(os, handleObject->reference, 1); ++ ++ gcmkVERIFY_OK(gckOS_GetProcessID(&processID)); ++ ++ gcmkONERROR( ++ gckKERNEL_FindHandleDatbase(Kernel, ++ processID, ++ &handleDatabase, ++ &mutex)); ++ ++ /* Allocate a handle for this object. */ ++ gcmkONERROR( ++ gckKERNEL_AllocateIntegerId(handleDatabase, handleObject, &handle)); ++ ++ handleObject->node = Node; ++ handleObject->handle = handle; ++ ++ *Handle = handle; ++ ++ gcmkFOOTER_ARG("*Handle=%d", *Handle); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (handleObject != gcvNULL) ++ { ++ if (handleObject->reference != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(os, handleObject->reference)); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, handleObject)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++static gceSTATUS ++gckVIDMEM_NODE_Reference( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node ++ ) ++{ ++ gctINT32 oldValue; ++ gcmkHEADER_ARG("Kernel=0x%X Node=0x%X", Kernel, Node); ++ ++ gckOS_AtomIncrement(Kernel->os, Node->reference, &oldValue); ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++gckVIDMEM_HANDLE_Reference( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_HANDLE handleObject = gcvNULL; ++ gctPOINTER database = gcvNULL; ++ gctPOINTER mutex = gcvNULL; ++ gctINT32 oldValue = 0; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Handle=%d ProcessID=%d", Handle, ProcessID); ++ ++ gcmkONERROR( ++ gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex)); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Translate handle to gckVIDMEM_HANDLE object. */ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject)); ++ ++ /* Increase the reference count. */ ++ gckOS_AtomIncrement(Kernel->os, handleObject->reference, &oldValue); ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ acquired = gcvFALSE; ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckVIDMEM_HANDLE_Dereference( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle ++ ) ++{ ++ gceSTATUS status; ++ gctPOINTER handleDatabase = gcvNULL; ++ gctPOINTER mutex = gcvNULL; ++ gctINT32 oldValue = 0; ++ gckVIDMEM_HANDLE handleObject = gcvNULL; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Handle=%d ProcessID=%d", Handle, ProcessID); ++ ++ gcmkONERROR( ++ gckKERNEL_FindHandleDatbase(Kernel, ++ ProcessID, ++ &handleDatabase, ++ &mutex)); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Translate handle to gckVIDMEM_HANDLE. */ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(handleDatabase, Handle, (gctPOINTER *)&handleObject)); ++ ++ gckOS_AtomDecrement(Kernel->os, handleObject->reference, &oldValue); ++ ++ if (oldValue == 1) ++ { ++ /* Remove handle from database if this is the last reference. */ ++ gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(handleDatabase, Handle)); ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ acquired = gcvFALSE; ++ ++ if (oldValue == 1) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, handleObject->reference)); ++ gcmkOS_SAFE_FREE(Kernel->os, handleObject); ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckVIDMEM_HANDLE_LookupAndReference( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Handle, ++ OUT gckVIDMEM_NODE * Node ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_HANDLE handleObject = gcvNULL; ++ gckVIDMEM_NODE node = gcvNULL; ++ gctPOINTER database = gcvNULL; ++ gctPOINTER mutex = gcvNULL; ++ gctUINT32 processID = 0; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle); ++ ++ gckOS_GetProcessID(&processID); ++ ++ gcmkONERROR( ++ gckKERNEL_FindHandleDatbase(Kernel, processID, &database, &mutex)); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Translate handle to gckVIDMEM_HANDLE object. */ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject)); ++ ++ /* Get gckVIDMEM_NODE object. */ ++ node = handleObject->node; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ acquired = gcvFALSE; ++ ++ /* Reference this gckVIDMEM_NODE object. */ ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Reference(Kernel, node)); ++ ++ /* Return result. */ ++ *Node = node; ++ ++ gcmkFOOTER_ARG("*Node=%X", *Node); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckVIDMEM_HANDLE_Lookup( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle, ++ OUT gckVIDMEM_NODE * Node ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_HANDLE handleObject = gcvNULL; ++ gckVIDMEM_NODE node = gcvNULL; ++ gctPOINTER database = gcvNULL; ++ gctPOINTER mutex = gcvNULL; ++ gctBOOL acquired = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%X ProcessID=%d Handle=%d", ++ Kernel, ProcessID, Handle); ++ ++ gcmkONERROR( ++ gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex)); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ gcmkONERROR( ++ gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject)); ++ ++ node = handleObject->node; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ acquired = gcvFALSE; ++ ++ *Node = node; ++ ++ gcmkFOOTER_ARG("*Node=%X", *Node); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_NODE_Allocate ++** ++** Allocate a gckVIDMEM_NODE object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gcuVIDMEM_NODE_PTR Node ++** Pointer to a gcuVIDMEM_NODE union. ++** ++** OUTPUT: ++** ++** gctUINT32 * Handle ++** Pointer to a variable receiving a handle represent this ++** gckVIDMEM_NODE in userspace. ++*/ ++gceSTATUS ++gckVIDMEM_NODE_Allocate( ++ IN gckKERNEL Kernel, ++ IN gcuVIDMEM_NODE_PTR VideoNode, ++ IN gceSURF_TYPE Type, ++ IN gcePOOL Pool, ++ IN gctUINT32 * Handle ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE node = gcvNULL; ++ gctPOINTER pointer = gcvNULL; ++ gctUINT32 handle = 0; ++ gckOS os = Kernel->os; ++ ++ gcmkHEADER_ARG("Kernel=0x%X VideoNode=0x%X", Kernel, VideoNode); ++ ++ /* Construct a node. */ ++ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_NODE), &pointer)); ++ ++ gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_NODE))); ++ ++ node = pointer; ++ ++ node->node = VideoNode; ++ node->type = Type; ++ node->pool = Pool; ++ ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkONERROR(gckOS_CreateMutex(os, &node->mapMutex)); ++#endif ++ ++ gcmkONERROR(gckOS_AtomConstruct(os, &node->reference)); ++ ++ gcmkONERROR(gckOS_CreateMutex(os, &node->mutex)); ++ ++ /* Reference is 1 by default . */ ++ gckVIDMEM_NODE_Reference(Kernel, node); ++ ++ /* Create a handle to represent this node. */ ++ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(Kernel, node, &handle)); ++ ++ *Handle = handle; ++ ++ gcmkFOOTER_ARG("*Handle=%d", *Handle); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (node != gcvNULL) ++ { ++#if gcdPROCESS_ADDRESS_SPACE ++ if (node->mapMutex != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->mapMutex)); ++ } ++#endif ++ ++ if (node->mutex) ++ { ++ gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->mutex)); ++ } ++ ++ if (node->reference != gcvNULL) ++ { ++ gcmkVERIFY_OK(gckOS_AtomDestroy(os, node->reference)); ++ } ++ ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++gceSTATUS ++gckVIDMEM_NODE_Dereference( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node ++ ) ++{ ++ gctINT32 oldValue = 0; ++ gctPOINTER database = Kernel->db->nameDatabase; ++ gctPOINTER mutex = Kernel->db->nameDatabaseMutex; ++ ++ gcmkHEADER_ARG("Kernel=0x%X Node=0x%X", Kernel, Node); ++ ++ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE)); ++ ++ gcmkVERIFY_OK(gckOS_AtomDecrement(Kernel->os, Node->reference, &oldValue)); ++ ++ if (oldValue == 1 && Node->name) ++ { ++ /* Free name if exists. */ ++ gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, Node->name)); ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ ++ if (oldValue == 1) ++ { ++ /* Free gcuVIDMEM_NODE. */ ++ gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, Node->node)); ++ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Node->reference)); ++#if gcdPROCESS_ADDRESS_SPACE ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Node->mapMutex)); ++#endif ++ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Node->mutex)); ++ gcmkOS_SAFE_FREE(Kernel->os, Node); ++ } ++ ++ gcmkFOOTER_NO(); ++ return gcvSTATUS_OK; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_NODE_Name ++** ++** Naming a gckVIDMEM_NODE object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctUINT32 Handle ++** Handle to a gckVIDMEM_NODE object. ++** ++** OUTPUT: ++** ++** gctUINT32 * Name ++** Pointer to a variable receiving a name which can be pass to another ++** process. ++*/ ++gceSTATUS ++gckVIDMEM_NODE_Name( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Handle, ++ IN gctUINT32 * Name ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE node = gcvNULL; ++ gctUINT32 name = 0; ++ gctUINT32 processID = 0; ++ gctPOINTER database = Kernel->db->nameDatabase; ++ gctPOINTER mutex = Kernel->db->nameDatabaseMutex; ++ gctBOOL acquired = gcvFALSE; ++ gctBOOL referenced = gcvFALSE; ++ gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle); ++ ++ gcmkONERROR(gckOS_GetProcessID(&processID)); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node)); ++ referenced = gcvTRUE; ++ ++ if (node->name == 0) ++ { ++ /* Name this node. */ ++ gcmkONERROR(gckKERNEL_AllocateIntegerId(database, node, &name)); ++ node->name = name; ++ } ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ acquired = gcvFALSE; ++ ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node)); ++ ++ if(node) ++ { ++ *Name = node->name; ++ } ++ ++ gcmkFOOTER_ARG("*Name=%d", *Name); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (referenced) ++ { ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node)); ++ } ++ ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_NODE_Import ++** ++** Import a gckVIDMEM_NODE object. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctUINT32 Name ++** Name of a gckVIDMEM_NODE object. ++** ++** OUTPUT: ++** ++** gctUINT32 * Handle ++** Pointer to a variable receiving a handle represent this ++** gckVIDMEM_NODE in userspace. ++*/ ++gceSTATUS ++gckVIDMEM_NODE_Import( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Name, ++ IN gctUINT32 * Handle ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE node = gcvNULL; ++ gctPOINTER database = Kernel->db->nameDatabase; ++ gctPOINTER mutex = Kernel->db->nameDatabaseMutex; ++ gctBOOL acquired = gcvFALSE; ++ gctBOOL referenced = gcvFALSE; ++ ++ gcmkHEADER_ARG("Kernel=0x%X Name=%d", Kernel, Name); ++ ++ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE)); ++ acquired = gcvTRUE; ++ ++ /* Lookup in database to get the node. */ ++ gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, (gctPOINTER *)&node)); ++ ++ /* Reference the node. */ ++ gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, node)); ++ referenced = gcvTRUE; ++ ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ acquired = gcvFALSE; ++ ++ /* Allocate a handle for current process. */ ++ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(Kernel, node, Handle)); ++ ++ gcmkFOOTER_ARG("*Handle=%d", *Handle); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (referenced) ++ { ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node)); ++ } ++ ++ if (acquired) ++ { ++ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ ++ ++typedef struct _gcsVIDMEM_NODE_FDPRIVATE ++{ ++ gcsFDPRIVATE base; ++ gckKERNEL kernel; ++ gckVIDMEM_NODE node; ++} ++gcsVIDMEM_NODE_FDPRIVATE; ++ ++ ++static gctINT ++_ReleaseFdPrivate( ++ gcsFDPRIVATE_PTR FdPrivate ++ ) ++{ ++ /* Cast private info. */ ++ gcsVIDMEM_NODE_FDPRIVATE * private = (gcsVIDMEM_NODE_FDPRIVATE *) FdPrivate; ++ ++ gckVIDMEM_NODE_Dereference(private->kernel, private->node); ++ gckOS_Free(private->kernel->os, private); ++ ++ return 0; ++} ++ ++/******************************************************************************* ++** ++** gckVIDMEM_NODE_GetFd ++** ++** Attach a gckVIDMEM_NODE object to a native fd. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** gctUINT32 Handle ++** Handle to a gckVIDMEM_NODE object. ++** ++** OUTPUT: ++** ++** gctUINT32 * Fd ++** Pointer to a variable receiving a native fd from os. ++*/ ++gceSTATUS ++gckVIDMEM_NODE_GetFd( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Handle, ++ OUT gctINT * Fd ++ ) ++{ ++ gceSTATUS status; ++ gckVIDMEM_NODE node = gcvNULL; ++ gctBOOL referenced = gcvFALSE; ++ gcsVIDMEM_NODE_FDPRIVATE * fdPrivate = gcvNULL; ++ gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle); ++ ++ /* Query and reference handle. */ ++ gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node)); ++ referenced = gcvTRUE; ++ ++ /* Allocate memory for private info. */ ++ gcmkONERROR(gckOS_Allocate( ++ Kernel->os, ++ gcmSIZEOF(gcsVIDMEM_NODE_FDPRIVATE), ++ (gctPOINTER *)&fdPrivate ++ )); ++ ++ fdPrivate->base.release = _ReleaseFdPrivate; ++ fdPrivate->kernel = Kernel; ++ fdPrivate->node = node; ++ ++ /* Allocated fd owns a reference. */ ++ gcmkONERROR(gckOS_GetFd("vidmem", &fdPrivate->base, Fd)); ++ ++ gcmkFOOTER_ARG("*Fd=%d", *Fd); ++ return gcvSTATUS_OK; ++ ++OnError: ++ if (referenced) ++ { ++ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node)); ++ } ++ ++ if (fdPrivate) ++ { ++ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, fdPrivate)); ++ } ++ ++ gcmkFOOTER(); ++ return status; ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/aqHal.h linux-3.14.72/drivers/gpu/galcore/inc/aqHal.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/aqHal.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/aqHal.h 2016-06-19 22:11:55.149150242 +0200 +@@ -0,0 +1 @@ ++#include "HAL/gc_hal.h" +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_base.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_base.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_base.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_base.h 2016-06-19 22:11:55.153149980 +0200 +@@ -0,0 +1,5538 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++#ifndef __gc_hal_base_h_ ++#define __gc_hal_base_h_ ++ ++#include "gc_hal_enum.h" ++#include "gc_hal_types.h" ++#include "gc_hal_dump.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++****************************** Object Declarations ***************************** ++\******************************************************************************/ ++ ++typedef struct _gckOS * gckOS; ++typedef struct _gcoHAL * gcoHAL; ++typedef struct _gcoOS * gcoOS; ++typedef struct _gco2D * gco2D; ++typedef struct gcsATOM * gcsATOM_PTR; ++ ++#if gcdENABLE_3D ++typedef struct _gco3D * gco3D; ++typedef struct _gcoCL * gcoCL; ++typedef struct _gcsFAST_FLUSH * gcsFAST_FLUSH_PTR; ++#endif ++ ++typedef struct _gcoSURF * gcoSURF; ++typedef struct _gcsSURF_INFO * gcsSURF_INFO_PTR; ++typedef struct _gcsSURF_NODE * gcsSURF_NODE_PTR; ++typedef struct _gcsSURF_FORMAT_INFO * gcsSURF_FORMAT_INFO_PTR; ++typedef struct _gcsPOINT * gcsPOINT_PTR; ++typedef struct _gcsSIZE * gcsSIZE_PTR; ++typedef struct _gcsRECT * gcsRECT_PTR; ++typedef struct _gcsBOUNDARY * gcsBOUNDARY_PTR; ++typedef struct _gcoDUMP * gcoDUMP; ++typedef struct _gcoHARDWARE * gcoHARDWARE; ++typedef union _gcuVIDMEM_NODE * gcuVIDMEM_NODE_PTR; ++typedef struct _gcsVIDMEM_NODE * gckVIDMEM_NODE; ++ ++#if gcdENABLE_VG ++typedef struct _gcoVG * gcoVG; ++typedef struct _gcsCOMPLETION_SIGNAL * gcsCOMPLETION_SIGNAL_PTR; ++typedef struct _gcsCONTEXT_MAP * gcsCONTEXT_MAP_PTR; ++#else ++typedef void * gcoVG; ++#endif ++ ++#if gcdSYNC ++typedef struct _gcoFENCE * gcoFENCE; ++typedef struct _gcsSYNC_CONTEXT * gcsSYNC_CONTEXT_PTR; ++#endif ++ ++#if defined(ANDROID) ++typedef struct _gcoOS_SymbolsList gcoOS_SymbolsList; ++#endif ++ ++/******************************************************************************\ ++******************************* Process local storage ************************* ++\******************************************************************************/ ++ ++typedef struct _gcsPLS * gcsPLS_PTR; ++ ++#if gcdENABLE_3D ++/****************************************************************************** ++** ++** Patch defines which should be moved to dedicate file later ++** ++** !!! ALWAYS ADD new ID in the TAIL, otherwise will break exising TRACE FILE ++*******************************************************************************/ ++typedef enum _gcePATCH_ID ++{ ++ gcvPATCH_NOTINIT = -1, ++ gcvPATCH_INVALID = 0, ++ ++#if gcdDEBUG_OPTION ++ gcvPATCH_DEBUG, ++#endif ++ ++ gcvPATCH_GTFES30, ++ gcvPATCH_CTGL11, ++ gcvPATCH_CTGL20, ++ gcvPATCH_GLBM11, ++ gcvPATCH_GLBM21, ++ gcvPATCH_GLBM25, ++ gcvPATCH_GLBM27, ++ gcvPATCH_GLBMGUI, ++ gcvPATCH_GFXBENCH, ++ gcvPATCH_ANTUTU, /* Antutu 3.x */ ++ gcvPATCH_ANTUTU4X, /* Antutu 4.x */ ++ gcvPATCH_QUADRANT, ++ gcvPATCH_GPUBENCH, ++ gcvPATCH_DUOKAN, ++ gcvPATCH_GLOFTSXHM, ++ gcvPATCH_XRUNNER, ++ gcvPATCH_BUSPARKING3D, ++ gcvPATCH_SIEGECRAFT, ++ gcvPATCH_PREMIUM, ++ gcvPATCH_RACEILLEGAL, ++ gcvPATCH_MEGARUN, ++ gcvPATCH_BMGUI, ++ gcvPATCH_NENAMARK, ++ gcvPATCH_NENAMARK2, ++ gcvPATCH_FISHNOODLE, ++ gcvPATCH_MM06, ++ gcvPATCH_MM07, ++ gcvPATCH_BM21, ++ gcvPATCH_SMARTBENCH, ++ gcvPATCH_JPCT, ++ gcvPATCH_NEOCORE, ++ gcvPATCH_RTESTVA, ++ gcvPATCH_NBA2013, ++ gcvPATCH_BARDTALE, ++ gcvPATCH_F18, ++ gcvPATCH_CARPARK, ++ gcvPATCH_CARCHALLENGE, ++ gcvPATCH_HEROESCALL, ++ gcvPATCH_GLOFTF3HM, ++ gcvPATCH_CRAZYRACING, ++ gcvPATCH_FIREFOX, ++ gcvPATCH_CHROME, ++ gcvPATCH_MONOPOLY, ++ gcvPATCH_SNOWCOLD, ++ gcvPATCH_BM3, ++ gcvPATCH_BASEMARKX, ++ gcvPATCH_DEQP, ++ gcvPATCH_SF4, ++ gcePATCH_MGOHEAVEN2, ++ gcePATCH_SILIBILI, ++ gcePATCH_ELEMENTSDEF, ++ gcePATCH_GLOFTKRHM, ++ gcvPATCH_OCLCTS, ++ gcvPATCH_A8HP, ++ gcvPATCH_A8CN, ++ gcvPATCH_WISTONESG, ++ gcvPATCH_SPEEDRACE, ++ gcvPATCH_FSBHAWAIIF, ++ gcvPATCH_AIRNAVY, ++ gcvPATCH_F18NEW, ++ gcvPATCH_CKZOMBIES2, ++ gcvPATCH_EADGKEEPER, ++ gcvPATCH_BASEMARK2V2, ++ gcvPATCH_RIPTIDEGP2, ++ gcvPATCH_OESCTS, ++ gcvPATCH_GANGSTAR, ++ gcvPATCH_WHRKYZIXOVAN, ++ gcvPATCH_NAMESGAS, ++ gcvPATCH_AFTERBURNER, ++ gcvPATCH_UIMARK, ++ gcvPATCH_FM_OES_PLAYER, ++ gcvPATCH_SUMSUNG_BENCH, ++ gcvPATCH_ROCKSTAR_MAXPAYNE, ++ gcvPATCH_TITANPACKING, ++ gcvPATCH_BASEMARKOSIICN, ++ gcvPATCH_FRUITNINJA, ++#if defined(ANDROID) ++ gcePATCH_ANDROID_CTS_MEDIA_PRESENTATIONTIME, ++#endif ++ gcvPATCH_ANDROID_COMPOSITOR, ++ gcvPATCH_CTS_TEXTUREVIEW, ++ gcvPATCH_WATER2_CHUKONG, ++ ++ gcvPATCH_COUNT ++} gcePATCH_ID; ++#endif /* gcdENABLE_3D */ ++ ++typedef void (* gctPLS_DESTRUCTOR) ( ++ gcsPLS_PTR ++ ); ++ ++typedef struct _gcsPLS ++{ ++ /* Global objects. */ ++ gcoOS os; ++ gcoHAL hal; ++ ++ /* Internal memory pool. */ ++ gctSIZE_T internalSize; ++ gctPHYS_ADDR internalPhysical; ++ gctPOINTER internalLogical; ++ ++ /* External memory pool. */ ++ gctSIZE_T externalSize; ++ gctPHYS_ADDR externalPhysical; ++ gctPOINTER externalLogical; ++ ++ /* Contiguous memory pool. */ ++ gctSIZE_T contiguousSize; ++ gctPHYS_ADDR contiguousPhysical; ++ gctPOINTER contiguousLogical; ++ ++ /* EGL-specific process-wide objects. */ ++ gctPOINTER eglDisplayInfo; ++ gctPOINTER eglSurfaceInfo; ++ gceSURF_FORMAT eglConfigFormat; ++ ++ /* PLS reference count */ ++ gcsATOM_PTR reference; ++ ++ /* PorcessID of the constrcutor process */ ++ gctUINT32 processID; ++ ++ /* ThreadID of the constrcutor process. */ ++ gctSIZE_T threadID; ++ /* Flag for calling module destructor. */ ++ gctBOOL exiting; ++ ++ gctBOOL bNeedSupportNP2Texture; ++ ++ gctPLS_DESTRUCTOR destructor; ++ /* Mutex to guard PLS access. currently it's for EGL. ++ ** We can use this mutex for every PLS access. ++ */ ++ gctPOINTER accessLock; ++#if gcdENABLE_3D ++ /* Global patchID to overwrite the detection */ ++ gcePATCH_ID patchID; ++#endif ++} ++gcsPLS; ++ ++extern gcsPLS gcPLS; ++ ++#if gcdENABLE_3D ++#define gcPLS_INITIALIZER \ ++{ \ ++ gcvNULL, /* gcoOS object. */ \ ++ gcvNULL, /* gcoHAL object. */ \ ++ 0, /* internalSize */ \ ++ gcvNULL, /* internalPhysical */ \ ++ gcvNULL, /* internalLogical */ \ ++ 0, /* externalSize */ \ ++ gcvNULL, /* externalPhysical */ \ ++ gcvNULL, /* externalLogical */ \ ++ 0, /* contiguousSize */ \ ++ gcvNULL, /* contiguousPhysical */ \ ++ gcvNULL, /* contiguousLogical */ \ ++ gcvNULL, /* eglDisplayInfo */ \ ++ gcvNULL, /* eglSurfaceInfo */ \ ++ gcvSURF_A8R8G8B8,/* eglConfigFormat */ \ ++ gcvNULL, /* reference */ \ ++ 0, /* processID */ \ ++ 0, /* threadID */ \ ++ gcvFALSE, /* exiting */ \ ++ gcvFALSE, /* Special flag for NP2 texture. */ \ ++ gcvNULL, /* destructor */ \ ++ gcvNULL, /* accessLock */ \ ++ gcvPATCH_NOTINIT,/* global patchID */ \ ++} ++#else ++#define gcPLS_INITIALIZER \ ++{ \ ++ gcvNULL, /* gcoOS object. */ \ ++ gcvNULL, /* gcoHAL object. */ \ ++ 0, /* internalSize */ \ ++ gcvNULL, /* internalPhysical */ \ ++ gcvNULL, /* internalLogical */ \ ++ 0, /* externalSize */ \ ++ gcvNULL, /* externalPhysical */ \ ++ gcvNULL, /* externalLogical */ \ ++ 0, /* contiguousSize */ \ ++ gcvNULL, /* contiguousPhysical */ \ ++ gcvNULL, /* contiguousLogical */ \ ++ gcvNULL, /* eglDisplayInfo */ \ ++ gcvNULL, /* eglSurfaceInfo */ \ ++ gcvSURF_A8R8G8B8,/* eglConfigFormat */ \ ++ gcvNULL, /* reference */ \ ++ 0, /* processID */ \ ++ 0, /* threadID */ \ ++ gcvFALSE, /* exiting */ \ ++ gcvFALSE, /* Special flag for NP2 texture. */ \ ++ gcvNULL, /* destructor */ \ ++ gcvNULL, /* accessLock */ \ ++} ++#endif ++ ++/******************************************************************************\ ++******************************* Thread local storage ************************* ++\******************************************************************************/ ++ ++typedef struct _gcsTLS * gcsTLS_PTR; ++ ++typedef void (* gctTLS_DESTRUCTOR) ( ++ gcsTLS_PTR ++ ); ++ ++typedef struct _gcsTLS ++{ ++ gceHARDWARE_TYPE currentType; ++ ++ /* Current 3D hardwre of this thread */ ++ gcoHARDWARE currentHardware; ++ ++ /* Default 3D hardware of this thread */ ++ gcoHARDWARE defaultHardware; ++ ++ /* Only for separated 3D and 2D */ ++ gcoHARDWARE hardware2D; ++#if gcdENABLE_VG ++ gcoVGHARDWARE vg; ++ gcoVG engineVG; ++#endif /* gcdENABLE_VG */ ++#if gcdENABLE_3D ++ gco3D engine3D; ++#endif ++#if gcdENABLE_2D ++ gco2D engine2D; ++#endif ++ ++ /*thread data */ ++ gctPOINTER context; ++ /* ES(including es1 and es2) client driver context which is current state */ ++ gctPOINTER esClientCtx; ++ gctTLS_DESTRUCTOR destructor; ++ ++ gctBOOL copied; ++ ++ /* libGAL.so handle */ ++ gctHANDLE handle; ++ ++ /* If true, do not releas 2d engine and hardware in hal layer */ ++ gctBOOL release2DUpper; ++} ++gcsTLS; ++ ++/******************************************************************************\ ++********************************* Enumerations ********************************* ++\******************************************************************************/ ++ ++typedef enum _gcePLS_VALUE ++{ ++ gcePLS_VALUE_EGL_DISPLAY_INFO, ++ gcePLS_VALUE_EGL_SURFACE_INFO, ++ gcePLS_VALUE_EGL_CONFIG_FORMAT_INFO, ++ gcePLS_VALUE_EGL_DESTRUCTOR_INFO, ++} ++gcePLS_VALUE; ++ ++/* Video memory pool type. */ ++typedef enum _gcePOOL ++{ ++ gcvPOOL_UNKNOWN = 0, ++ gcvPOOL_DEFAULT, ++ gcvPOOL_LOCAL, ++ gcvPOOL_LOCAL_INTERNAL, ++ gcvPOOL_LOCAL_EXTERNAL, ++ gcvPOOL_UNIFIED, ++ gcvPOOL_SYSTEM, ++ gcvPOOL_VIRTUAL, ++ gcvPOOL_USER, ++ gcvPOOL_CONTIGUOUS, ++ ++ gcvPOOL_NUMBER_OF_POOLS ++} ++gcePOOL; ++ ++#if gcdENABLE_3D ++/* Blending functions. */ ++typedef enum _gceBLEND_FUNCTION ++{ ++ gcvBLEND_ZERO, ++ gcvBLEND_ONE, ++ gcvBLEND_SOURCE_COLOR, ++ gcvBLEND_INV_SOURCE_COLOR, ++ gcvBLEND_SOURCE_ALPHA, ++ gcvBLEND_INV_SOURCE_ALPHA, ++ gcvBLEND_TARGET_COLOR, ++ gcvBLEND_INV_TARGET_COLOR, ++ gcvBLEND_TARGET_ALPHA, ++ gcvBLEND_INV_TARGET_ALPHA, ++ gcvBLEND_SOURCE_ALPHA_SATURATE, ++ gcvBLEND_CONST_COLOR, ++ gcvBLEND_INV_CONST_COLOR, ++ gcvBLEND_CONST_ALPHA, ++ gcvBLEND_INV_CONST_ALPHA, ++} ++gceBLEND_FUNCTION; ++ ++/* Blending modes. */ ++typedef enum _gceBLEND_MODE ++{ ++ gcvBLEND_ADD, ++ gcvBLEND_SUBTRACT, ++ gcvBLEND_REVERSE_SUBTRACT, ++ gcvBLEND_MIN, ++ gcvBLEND_MAX, ++} ++gceBLEND_MODE; ++ ++/* Depth modes. */ ++typedef enum _gceDEPTH_MODE ++{ ++ gcvDEPTH_NONE, ++ gcvDEPTH_Z, ++ gcvDEPTH_W, ++} ++gceDEPTH_MODE; ++#endif /* gcdENABLE_3D */ ++ ++#if (gcdENABLE_3D || gcdENABLE_VG) ++/* API flags. */ ++typedef enum _gceAPI ++{ ++ gcvAPI_D3D = 1, ++ gcvAPI_OPENGL_ES11, ++ gcvAPI_OPENGL_ES20, ++ gcvAPI_OPENGL_ES30, ++ gcvAPI_OPENGL, ++ gcvAPI_OPENVG, ++ gcvAPI_OPENCL, ++} ++gceAPI; ++#endif ++ ++ ++typedef enum _gceWHERE ++{ ++ gcvWHERE_COMMAND, ++ gcvWHERE_RASTER, ++ gcvWHERE_PIXEL, ++} ++gceWHERE; ++ ++typedef enum _gceHOW ++{ ++ gcvHOW_SEMAPHORE = 0x1, ++ gcvHOW_STALL = 0x2, ++ gcvHOW_SEMAPHORE_STALL = 0x3, ++} ++gceHOW; ++ ++typedef enum _gceSignalHandlerType ++{ ++ gcvHANDLE_SIGFPE_WHEN_SIGNAL_CODE_IS_0 = 0x1, ++} ++gceSignalHandlerType; ++ ++/* gcsHAL_Limits*/ ++typedef struct _gcsHAL_LIMITS ++{ ++ /* chip info */ ++ gceCHIPMODEL chipModel; ++ gctUINT32 chipRevision; ++ gctUINT32 featureCount; ++ gctUINT32 *chipFeatures; ++ ++ /* target caps */ ++ gctUINT32 maxWidth; ++ gctUINT32 maxHeight; ++ gctUINT32 multiTargetCount; ++ gctUINT32 maxSamples; ++ ++}gcsHAL_LIMITS; ++ ++/******************************************************************************\ ++*********** Generic Memory Allocation Optimization Using Containers ************ ++\******************************************************************************/ ++ ++/* Generic container definition. */ ++typedef struct _gcsCONTAINER_LINK * gcsCONTAINER_LINK_PTR; ++typedef struct _gcsCONTAINER_LINK ++{ ++ /* Points to the next container. */ ++ gcsCONTAINER_LINK_PTR next; ++} ++gcsCONTAINER_LINK; ++ ++typedef struct _gcsCONTAINER_RECORD * gcsCONTAINER_RECORD_PTR; ++typedef struct _gcsCONTAINER_RECORD ++{ ++ gcsCONTAINER_RECORD_PTR prev; ++ gcsCONTAINER_RECORD_PTR next; ++} ++gcsCONTAINER_RECORD; ++ ++typedef struct _gcsCONTAINER * gcsCONTAINER_PTR; ++typedef struct _gcsCONTAINER ++{ ++ gctUINT containerSize; ++ gctUINT recordSize; ++ gctUINT recordCount; ++ gcsCONTAINER_LINK_PTR containers; ++ gcsCONTAINER_RECORD freeList; ++ gcsCONTAINER_RECORD allocList; ++} ++gcsCONTAINER; ++ ++gceSTATUS ++gcsCONTAINER_Construct( ++ IN gcsCONTAINER_PTR Container, ++ gctUINT RecordsPerContainer, ++ gctUINT RecordSize ++ ); ++ ++gceSTATUS ++gcsCONTAINER_Destroy( ++ IN gcsCONTAINER_PTR Container ++ ); ++ ++gceSTATUS ++gcsCONTAINER_AllocateRecord( ++ IN gcsCONTAINER_PTR Container, ++ OUT gctPOINTER * Record ++ ); ++ ++gceSTATUS ++gcsCONTAINER_FreeRecord( ++ IN gcsCONTAINER_PTR Container, ++ IN gctPOINTER Record ++ ); ++ ++gceSTATUS ++gcsCONTAINER_FreeAll( ++ IN gcsCONTAINER_PTR Container ++ ); ++ ++/******************************************************************************\ ++********************************* gcoHAL Object ********************************* ++\******************************************************************************/ ++ ++/* Construct a new gcoHAL object. */ ++gceSTATUS ++gcoHAL_ConstructEx( ++ IN gctPOINTER Context, ++ IN gcoOS Os, ++ OUT gcoHAL * Hal ++ ); ++ ++/* Destroy an gcoHAL object. */ ++gceSTATUS ++gcoHAL_DestroyEx( ++ IN gcoHAL Hal ++ ); ++ ++/* Empty function for compatibility. */ ++gceSTATUS ++gcoHAL_Construct( ++ IN gctPOINTER Context, ++ IN gcoOS Os, ++ OUT gcoHAL * Hal ++ ); ++ ++/* Empty function for compatibility. */ ++gceSTATUS ++gcoHAL_Destroy( ++ IN gcoHAL Hal ++ ); ++ ++/* Get HAL options */ ++gceSTATUS ++gcoHAL_GetOption( ++ IN gcoHAL Hal, ++ IN gceOPTION Option ++ ); ++ ++gceSTATUS ++gcoHAL_FrameInfoOps( ++ IN gcoHAL Hal, ++ IN gceFRAMEINFO FrameInfo, ++ IN gceFRAMEINFO_OP Op, ++ IN OUT gctUINT * Val ++ ); ++ ++ ++gceSTATUS ++gcoHAL_GetHardware( ++ IN gcoHAL Hal, ++ OUT gcoHARDWARE* Hw ++ ); ++ ++#if gcdENABLE_2D ++/* Get pointer to gco2D object. */ ++gceSTATUS ++gcoHAL_Get2DEngine( ++ IN gcoHAL Hal, ++ OUT gco2D * Engine ++ ); ++#endif ++ ++#if gcdENABLE_3D ++gceSTATUS ++gcoHAL_GetSpecialHintData( ++ IN gcoHAL Hal, ++ OUT gctINT * Hint ++ ); ++/* ++** Deprecated(Don't use it), keep it here for external library(libgcu.so) ++*/ ++gceSTATUS ++gcoHAL_Get3DEngine( ++ IN gcoHAL Hal, ++ OUT gco3D * Engine ++ ); ++#endif /* gcdEANBLE_3D */ ++ ++ ++gceSTATUS ++gcoHAL_GetProductName( ++ IN gcoHAL Hal, ++ OUT gctSTRING *ProductName ++ ); ++ ++gceSTATUS ++gcoHAL_SetFscaleValue( ++ IN gctUINT FscaleValue ++ ); ++ ++gceSTATUS ++gcoHAL_GetFscaleValue( ++ OUT gctUINT * FscaleValue, ++ OUT gctUINT * MinFscaleValue, ++ OUT gctUINT * MaxFscaleValue ++ ); ++ ++gceSTATUS ++gcoHAL_SetBltNP2Texture( ++ gctBOOL enable ++ ); ++ ++gceSTATUS ++gcoHAL_NameVideoMemory( ++ IN gctUINT32 Handle, ++ OUT gctUINT32 * Name ++ ); ++ ++gceSTATUS ++gcoHAL_ImportVideoMemory( ++ IN gctUINT32 Name, ++ OUT gctUINT32 * Handle ++ ); ++ ++gceSTATUS ++gcoHAL_GetVideoMemoryFd( ++ IN gctUINT32 Handle, ++ OUT gctINT * Fd ++ ); ++ ++/* Verify whether the specified feature is available in hardware. */ ++gceSTATUS ++gcoHAL_IsFeatureAvailable( ++ IN gcoHAL Hal, ++ IN gceFEATURE Feature ++ ); ++ ++gceSTATUS ++gcoHAL_IsSwwaNeeded( ++ IN gcoHAL Hal, ++ IN gceSWWA Swwa ++ ); ++ ++gceSTATUS ++gcoHAL_IsFeatureAvailable1( ++ IN gcoHAL Hal, ++ IN gceFEATURE Feature ++ ); ++ ++/* Query the identity of the hardware. */ ++gceSTATUS ++gcoHAL_QueryChipIdentity( ++ IN gcoHAL Hal, ++ OUT gceCHIPMODEL* ChipModel, ++ OUT gctUINT32* ChipRevision, ++ OUT gctUINT32* ChipFeatures, ++ OUT gctUINT32* ChipMinorFeatures ++ ); ++ ++/* Query the minor features of the hardware. */ ++gceSTATUS gcoHAL_QueryChipMinorFeatures( ++ IN gcoHAL Hal, ++ OUT gctUINT32* NumFeatures, ++ OUT gctUINT32* ChipMinorFeatures ++ ); ++ ++gctINT32 ++gcoOS_EndRecordAllocation(void); ++void ++gcoOS_RecordAllocation(void); ++void ++gcoOS_AddRecordAllocation(gctSIZE_T Size); ++ ++/* Query the amount of video memory. */ ++gceSTATUS ++gcoHAL_QueryVideoMemory( ++ IN gcoHAL Hal, ++ OUT gctPHYS_ADDR * InternalAddress, ++ OUT gctSIZE_T * InternalSize, ++ OUT gctPHYS_ADDR * ExternalAddress, ++ OUT gctSIZE_T * ExternalSize, ++ OUT gctPHYS_ADDR * ContiguousAddress, ++ OUT gctSIZE_T * ContiguousSize ++ ); ++ ++/* Map video memory. */ ++gceSTATUS ++gcoHAL_MapMemory( ++ IN gcoHAL Hal, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T NumberOfBytes, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Unmap video memory. */ ++gceSTATUS ++gcoHAL_UnmapMemory( ++ IN gcoHAL Hal, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T NumberOfBytes, ++ IN gctPOINTER Logical ++ ); ++ ++/* Schedule an unmap of a buffer mapped through its physical address. */ ++gceSTATUS ++gcoHAL_ScheduleUnmapMemory( ++ IN gcoHAL Hal, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T NumberOfBytes, ++ IN gctPOINTER Logical ++ ); ++ ++/* Allocate video memory. */ ++gceSTATUS ++gcoOS_AllocateVideoMemory( ++ IN gcoOS Os, ++ IN gctBOOL InUserSpace, ++ IN gctBOOL InCacheable, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctUINT32 * Physical, ++ OUT gctPOINTER * Logical, ++ OUT gctPOINTER * Handle ++ ); ++ ++/* Free video memory. */ ++gceSTATUS ++gcoOS_FreeVideoMemory( ++ IN gcoOS Os, ++ IN gctPOINTER Handle ++ ); ++ ++/* Lock video memory. */ ++gceSTATUS ++gcoOS_LockVideoMemory( ++ IN gcoOS Os, ++ IN gctPOINTER Handle, ++ IN gctBOOL InUserSpace, ++ IN gctBOOL InCacheable, ++ OUT gctUINT32 * Physical, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Map user memory. */ ++gceSTATUS ++gcoHAL_MapUserMemory( ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * Info, ++ OUT gctUINT32_PTR GPUAddress ++ ); ++ ++/* Unmap user memory. */ ++gceSTATUS ++gcoHAL_UnmapUserMemory( ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Size, ++ IN gctPOINTER Info, ++ IN gctUINT32 GPUAddress ++ ); ++ ++/* Schedule an unmap of a user buffer using event mechanism. */ ++gceSTATUS ++gcoHAL_ScheduleUnmapUserMemory( ++ IN gcoHAL Hal, ++ IN gctPOINTER Info, ++ IN gctSIZE_T Size, ++ IN gctUINT32 Address, ++ IN gctPOINTER Memory ++ ); ++ ++/* Commit the current command buffer. */ ++gceSTATUS ++gcoHAL_Commit( ++ IN gcoHAL Hal, ++ IN gctBOOL Stall ++ ); ++ ++#if gcdENABLE_3D ++/* Sencd fence command. */ ++gceSTATUS ++gcoHAL_SendFence( ++ IN gcoHAL Hal ++ ); ++#endif /* gcdENABLE_3D */ ++ ++/* Query the tile capabilities. */ ++gceSTATUS ++gcoHAL_QueryTiled( ++ IN gcoHAL Hal, ++ OUT gctINT32 * TileWidth2D, ++ OUT gctINT32 * TileHeight2D, ++ OUT gctINT32 * TileWidth3D, ++ OUT gctINT32 * TileHeight3D ++ ); ++ ++gceSTATUS ++gcoHAL_Compact( ++ IN gcoHAL Hal ++ ); ++ ++#if VIVANTE_PROFILER ++gceSTATUS ++gcoHAL_ProfileStart( ++ IN gcoHAL Hal ++ ); ++ ++gceSTATUS ++gcoHAL_ProfileEnd( ++ IN gcoHAL Hal, ++ IN gctCONST_STRING Title ++ ); ++#endif ++ ++/* Power Management */ ++gceSTATUS ++gcoHAL_SetPowerManagementState( ++ IN gcoHAL Hal, ++ IN gceCHIPPOWERSTATE State ++ ); ++ ++gceSTATUS ++gcoHAL_QueryPowerManagementState( ++ IN gcoHAL Hal, ++ OUT gceCHIPPOWERSTATE *State ++ ); ++ ++/* Set the filter type for filter blit. */ ++gceSTATUS ++gcoHAL_SetFilterType( ++ IN gcoHAL Hal, ++ IN gceFILTER_TYPE FilterType ++ ); ++ ++gceSTATUS ++gcoHAL_GetDump( ++ IN gcoHAL Hal, ++ OUT gcoDUMP * Dump ++ ); ++ ++#if gcdENABLE_3D ++gceSTATUS ++gcoHAL_SetPatchID( ++ IN gcoHAL Hal, ++ IN gcePATCH_ID PatchID ++ ); ++ ++/* Get Patch ID based on process name */ ++gceSTATUS ++gcoHAL_GetPatchID( ++ IN gcoHAL Hal, ++ OUT gcePATCH_ID * PatchID ++ ); ++ ++gceSTATUS ++gcoHAL_SetGlobalPatchID( ++ IN gcoHAL Hal, ++ IN gcePATCH_ID PatchID ++ ); ++#endif /* gcdENABLE_3D */ ++/* Call the kernel HAL layer. */ ++gceSTATUS ++gcoHAL_Call( ++ IN gcoHAL Hal, ++ IN OUT gcsHAL_INTERFACE_PTR Interface ++ ); ++ ++/* Schedule an event. */ ++gceSTATUS ++gcoHAL_ScheduleEvent( ++ IN gcoHAL Hal, ++ IN OUT gcsHAL_INTERFACE_PTR Interface ++ ); ++ ++/* Destroy a surface. */ ++gceSTATUS ++gcoHAL_DestroySurface( ++ IN gcoHAL Hal, ++ IN gcoSURF Surface ++ ); ++ ++/* Request a start/stop timestamp. */ ++gceSTATUS ++gcoHAL_SetTimer( ++ IN gcoHAL Hal, ++ IN gctUINT32 Index, ++ IN gctBOOL Start ++ ); ++ ++/* Get Time delta from a Timer in microseconds. */ ++gceSTATUS ++gcoHAL_GetTimerTime( ++ IN gcoHAL Hal, ++ IN gctUINT32 Timer, ++ OUT gctINT32_PTR TimeDelta ++ ); ++ ++/* set timeout value. */ ++gceSTATUS ++gcoHAL_SetTimeOut( ++ IN gcoHAL Hal, ++ IN gctUINT32 timeOut ++ ); ++ ++gceSTATUS ++gcoHAL_SetHardwareType( ++ IN gcoHAL Hal, ++ IN gceHARDWARE_TYPE HardwardType ++ ); ++ ++gceSTATUS ++gcoHAL_GetHardwareType( ++ IN gcoHAL Hal, ++ OUT gceHARDWARE_TYPE * HardwardType ++ ); ++ ++gceSTATUS ++gcoHAL_QueryChipCount( ++ IN gcoHAL Hal, ++ OUT gctINT32 * Count ++ ); ++ ++gceSTATUS ++gcoHAL_Query3DCoreCount( ++ IN gcoHAL Hal, ++ OUT gctUINT32 *Count ++ ); ++ ++gceSTATUS ++gcoHAL_QuerySeparated2D( ++ IN gcoHAL Hal ++ ); ++ ++gceSTATUS ++gcoHAL_Is3DAvailable( ++ IN gcoHAL Hal ++ ); ++ ++/* Get pointer to gcoVG object. */ ++gceSTATUS ++gcoHAL_GetVGEngine( ++ IN gcoHAL Hal, ++ OUT gcoVG * Engine ++ ); ++ ++gceSTATUS ++gcoHAL_QueryChipLimits( ++ IN gcoHAL Hal, ++ IN gctINT32 Chip, ++ IN gctINT32 Mask, ++ OUT gcsHAL_LIMITS *Limits); ++ ++gceSTATUS ++gcoHAL_QueryChipFeature( ++ IN gcoHAL Hal, ++ IN gctINT32 Chip, ++ IN gctINT32 Mask, ++ IN gceFEATURE Feature); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Shared Buffer --------------------------------------------------------*/ ++ ++/* Create shared buffer. */ ++gceSTATUS ++gcoHAL_CreateShBuffer( ++ IN gctUINT32 Size, ++ OUT gctSHBUF * ShBuf ++ ); ++ ++/* Destroy shared buffer. */ ++gceSTATUS ++gcoHAL_DestroyShBuffer( ++ IN gctSHBUF ShBuf ++ ); ++ ++/* Map shared buffer to current process. */ ++gceSTATUS ++gcoHAL_MapShBuffer( ++ IN gctSHBUF ShBuf ++ ); ++ ++/* Write user data to shared buffer. */ ++gceSTATUS ++gcoHAL_WriteShBuffer( ++ IN gctSHBUF ShBuf, ++ IN gctCONST_POINTER Data, ++ IN gctUINT32 ByteCount ++ ); ++ ++/* Read user data from shared buffer. */ ++gceSTATUS ++gcoHAL_ReadShBuffer( ++ IN gctSHBUF ShBuf, ++ IN gctPOINTER Data, ++ IN gctUINT32 BytesCount, ++ OUT gctUINT32 * BytesRead ++ ); ++ ++/* Config power management to be enabled or disabled. */ ++gceSTATUS ++gcoHAL_ConfigPowerManagement( ++ IN gctBOOL Enable ++ ); ++ ++#if gcdENABLE_3D || gcdENABLE_VG ++/* Query the target capabilities. */ ++gceSTATUS ++gcoHAL_QueryTargetCaps( ++ IN gcoHAL Hal, ++ OUT gctUINT * MaxWidth, ++ OUT gctUINT * MaxHeight, ++ OUT gctUINT * MultiTargetCount, ++ OUT gctUINT * MaxSamples ++ ); ++#endif ++ ++/******************************************************************************\ ++********************************** gcoOS Object ********************************* ++\******************************************************************************/ ++/* Lock PLS access */ ++gceSTATUS ++gcoOS_LockPLS( ++ void ++ ); ++ ++/* Unlock PLS access */ ++gceSTATUS ++gcoOS_UnLockPLS( ++ void ++ ); ++ ++/* Get PLS value for given key */ ++gctPOINTER ++gcoOS_GetPLSValue( ++ IN gcePLS_VALUE key ++ ); ++ ++/* Set PLS value of a given key */ ++void ++gcoOS_SetPLSValue( ++ IN gcePLS_VALUE key, ++ OUT gctPOINTER value ++ ); ++ ++/* Get access to the thread local storage. */ ++gceSTATUS ++gcoOS_GetTLS( ++ OUT gcsTLS_PTR * TLS ++ ); ++ ++ /* Copy the TLS from a source thread. */ ++ gceSTATUS gcoOS_CopyTLS(IN gcsTLS_PTR Source); ++ ++/* Destroy the objects associated with the current thread. */ ++void ++gcoOS_FreeThreadData( ++ void ++ ); ++ ++/* Empty function for compatibility. */ ++gceSTATUS ++gcoOS_Construct( ++ IN gctPOINTER Context, ++ OUT gcoOS * Os ++ ); ++ ++/* Empty function for compatibility. */ ++gceSTATUS ++gcoOS_Destroy( ++ IN gcoOS Os ++ ); ++ ++/* Get the base address for the physical memory. */ ++gceSTATUS ++gcoOS_GetBaseAddress( ++ IN gcoOS Os, ++ OUT gctUINT32_PTR BaseAddress ++ ); ++ ++/* Allocate memory from the heap. */ ++gceSTATUS ++gcoOS_Allocate( ++ IN gcoOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Get allocated memory size. */ ++gceSTATUS ++gcoOS_GetMemorySize( ++ IN gcoOS Os, ++ IN gctPOINTER Memory, ++ OUT gctSIZE_T_PTR MemorySize ++ ); ++ ++/* Free allocated memory. */ ++gceSTATUS ++gcoOS_Free( ++ IN gcoOS Os, ++ IN gctPOINTER Memory ++ ); ++ ++/* Allocate memory. */ ++gceSTATUS ++gcoOS_AllocateSharedMemory( ++ IN gcoOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Free memory. */ ++gceSTATUS ++gcoOS_FreeSharedMemory( ++ IN gcoOS Os, ++ IN gctPOINTER Memory ++ ); ++ ++/* Allocate memory. */ ++gceSTATUS ++gcoOS_AllocateMemory( ++ IN gcoOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Free memory. */ ++gceSTATUS ++gcoOS_FreeMemory( ++ IN gcoOS Os, ++ IN gctPOINTER Memory ++ ); ++ ++/* Allocate contiguous memory. */ ++gceSTATUS ++gcoOS_AllocateContiguous( ++ IN gcoOS Os, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Free contiguous memory. */ ++gceSTATUS ++gcoOS_FreeContiguous( ++ IN gcoOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Map user memory. */ ++gceSTATUS ++gcoOS_MapUserMemory( ++ IN gcoOS Os, ++ IN gctPOINTER Memory, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * Info, ++ OUT gctUINT32_PTR Address ++ ); ++ ++/* Map user memory. */ ++gceSTATUS ++gcoOS_MapUserMemoryEx( ++ IN gcoOS Os, ++ IN gctPOINTER Memory, ++ IN gctUINT32 Physical, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * Info, ++ OUT gctUINT32_PTR Address ++ ); ++ ++/* Unmap user memory. */ ++gceSTATUS ++gcoOS_UnmapUserMemory( ++ IN gcoOS Os, ++ IN gctPOINTER Memory, ++ IN gctSIZE_T Size, ++ IN gctPOINTER Info, ++ IN gctUINT32 Address ++ ); ++ ++/* Device I/O Control call to the kernel HAL layer. */ ++gceSTATUS ++gcoOS_DeviceControl( ++ IN gcoOS Os, ++ IN gctUINT32 IoControlCode, ++ IN gctPOINTER InputBuffer, ++ IN gctSIZE_T InputBufferSize, ++ IN gctPOINTER OutputBuffer, ++ IN gctSIZE_T OutputBufferSize ++ ); ++ ++/* Allocate non paged memory. */ ++gceSTATUS ++gcoOS_AllocateNonPagedMemory( ++ IN gcoOS Os, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Free non paged memory. */ ++gceSTATUS ++gcoOS_FreeNonPagedMemory( ++ IN gcoOS Os, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical ++ ); ++ ++#define gcmOS_SAFE_FREE(os, mem) \ ++ gcoOS_Free(os, mem); \ ++ mem = gcvNULL ++ ++#define gcmOS_SAFE_FREE_SHARED_MEMORY(os, mem) \ ++ gcoOS_FreeSharedMemory(os, mem); \ ++ mem = gcvNULL ++ ++#define gcmkOS_SAFE_FREE(os, mem) \ ++ gckOS_Free(os, mem); \ ++ mem = gcvNULL ++ ++typedef enum _gceFILE_MODE ++{ ++ gcvFILE_CREATE = 0, ++ gcvFILE_APPEND, ++ gcvFILE_READ, ++ gcvFILE_CREATETEXT, ++ gcvFILE_APPENDTEXT, ++ gcvFILE_READTEXT, ++} ++gceFILE_MODE; ++ ++/* Open a file. */ ++gceSTATUS ++gcoOS_Open( ++ IN gcoOS Os, ++ IN gctCONST_STRING FileName, ++ IN gceFILE_MODE Mode, ++ OUT gctFILE * File ++ ); ++ ++/* Close a file. */ ++gceSTATUS ++gcoOS_Close( ++ IN gcoOS Os, ++ IN gctFILE File ++ ); ++ ++/* Read data from a file. */ ++gceSTATUS ++gcoOS_Read( ++ IN gcoOS Os, ++ IN gctFILE File, ++ IN gctSIZE_T ByteCount, ++ IN gctPOINTER Data, ++ OUT gctSIZE_T * ByteRead ++ ); ++ ++/* Write data to a file. */ ++gceSTATUS ++gcoOS_Write( ++ IN gcoOS Os, ++ IN gctFILE File, ++ IN gctSIZE_T ByteCount, ++ IN gctCONST_POINTER Data ++ ); ++ ++/* Flush data to a file. */ ++gceSTATUS ++gcoOS_Flush( ++ IN gcoOS Os, ++ IN gctFILE File ++ ); ++ ++/* Close a file descriptor. */ ++gceSTATUS ++gcoOS_CloseFD( ++ IN gcoOS Os, ++ IN gctINT FD ++ ); ++ ++/* Dup file descriptor to another. */ ++gceSTATUS ++gcoOS_DupFD( ++ IN gcoOS Os, ++ IN gctINT FD, ++ OUT gctINT * FD2 ++ ); ++ ++/* Create an endpoint for communication. */ ++gceSTATUS ++gcoOS_Socket( ++ IN gcoOS Os, ++ IN gctINT Domain, ++ IN gctINT Type, ++ IN gctINT Protocol, ++ OUT gctINT *SockFd ++ ); ++ ++/* Close a socket. */ ++gceSTATUS ++gcoOS_CloseSocket( ++ IN gcoOS Os, ++ IN gctINT SockFd ++ ); ++ ++/* Initiate a connection on a socket. */ ++gceSTATUS ++gcoOS_Connect( ++ IN gcoOS Os, ++ IN gctINT SockFd, ++ IN gctCONST_POINTER HostName, ++ IN gctUINT Port); ++ ++/* Shut down part of connection on a socket. */ ++gceSTATUS ++gcoOS_Shutdown( ++ IN gcoOS Os, ++ IN gctINT SockFd, ++ IN gctINT How ++ ); ++ ++/* Send a message on a socket. */ ++gceSTATUS ++gcoOS_Send( ++ IN gcoOS Os, ++ IN gctINT SockFd, ++ IN gctSIZE_T ByteCount, ++ IN gctCONST_POINTER Data, ++ IN gctINT Flags ++ ); ++ ++/* Initiate a connection on a socket. */ ++gceSTATUS ++gcoOS_WaitForSend( ++ IN gcoOS Os, ++ IN gctINT SockFd, ++ IN gctINT Seconds, ++ IN gctINT MicroSeconds); ++ ++/* Get environment variable value. */ ++gceSTATUS ++gcoOS_GetEnv( ++ IN gcoOS Os, ++ IN gctCONST_STRING VarName, ++ OUT gctSTRING * Value ++ ); ++ ++/* Set environment variable value. */ ++gceSTATUS ++gcoOS_SetEnv( ++ IN gcoOS Os, ++ IN gctCONST_STRING VarName, ++ IN gctSTRING Value ++ ); ++ ++/* Get current working directory. */ ++gceSTATUS ++gcoOS_GetCwd( ++ IN gcoOS Os, ++ IN gctINT SizeInBytes, ++ OUT gctSTRING Buffer ++ ); ++ ++/* Get file status info. */ ++gceSTATUS ++gcoOS_Stat( ++ IN gcoOS Os, ++ IN gctCONST_STRING FileName, ++ OUT gctPOINTER Buffer ++ ); ++ ++typedef enum _gceFILE_WHENCE ++{ ++ gcvFILE_SEEK_SET, ++ gcvFILE_SEEK_CUR, ++ gcvFILE_SEEK_END ++} ++gceFILE_WHENCE; ++ ++/* Set the current position of a file. */ ++gceSTATUS ++gcoOS_Seek( ++ IN gcoOS Os, ++ IN gctFILE File, ++ IN gctUINT32 Offset, ++ IN gceFILE_WHENCE Whence ++ ); ++ ++/* Set the current position of a file. */ ++gceSTATUS ++gcoOS_SetPos( ++ IN gcoOS Os, ++ IN gctFILE File, ++ IN gctUINT32 Position ++ ); ++ ++/* Get the current position of a file. */ ++gceSTATUS ++gcoOS_GetPos( ++ IN gcoOS Os, ++ IN gctFILE File, ++ OUT gctUINT32 * Position ++ ); ++ ++/* Same as strstr. */ ++gceSTATUS ++gcoOS_StrStr( ++ IN gctCONST_STRING String, ++ IN gctCONST_STRING SubString, ++ OUT gctSTRING * Output ++ ); ++ ++/* Find the last occurance of a character inside a string. */ ++gceSTATUS ++gcoOS_StrFindReverse( ++ IN gctCONST_STRING String, ++ IN gctINT8 Character, ++ OUT gctSTRING * Output ++ ); ++ ++gceSTATUS ++gcoOS_StrDup( ++ IN gcoOS Os, ++ IN gctCONST_STRING String, ++ OUT gctSTRING * Target ++ ); ++ ++/* Copy a string. */ ++gceSTATUS ++gcoOS_StrCopySafe( ++ IN gctSTRING Destination, ++ IN gctSIZE_T DestinationSize, ++ IN gctCONST_STRING Source ++ ); ++ ++/* Append a string. */ ++gceSTATUS ++gcoOS_StrCatSafe( ++ IN gctSTRING Destination, ++ IN gctSIZE_T DestinationSize, ++ IN gctCONST_STRING Source ++ ); ++ ++/* Compare two strings. */ ++gceSTATUS ++gcoOS_StrCmp( ++ IN gctCONST_STRING String1, ++ IN gctCONST_STRING String2 ++ ); ++ ++/* Compare characters of two strings. */ ++gceSTATUS ++gcoOS_StrNCmp( ++ IN gctCONST_STRING String1, ++ IN gctCONST_STRING String2, ++ IN gctSIZE_T Count ++ ); ++ ++/* Convert string to float. */ ++gceSTATUS ++gcoOS_StrToFloat( ++ IN gctCONST_STRING String, ++ OUT gctFLOAT * Float ++ ); ++ ++/* Convert hex string to integer. */ ++gceSTATUS gcoOS_HexStrToInt( ++ IN gctCONST_STRING String, ++ OUT gctINT * Int ++ ); ++ ++/* Convert hex string to float. */ ++gceSTATUS ++gcoOS_HexStrToFloat( ++ IN gctCONST_STRING String, ++ OUT gctFLOAT * Float ++ ); ++ ++/* Convert string to integer. */ ++gceSTATUS ++gcoOS_StrToInt( ++ IN gctCONST_STRING String, ++ OUT gctINT * Int ++ ); ++ ++gceSTATUS ++gcoOS_MemCmp( ++ IN gctCONST_POINTER Memory1, ++ IN gctCONST_POINTER Memory2, ++ IN gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gcoOS_PrintStrSafe( ++ OUT gctSTRING String, ++ IN gctSIZE_T StringSize, ++ IN OUT gctUINT * Offset, ++ IN gctCONST_STRING Format, ++ ... ++ ); ++ ++gceSTATUS ++gcoOS_LoadLibrary( ++ IN gcoOS Os, ++ IN gctCONST_STRING Library, ++ OUT gctHANDLE * Handle ++ ); ++ ++gceSTATUS ++gcoOS_FreeLibrary( ++ IN gcoOS Os, ++ IN gctHANDLE Handle ++ ); ++ ++gceSTATUS ++gcoOS_GetProcAddress( ++ IN gcoOS Os, ++ IN gctHANDLE Handle, ++ IN gctCONST_STRING Name, ++ OUT gctPOINTER * Function ++ ); ++ ++gceSTATUS ++gcoOS_Compact( ++ IN gcoOS Os ++ ); ++ ++gceSTATUS ++gcoOS_AddSignalHandler ( ++ IN gceSignalHandlerType SignalHandlerType ++ ); ++ ++#if VIVANTE_PROFILER ++gceSTATUS ++gcoOS_ProfileStart( ++ IN gcoOS Os ++ ); ++ ++gceSTATUS ++gcoOS_ProfileEnd( ++ IN gcoOS Os, ++ IN gctCONST_STRING Title ++ ); ++ ++gceSTATUS ++gcoOS_SetProfileSetting( ++ IN gcoOS Os, ++ IN gctBOOL Enable, ++ IN gctCONST_STRING FileName ++ ); ++#endif ++ ++/* Query the video memory. */ ++gceSTATUS ++gcoOS_QueryVideoMemory( ++ IN gcoOS Os, ++ OUT gctPHYS_ADDR * InternalAddress, ++ OUT gctSIZE_T * InternalSize, ++ OUT gctPHYS_ADDR * ExternalAddress, ++ OUT gctSIZE_T * ExternalSize, ++ OUT gctPHYS_ADDR * ContiguousAddress, ++ OUT gctSIZE_T * ContiguousSize ++ ); ++ ++/* Detect if the process is the executable specified. */ ++gceSTATUS ++gcoOS_DetectProcessByNamePid( ++ IN gctCONST_STRING Name, ++ IN gctHANDLE Pid ++ ); ++ ++/* Detect if the current process is the executable specified. */ ++gceSTATUS ++gcoOS_DetectProcessByName( ++ IN gctCONST_STRING Name ++ ); ++ ++gceSTATUS ++gcoOS_DetectProcessByEncryptedName( ++ IN gctCONST_STRING Name ++ ); ++ ++#if defined(ANDROID) ++gceSTATUS ++gcoOS_DetectProgrameByEncryptedSymbols( ++ IN gcoOS_SymbolsList Symbols ++ ); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Atoms ----------------------------------------------------------------*/ ++ ++/* Construct an atom. */ ++gceSTATUS ++gcoOS_AtomConstruct( ++ IN gcoOS Os, ++ OUT gcsATOM_PTR * Atom ++ ); ++ ++/* Destroy an atom. */ ++gceSTATUS ++gcoOS_AtomDestroy( ++ IN gcoOS Os, ++ IN gcsATOM_PTR Atom ++ ); ++ ++/* Get the 32-bit value protected by an atom. */ ++gceSTATUS ++gcoOS_AtomGet( ++ IN gcoOS Os, ++ IN gcsATOM_PTR Atom, ++ OUT gctINT32_PTR Value ++ ); ++ ++/* Set the 32-bit value protected by an atom. */ ++gceSTATUS ++gcoOS_AtomSet( ++ IN gcoOS Os, ++ IN gcsATOM_PTR Atom, ++ IN gctINT32 Value ++ ); ++ ++/* Increment an atom. */ ++gceSTATUS ++gcoOS_AtomIncrement( ++ IN gcoOS Os, ++ IN gcsATOM_PTR Atom, ++ OUT gctINT32_PTR OldValue ++ ); ++ ++/* Decrement an atom. */ ++gceSTATUS ++gcoOS_AtomDecrement( ++ IN gcoOS Os, ++ IN gcsATOM_PTR Atom, ++ OUT gctINT32_PTR OldValue ++ ); ++ ++gctHANDLE ++gcoOS_GetCurrentProcessID( ++ void ++ ); ++ ++gctHANDLE ++gcoOS_GetCurrentThreadID( ++ void ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Time -----------------------------------------------------------------*/ ++ ++/* Get the number of milliseconds since the system started. */ ++gctUINT32 ++gcoOS_GetTicks( ++ void ++ ); ++ ++/* Get time in microseconds. */ ++gceSTATUS ++gcoOS_GetTime( ++ gctUINT64_PTR Time ++ ); ++ ++/* Get CPU usage in microseconds. */ ++gceSTATUS ++gcoOS_GetCPUTime( ++ gctUINT64_PTR CPUTime ++ ); ++ ++/* Get memory usage. */ ++gceSTATUS ++gcoOS_GetMemoryUsage( ++ gctUINT32_PTR MaxRSS, ++ gctUINT32_PTR IxRSS, ++ gctUINT32_PTR IdRSS, ++ gctUINT32_PTR IsRSS ++ ); ++ ++/* Delay a number of microseconds. */ ++gceSTATUS ++gcoOS_Delay( ++ IN gcoOS Os, ++ IN gctUINT32 Delay ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Threads --------------------------------------------------------------*/ ++ ++typedef void * gctTHREAD_RETURN; ++typedef void * (* gcTHREAD_ROUTINE)(void *); ++ ++/* Create a new thread. */ ++gceSTATUS ++gcoOS_CreateThread( ++ IN gcoOS Os, ++ IN gcTHREAD_ROUTINE Worker, ++ IN gctPOINTER Argument, ++ OUT gctPOINTER * Thread ++ ); ++ ++/* Close a thread. */ ++gceSTATUS ++gcoOS_CloseThread( ++ IN gcoOS Os, ++ IN gctPOINTER Thread ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Mutexes --------------------------------------------------------------*/ ++ ++/* Create a new mutex. */ ++gceSTATUS ++gcoOS_CreateMutex( ++ IN gcoOS Os, ++ OUT gctPOINTER * Mutex ++ ); ++ ++/* Delete a mutex. */ ++gceSTATUS ++gcoOS_DeleteMutex( ++ IN gcoOS Os, ++ IN gctPOINTER Mutex ++ ); ++ ++/* Acquire a mutex. */ ++gceSTATUS ++gcoOS_AcquireMutex( ++ IN gcoOS Os, ++ IN gctPOINTER Mutex, ++ IN gctUINT32 Timeout ++ ); ++ ++/* Release a mutex. */ ++gceSTATUS ++gcoOS_ReleaseMutex( ++ IN gcoOS Os, ++ IN gctPOINTER Mutex ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Signals --------------------------------------------------------------*/ ++ ++/* Create a signal. */ ++gceSTATUS ++gcoOS_CreateSignal( ++ IN gcoOS Os, ++ IN gctBOOL ManualReset, ++ OUT gctSIGNAL * Signal ++ ); ++ ++/* Destroy a signal. */ ++gceSTATUS ++gcoOS_DestroySignal( ++ IN gcoOS Os, ++ IN gctSIGNAL Signal ++ ); ++ ++/* Signal a signal. */ ++gceSTATUS ++gcoOS_Signal( ++ IN gcoOS Os, ++ IN gctSIGNAL Signal, ++ IN gctBOOL State ++ ); ++ ++/* Wait for a signal. */ ++gceSTATUS ++gcoOS_WaitSignal( ++ IN gcoOS Os, ++ IN gctSIGNAL Signal, ++ IN gctUINT32 Wait ++ ); ++ ++/* Map a signal from another process */ ++gceSTATUS ++gcoOS_MapSignal( ++ IN gctSIGNAL RemoteSignal, ++ OUT gctSIGNAL * LocalSignal ++ ); ++ ++/* Unmap a signal mapped from another process */ ++gceSTATUS ++gcoOS_UnmapSignal( ++ IN gctSIGNAL Signal ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Android Native Fence -------------------------------------------------*/ ++ ++/* Create sync point. */ ++gceSTATUS ++gcoOS_CreateSyncPoint( ++ IN gcoOS Os, ++ OUT gctSYNC_POINT * SyncPoint ++ ); ++ ++/* Destroy sync point. */ ++gceSTATUS ++gcoOS_DestroySyncPoint( ++ IN gcoOS Os, ++ IN gctSYNC_POINT SyncPoint ++ ); ++ ++/* Create native fence. */ ++gceSTATUS ++gcoOS_CreateNativeFence( ++ IN gcoOS Os, ++ IN gctSYNC_POINT SyncPoint, ++ OUT gctINT * FenceFD ++ ); ++ ++/* Wait on native fence. */ ++gceSTATUS ++gcoOS_WaitNativeFence( ++ IN gcoOS Os, ++ IN gctINT FenceFD, ++ IN gctUINT32 Timeout ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Memory Access and Cache ----------------------------------------------*/ ++ ++/* Write a register. */ ++gceSTATUS ++gcoOS_WriteRegister( ++ IN gcoOS Os, ++ IN gctUINT32 Address, ++ IN gctUINT32 Data ++ ); ++ ++/* Read a register. */ ++gceSTATUS ++gcoOS_ReadRegister( ++ IN gcoOS Os, ++ IN gctUINT32 Address, ++ OUT gctUINT32 * Data ++ ); ++ ++gceSTATUS ++gcoOS_CacheClean( ++ IN gcoOS Os, ++ IN gctUINT32 Node, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gcoOS_CacheFlush( ++ IN gcoOS Os, ++ IN gctUINT32 Node, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gcoOS_CacheInvalidate( ++ IN gcoOS Os, ++ IN gctUINT32 Node, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gcoOS_MemoryBarrier( ++ IN gcoOS Os, ++ IN gctPOINTER Logical ++ ); ++ ++gceSTATUS ++gcoOS_CPUPhysicalToGPUPhysical( ++ IN gctUINT32 CPUPhysical, ++ OUT gctUINT32_PTR GPUPhysical ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----- Profile --------------------------------------------------------------*/ ++ ++gceSTATUS ++gckOS_GetProfileTick( ++ OUT gctUINT64_PTR Tick ++ ); ++ ++gceSTATUS ++gckOS_QueryProfileTickRate( ++ OUT gctUINT64_PTR TickRate ++ ); ++ ++gctUINT32 ++gckOS_ProfileToMS( ++ IN gctUINT64 Ticks ++ ); ++ ++gceSTATUS ++gcoOS_GetProfileTick( ++ OUT gctUINT64_PTR Tick ++ ); ++ ++gceSTATUS ++gcoOS_QueryProfileTickRate( ++ OUT gctUINT64_PTR TickRate ++ ); ++ ++#define _gcmPROFILE_INIT(prefix, freq, start) \ ++ do { \ ++ prefix ## OS_QueryProfileTickRate(&(freq)); \ ++ prefix ## OS_GetProfileTick(&(start)); \ ++ } while (gcvFALSE) ++ ++#define _gcmPROFILE_QUERY(prefix, start, ticks) \ ++ do { \ ++ prefix ## OS_GetProfileTick(&(ticks)); \ ++ (ticks) = ((ticks) > (start)) ? ((ticks) - (start)) \ ++ : (~0ull - (start) + (ticks) + 1); \ ++ } while (gcvFALSE) ++ ++#if gcdENABLE_PROFILING ++# define gcmkPROFILE_INIT(freq, start) _gcmPROFILE_INIT(gck, freq, start) ++# define gcmkPROFILE_QUERY(start, ticks) _gcmPROFILE_QUERY(gck, start, ticks) ++# define gcmPROFILE_INIT(freq, start) _gcmPROFILE_INIT(gco, freq, start) ++# define gcmPROFILE_QUERY(start, ticks) _gcmPROFILE_QUERY(gco, start, ticks) ++# define gcmPROFILE_ONLY(x) x ++# define gcmPROFILE_ELSE(x) do { } while (gcvFALSE) ++# define gcmPROFILE_DECLARE_ONLY(x) x ++# define gcmPROFILE_DECLARE_ELSE(x) typedef x ++#else ++# define gcmkPROFILE_INIT(start, freq) do { } while (gcvFALSE) ++# define gcmkPROFILE_QUERY(start, ticks) do { } while (gcvFALSE) ++# define gcmPROFILE_INIT(start, freq) do { } while (gcvFALSE) ++# define gcmPROFILE_QUERY(start, ticks) do { } while (gcvFALSE) ++# define gcmPROFILE_ONLY(x) do { } while (gcvFALSE) ++# define gcmPROFILE_ELSE(x) x ++# define gcmPROFILE_DECLARE_ONLY(x) do { } while (gcvFALSE) ++# define gcmPROFILE_DECLARE_ELSE(x) x ++#endif ++ ++/******************************************************************************* ++** gcoMATH object ++*/ ++ ++#define gcdPI 3.14159265358979323846f ++ ++/* Kernel. */ ++gctINT ++gckMATH_ModuloInt( ++ IN gctINT X, ++ IN gctINT Y ++ ); ++ ++/* User. */ ++gctUINT32 ++gcoMATH_Log2in5dot5( ++ IN gctINT X ++ ); ++ ++ ++gctFLOAT ++gcoMATH_UIntAsFloat( ++ IN gctUINT32 X ++ ); ++ ++gctUINT32 ++gcoMATH_FloatAsUInt( ++ IN gctFLOAT X ++ ); ++ ++gctBOOL ++gcoMATH_CompareEqualF( ++ IN gctFLOAT X, ++ IN gctFLOAT Y ++ ); ++ ++gctUINT16 ++gcoMATH_UInt8AsFloat16( ++ IN gctUINT8 X ++ ); ++ ++gctUINT32 ++gcoMATH_Float16ToFloat( ++ IN gctUINT16 In ++ ); ++ ++gctUINT16 ++gcoMATH_FloatToFloat16( ++ IN gctUINT32 In ++ ); ++ ++gctUINT32 ++gcoMATH_Float11ToFloat( ++ IN gctUINT32 In ++ ); ++ ++gctUINT16 ++gcoMATH_FloatToFloat11( ++ IN gctUINT32 In ++ ); ++ ++gctUINT32 ++gcoMATH_Float10ToFloat( ++ IN gctUINT32 In ++ ); ++ ++gctUINT16 ++gcoMATH_FloatToFloat10( ++ IN gctUINT32 In ++ ); ++ ++gctUINT32 ++gcoMATH_Float14ToFloat( ++ IN gctUINT16 In ++ ); ++ ++/******************************************************************************\ ++**************************** Coordinate Structures ***************************** ++\******************************************************************************/ ++ ++typedef struct _gcsPOINT ++{ ++ gctINT32 x; ++ gctINT32 y; ++} ++gcsPOINT; ++ ++typedef struct _gcsSIZE ++{ ++ gctINT32 width; ++ gctINT32 height; ++} ++gcsSIZE; ++ ++typedef struct _gcsRECT ++{ ++ gctINT32 left; ++ gctINT32 top; ++ gctINT32 right; ++ gctINT32 bottom; ++} ++gcsRECT; ++ ++typedef union _gcsPIXEL ++{ ++ struct ++ { ++ gctFLOAT r, g, b, a; ++ gctFLOAT d, s; ++ } pf; ++ ++ struct ++ { ++ gctINT32 r, g, b, a; ++ gctINT32 d, s; ++ } pi; ++ ++ struct ++ { ++ gctUINT32 r, g, b, a; ++ gctUINT32 d, s; ++ } pui; ++ ++} gcsPIXEL; ++ ++/******************************************************************************\ ++********************************* gcoSURF Object ******************************** ++\******************************************************************************/ ++ ++/*----------------------------------------------------------------------------*/ ++/*------------------------------- gcoSURF Common ------------------------------*/ ++ ++/* Color format classes. */ ++typedef enum _gceFORMAT_CLASS ++{ ++ gcvFORMAT_CLASS_RGBA = 4500, ++ gcvFORMAT_CLASS_YUV, ++ gcvFORMAT_CLASS_INDEX, ++ gcvFORMAT_CLASS_LUMINANCE, ++ gcvFORMAT_CLASS_BUMP, ++ gcvFORMAT_CLASS_DEPTH, ++ gcvFORMAT_CLASS_ASTC, ++ gcvFORMAT_CLASS_OTHER ++} ++gceFORMAT_CLASS; ++ ++/* Color format data type */ ++typedef enum _gceFORMAT_DATATYPE ++{ ++ gcvFORMAT_DATATYPE_UNSIGNED_NORMALIZED, ++ gcvFORMAT_DATATYPE_SIGNED_NORMALIZED, ++ gcvFORMAT_DATATYPE_UNSIGNED_INTEGER, ++ gcvFORMAT_DATATYPE_SIGNED_INTEGER, ++ gcvFORMAT_DATATYPE_FLOAT16, ++ gcvFORMAT_DATATYPE_FLOAT32, ++ gcvFORMAT_DATATYPE_FLOAT_E5B9G9R9, ++ gcvFORMAT_DATATYPE_FLOAT_B10G11R11F, ++ gcvFORMAT_DATATYPE_INDEX, ++ gcvFORMAT_DATATYPE_SRGB, ++ gcvFORMAT_DATATYPE_FLOAT32_UINT, ++} ++gceFORMAT_DATATYPE; ++ ++/* Special enums for width field in gcsFORMAT_COMPONENT. */ ++typedef enum _gceCOMPONENT_CONTROL ++{ ++ gcvCOMPONENT_NOTPRESENT = 0x00, ++ gcvCOMPONENT_DONTCARE = 0x80, ++ gcvCOMPONENT_WIDTHMASK = 0x7F, ++ gcvCOMPONENT_ODD = 0x80 ++} ++gceCOMPONENT_CONTROL; ++ ++/* Color format component parameters. */ ++typedef struct _gcsFORMAT_COMPONENT ++{ ++ gctUINT8 start; ++ gctUINT8 width; ++} ++gcsFORMAT_COMPONENT; ++ ++/* RGBA color format class. */ ++typedef struct _gcsFORMAT_CLASS_TYPE_RGBA ++{ ++ gcsFORMAT_COMPONENT alpha; ++ gcsFORMAT_COMPONENT red; ++ gcsFORMAT_COMPONENT green; ++ gcsFORMAT_COMPONENT blue; ++} ++gcsFORMAT_CLASS_TYPE_RGBA; ++ ++/* YUV color format class. */ ++typedef struct _gcsFORMAT_CLASS_TYPE_YUV ++{ ++ gcsFORMAT_COMPONENT y; ++ gcsFORMAT_COMPONENT u; ++ gcsFORMAT_COMPONENT v; ++} ++gcsFORMAT_CLASS_TYPE_YUV; ++ ++/* Index color format class. */ ++typedef struct _gcsFORMAT_CLASS_TYPE_INDEX ++{ ++ gcsFORMAT_COMPONENT value; ++} ++gcsFORMAT_CLASS_TYPE_INDEX; ++ ++/* Luminance color format class. */ ++typedef struct _gcsFORMAT_CLASS_TYPE_LUMINANCE ++{ ++ gcsFORMAT_COMPONENT alpha; ++ gcsFORMAT_COMPONENT value; ++} ++gcsFORMAT_CLASS_TYPE_LUMINANCE; ++ ++/* Bump map color format class. */ ++typedef struct _gcsFORMAT_CLASS_TYPE_BUMP ++{ ++ gcsFORMAT_COMPONENT alpha; ++ gcsFORMAT_COMPONENT l; ++ gcsFORMAT_COMPONENT v; ++ gcsFORMAT_COMPONENT u; ++ gcsFORMAT_COMPONENT q; ++ gcsFORMAT_COMPONENT w; ++} ++gcsFORMAT_CLASS_TYPE_BUMP; ++ ++/* Depth and stencil format class. */ ++typedef struct _gcsFORMAT_CLASS_TYPE_DEPTH ++{ ++ gcsFORMAT_COMPONENT depth; ++ gcsFORMAT_COMPONENT stencil; ++} ++gcsFORMAT_CLASS_TYPE_DEPTH; ++ ++typedef union _gcuPIXEL_FORMAT_CLASS ++{ ++ gcsFORMAT_CLASS_TYPE_BUMP bump; ++ gcsFORMAT_CLASS_TYPE_RGBA rgba; ++ gcsFORMAT_CLASS_TYPE_YUV yuv; ++ gcsFORMAT_CLASS_TYPE_LUMINANCE lum; ++ gcsFORMAT_CLASS_TYPE_INDEX index; ++ gcsFORMAT_CLASS_TYPE_DEPTH depth; ++} ++gcuPIXEL_FORMAT_CLASS; ++ ++/* Format parameters. */ ++typedef struct _gcsSURF_FORMAT_INFO ++{ ++ /* Name of the format */ ++ gctCONST_STRING formatName; ++ ++ /* Format code and class. */ ++ gceSURF_FORMAT format; ++ gceFORMAT_CLASS fmtClass; ++ ++ /* Format data type */ ++ gceFORMAT_DATATYPE fmtDataType; ++ ++ /* The size of one pixel in bits. */ ++ gctUINT8 bitsPerPixel; ++ ++ /* Pixel block dimensions. */ ++ gctUINT blockWidth; ++ gctUINT blockHeight; ++ ++ /* Pixel block size in bits. */ ++ gctUINT blockSize; ++ ++ /* Some formats are larger than what the GPU can support. */ ++ /* These formats are read in the number of layers specified. */ ++ gctUINT8 layers; ++ ++ /* The format is faked and software will interpret it differently ++ ** with HW. Most of them can't be blendable(PE) or filterable(TX). ++ */ ++ gctBOOL fakedFormat; ++ ++ /* Some formats have two neighbour pixels interleaved together. */ ++ /* To describe such format, set the flag to 1 and add another */ ++ /* like this one describing the odd pixel format. */ ++ gctBOOL interleaved; ++ ++ /* sRGB format. */ ++ gctBOOL sRGB; ++ ++ /* Format components. */ ++ gcuPIXEL_FORMAT_CLASS u; ++ ++ /* Format components. */ ++ gcuPIXEL_FORMAT_CLASS uOdd; ++ ++ /* Render format. */ ++ gceSURF_FORMAT closestRenderFormat; ++ /*gctCLOSEST_FORMAT dynamicClosestRenderFormat;*/ ++ gctUINT renderFormat; ++ const gceTEXTURE_SWIZZLE * pixelSwizzle; ++ ++ /* Texture format. */ ++ gceSURF_FORMAT closestTXFormat; ++ gctUINT txFormat; ++ const gceTEXTURE_SWIZZLE * txSwizzle; ++ gctBOOL txIntFilter; ++} ++gcsSURF_FORMAT_INFO; ++ ++/* Frame buffer information. */ ++typedef struct _gcsSURF_FRAMEBUFFER ++{ ++ gctPOINTER logical; ++ gctUINT width, height; ++ gctINT stride; ++ gceSURF_FORMAT format; ++} ++gcsSURF_FRAMEBUFFER; ++ ++/* Generic pixel component descriptors. */ ++extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XXX8; ++extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XX8X; ++extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_X8XX; ++extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_8XXX; ++ ++typedef enum _gceORIENTATION ++{ ++ gcvORIENTATION_TOP_BOTTOM, ++ gcvORIENTATION_BOTTOM_TOP, ++} ++gceORIENTATION; ++ ++ ++/* Construct a new gcoSURF object. */ ++gceSTATUS ++gcoSURF_Construct( ++ IN gcoHAL Hal, ++ IN gctUINT Width, ++ IN gctUINT Height, ++ IN gctUINT Depth, ++ IN gceSURF_TYPE Type, ++ IN gceSURF_FORMAT Format, ++ IN gcePOOL Pool, ++ OUT gcoSURF * Surface ++ ); ++ ++/* Destroy an gcoSURF object. */ ++gceSTATUS ++gcoSURF_Destroy( ++ IN gcoSURF Surface ++ ); ++ ++/* Map user-allocated surface. */ ++gceSTATUS ++gcoSURF_MapUserSurface( ++ IN gcoSURF Surface, ++ IN gctUINT Alignment, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical ++ ); ++ ++/* Wrapp surface with known logical/GPU address */ ++gceSTATUS ++gcoSURF_WrapSurface( ++ IN gcoSURF Surface, ++ IN gctUINT Alignment, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical ++ ); ++ ++ ++/* Query vid mem node info. */ ++gceSTATUS ++gcoSURF_QueryVidMemNode( ++ IN gcoSURF Surface, ++ OUT gctUINT32 * Node, ++ OUT gcePOOL * Pool, ++ OUT gctSIZE_T_PTR Bytes ++ ); ++ ++/* Set the color type of the surface. */ ++gceSTATUS ++gcoSURF_SetColorType( ++ IN gcoSURF Surface, ++ IN gceSURF_COLOR_TYPE ColorType ++ ); ++ ++/* Get the color type of the surface. */ ++gceSTATUS ++gcoSURF_GetColorType( ++ IN gcoSURF Surface, ++ OUT gceSURF_COLOR_TYPE *ColorType ++ ); ++ ++/* Set the color space of the surface. */ ++gceSTATUS ++gcoSURF_SetColorSpace( ++ IN gcoSURF Surface, ++ IN gceSURF_COLOR_SPACE ColorSpace ++ ); ++ ++/* Get the color space of the surface. */ ++gceSTATUS ++gcoSURF_GetColorSpace( ++ IN gcoSURF Surface, ++ OUT gceSURF_COLOR_SPACE *ColorSpace ++ ); ++ ++ ++/* Set the surface ration angle. */ ++gceSTATUS ++gcoSURF_SetRotation( ++ IN gcoSURF Surface, ++ IN gceSURF_ROTATION Rotation ++ ); ++ ++gceSTATUS ++gcoSURF_IsValid( ++ IN gcoSURF Surface ++ ); ++ ++#if gcdENABLE_3D ++/* Verify and return the state of the tile status mechanism. */ ++gceSTATUS ++gcoSURF_IsTileStatusSupported( ++ IN gcoSURF Surface ++ ); ++ ++/* Verify if surface has tile status enabled. */ ++gceSTATUS ++gcoSURF_IsTileStatusEnabled( ++ IN gcoSURF Surface ++ ); ++ ++/* Verify if surface is compressed. */ ++gceSTATUS ++gcoSURF_IsCompressed( ++ IN gcoSURF Surface ++ ); ++ ++/* Enable tile status for the specified surface on zero slot. */ ++gceSTATUS ++gcoSURF_EnableTileStatus( ++ IN gcoSURF Surface ++ ); ++ ++/* Enable tile status for the specified surface on specified slot. */ ++gceSTATUS ++gcoSURF_EnableTileStatusEx( ++ IN gcoSURF Surface, ++ IN gctUINT RtIndex ++ ); ++ ++/* Disable tile status for the specified surface. */ ++gceSTATUS ++gcoSURF_DisableTileStatus( ++ IN gcoSURF Surface, ++ IN gctBOOL Decompress ++ ); ++ ++/* Flush tile status cache for the specified surface. */ ++gceSTATUS ++gcoSURF_FlushTileStatus( ++ IN gcoSURF Surface, ++ IN gctBOOL Decompress ++ ); ++#endif /* gcdENABLE_3D */ ++ ++/* Get surface size. */ ++gceSTATUS ++gcoSURF_GetSize( ++ IN gcoSURF Surface, ++ OUT gctUINT * Width, ++ OUT gctUINT * Height, ++ OUT gctUINT * Depth ++ ); ++ ++/* Get surface aligned sizes. */ ++gceSTATUS ++gcoSURF_GetAlignedSize( ++ IN gcoSURF Surface, ++ OUT gctUINT * Width, ++ OUT gctUINT * Height, ++ OUT gctINT * Stride ++ ); ++ ++/* Get alignments. */ ++gceSTATUS ++gcoSURF_GetAlignment( ++ IN gceSURF_TYPE Type, ++ IN gceSURF_FORMAT Format, ++ OUT gctUINT * AddressAlignment, ++ OUT gctUINT * XAlignment, ++ OUT gctUINT * YAlignment ++ ); ++ ++gceSTATUS ++gcoSURF_AlignResolveRect( ++ IN gcoSURF Surf, ++ IN gcsPOINT_PTR RectOrigin, ++ IN gcsPOINT_PTR RectSize, ++ OUT gcsPOINT_PTR AlignedOrigin, ++ OUT gcsPOINT_PTR AlignedSize ++ ); ++ ++/* Get surface type and format. */ ++gceSTATUS ++gcoSURF_GetFormat( ++ IN gcoSURF Surface, ++ OUT OPTIONAL gceSURF_TYPE * Type, ++ OUT OPTIONAL gceSURF_FORMAT * Format ++ ); ++ ++/* Get surface information */ ++gceSTATUS ++gcoSURF_GetFormatInfo( ++ IN gcoSURF Surface, ++ OUT gcsSURF_FORMAT_INFO_PTR * formatInfo ++ ); ++ ++/* Get Surface pack format */ ++gceSTATUS ++gcoSURF_GetPackedFormat( ++ IN gcoSURF Surface, ++ OUT gceSURF_FORMAT * Format ++ ); ++ ++/* Get surface tiling. */ ++gceSTATUS ++gcoSURF_GetTiling( ++ IN gcoSURF Surface, ++ OUT gceTILING * Tiling ++ ); ++ ++/* Get flip bitmap offset bytes. */ ++gceSTATUS ++gcoSURF_GetFlipBitmapOffset( ++ IN gcoSURF Surface, ++ OUT gctUINT_PTR FlipBitmapOffset ++ ); ++ ++/* Get bottom buffer offset bytes. */ ++gceSTATUS ++gcoSURF_GetBottomBufferOffset( ++ IN gcoSURF Surface, ++ OUT gctUINT_PTR BottomBufferOffset ++ ); ++ ++/* Lock the surface. */ ++gceSTATUS ++gcoSURF_Lock( ++ IN gcoSURF Surface, ++ IN OUT gctUINT32 * Address, ++ IN OUT gctPOINTER * Memory ++ ); ++ ++/* Unlock the surface. */ ++gceSTATUS ++gcoSURF_Unlock( ++ IN gcoSURF Surface, ++ IN gctPOINTER Memory ++ ); ++ ++/*. Query surface flags.*/ ++gceSTATUS ++gcoSURF_QueryFlags( ++ IN gcoSURF Surface, ++ IN gceSURF_FLAG Flag ++ ); ++ ++/* Return pixel format parameters; Info is required to be a pointer to an ++ * array of at least two items because some formats have up to two records ++ * of description. */ ++gceSTATUS ++gcoSURF_QueryFormat( ++ IN gceSURF_FORMAT Format, ++ OUT gcsSURF_FORMAT_INFO_PTR * Info ++ ); ++ ++/* Compute the color pixel mask. */ ++gceSTATUS ++gcoSURF_ComputeColorMask( ++ IN gcsSURF_FORMAT_INFO_PTR Format, ++ OUT gctUINT32_PTR ColorMask ++ ); ++ ++/* Flush the surface. */ ++gceSTATUS ++gcoSURF_Flush( ++ IN gcoSURF Surface ++ ); ++ ++/* Fill surface from it's tile status buffer. */ ++gceSTATUS ++gcoSURF_FillFromTile( ++ IN gcoSURF Surface ++ ); ++ ++/* Fill surface with a value. */ ++gceSTATUS ++gcoSURF_Fill( ++ IN gcoSURF Surface, ++ IN gcsPOINT_PTR Origin, ++ IN gcsSIZE_PTR Size, ++ IN gctUINT32 Value, ++ IN gctUINT32 Mask ++ ); ++ ++/* Alpha blend two surfaces together. */ ++gceSTATUS ++gcoSURF_Blend( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gcsPOINT_PTR SrcOrig, ++ IN gcsPOINT_PTR DestOrigin, ++ IN gcsSIZE_PTR Size, ++ IN gceSURF_BLEND_MODE Mode ++ ); ++ ++/* Create a new gcoSURF wrapper object. */ ++gceSTATUS ++gcoSURF_ConstructWrapper( ++ IN gcoHAL Hal, ++ OUT gcoSURF * Surface ++ ); ++ ++/* Set surface flags.*/ ++gceSTATUS ++gcoSURF_SetFlags( ++ IN gcoSURF Surface, ++ IN gceSURF_FLAG Flag, ++ IN gctBOOL Value ++ ); ++ ++/* Set the underlying buffer for the surface wrapper. */ ++gceSTATUS ++gcoSURF_SetBuffer( ++ IN gcoSURF Surface, ++ IN gceSURF_TYPE Type, ++ IN gceSURF_FORMAT Format, ++ IN gctUINT Stride, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical ++ ); ++ ++/* Set the underlying video buffer for the surface wrapper. */ ++gceSTATUS ++gcoSURF_SetVideoBuffer( ++ IN gcoSURF Surface, ++ IN gceSURF_TYPE Type, ++ IN gceSURF_FORMAT Format, ++ IN gctUINT Width, ++ IN gctUINT Height, ++ IN gctUINT Stride, ++ IN gctPOINTER *LogicalPlane1, ++ IN gctUINT32 *PhysicalPlane1 ++ ); ++ ++/* Set the size of the surface in pixels and map the underlying buffer. */ ++gceSTATUS ++gcoSURF_SetWindow( ++ IN gcoSURF Surface, ++ IN gctUINT X, ++ IN gctUINT Y, ++ IN gctUINT Width, ++ IN gctUINT Height ++ ); ++ ++/* Set width/height alignment of the surface directly and calculate stride/size. This is only for dri backend now. Please be careful before use. */ ++gceSTATUS ++gcoSURF_SetAlignment( ++ IN gcoSURF Surface, ++ IN gctUINT Width, ++ IN gctUINT Height ++ ); ++ ++/* Increase reference count of the surface. */ ++gceSTATUS ++gcoSURF_ReferenceSurface( ++ IN gcoSURF Surface ++ ); ++ ++/* Get surface reference count. */ ++gceSTATUS ++gcoSURF_QueryReferenceCount( ++ IN gcoSURF Surface, ++ OUT gctINT32 * ReferenceCount ++ ); ++ ++/* Set surface orientation. */ ++gceSTATUS ++gcoSURF_SetOrientation( ++ IN gcoSURF Surface, ++ IN gceORIENTATION Orientation ++ ); ++ ++/* Query surface orientation. */ ++gceSTATUS ++gcoSURF_QueryOrientation( ++ IN gcoSURF Surface, ++ OUT gceORIENTATION * Orientation ++ ); ++ ++gceSTATUS ++gcoSURF_SetOffset( ++ IN gcoSURF Surface, ++ IN gctSIZE_T Offset ++ ); ++ ++gceSTATUS ++gcoSURF_NODE_Cache( ++ IN gcsSURF_NODE_PTR Node, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++/* Lock and unlock surface node */ ++gceSTATUS ++gcoSURF_LockNode( ++ IN gcsSURF_NODE_PTR Node, ++ OUT gctUINT32 * Address, ++ OUT gctPOINTER * Memory ++ ); ++ ++gceSTATUS ++gcoSURF_UnLockNode( ++ IN gcsSURF_NODE_PTR Node, ++ IN gceSURF_TYPE Type ++ ); ++ ++/* Perform CPU cache operation on surface node */ ++gceSTATUS ++gcoSURF_NODE_CPUCacheOperation( ++ IN gcsSURF_NODE_PTR Node, ++ IN gceSURF_TYPE Type, ++ IN gctSIZE_T Offset, ++ IN gctSIZE_T Length, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++/* Perform CPU cache operation on surface */ ++gceSTATUS ++gcoSURF_CPUCacheOperation( ++ IN gcoSURF Surface, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++ ++gceSTATUS ++gcoSURF_Swap( ++ IN gcoSURF Surface1, ++ IN gcoSURF Surface2 ++ ); ++ ++gceSTATUS ++gcoSURF_ResetSurWH( ++ IN gcoSURF Surface, ++ IN gctUINT oriw, ++ IN gctUINT orih, ++ IN gctUINT alignw, ++ IN gctUINT alignh, ++ IN gceSURF_FORMAT fmt ++); ++ ++/* Update surface timestamp. */ ++gceSTATUS ++gcoSURF_UpdateTimeStamp( ++ IN gcoSURF Surface ++ ); ++ ++/* Query surface current timestamp. */ ++gceSTATUS ++gcoSURF_QueryTimeStamp( ++ IN gcoSURF Surface, ++ OUT gctUINT64 * TimeStamp ++ ); ++ ++/* ++ * Allocate shared buffer for this surface, so that ++ * surface states can be shared across processes. ++ */ ++gceSTATUS ++gcoSURF_AllocShBuffer( ++ IN gcoSURF Surface, ++ OUT gctSHBUF * ShBuf ++ ); ++ ++/* Bind shared buffer to this surface */ ++gceSTATUS ++gcoSURF_BindShBuffer( ++ IN gcoSURF Surface, ++ IN gctSHBUF ShBuf ++ ); ++ ++/* Push surface shared states to shared buffer. */ ++gceSTATUS ++gcoSURF_PushSharedInfo( ++ IN gcoSURF Surface ++ ); ++ ++/* Pop shared states from shared buffer. */ ++gceSTATUS ++gcoSURF_PopSharedInfo( ++ IN gcoSURF Surface ++ ); ++ ++#if (gcdENABLE_3D || gcdENABLE_VG) ++/* Copy surface. */ ++gceSTATUS ++gcoSURF_Copy( ++ IN gcoSURF Surface, ++ IN gcoSURF Source ++ ); ++ ++/* Set number of samples for a gcoSURF object. */ ++gceSTATUS ++gcoSURF_SetSamples( ++ IN gcoSURF Surface, ++ IN gctUINT Samples ++ ); ++ ++/* Get the number of samples per pixel. */ ++gceSTATUS ++gcoSURF_GetSamples( ++ IN gcoSURF Surface, ++ OUT gctUINT_PTR Samples ++ ); ++#endif ++ ++/******************************************************************************\ ++********************************* gcoDUMP Object ******************************** ++\******************************************************************************/ ++ ++/* Construct a new gcoDUMP object. */ ++gceSTATUS ++gcoDUMP_Construct( ++ IN gcoOS Os, ++ IN gcoHAL Hal, ++ OUT gcoDUMP * Dump ++ ); ++ ++/* Destroy a gcoDUMP object. */ ++gceSTATUS ++gcoDUMP_Destroy( ++ IN gcoDUMP Dump ++ ); ++ ++/* Enable/disable dumping. */ ++gceSTATUS ++gcoDUMP_Control( ++ IN gcoDUMP Dump, ++ IN gctSTRING FileName ++ ); ++ ++gceSTATUS ++gcoDUMP_IsEnabled( ++ IN gcoDUMP Dump, ++ OUT gctBOOL * Enabled ++ ); ++ ++/* Add surface. */ ++gceSTATUS ++gcoDUMP_AddSurface( ++ IN gcoDUMP Dump, ++ IN gctINT32 Width, ++ IN gctINT32 Height, ++ IN gceSURF_FORMAT PixelFormat, ++ IN gctUINT32 Address, ++ IN gctSIZE_T ByteCount ++ ); ++ ++/* Mark the beginning of a frame. */ ++gceSTATUS ++gcoDUMP_FrameBegin( ++ IN gcoDUMP Dump ++ ); ++ ++/* Mark the end of a frame. */ ++gceSTATUS ++gcoDUMP_FrameEnd( ++ IN gcoDUMP Dump ++ ); ++ ++/* Dump data. */ ++gceSTATUS ++gcoDUMP_DumpData( ++ IN gcoDUMP Dump, ++ IN gceDUMP_TAG Type, ++ IN gctUINT32 Address, ++ IN gctSIZE_T ByteCount, ++ IN gctCONST_POINTER Data ++ ); ++ ++/* Delete an address. */ ++gceSTATUS ++gcoDUMP_Delete( ++ IN gcoDUMP Dump, ++ IN gctUINT32 Address ++ ); ++ ++/* Enable dump or not. */ ++gceSTATUS ++gcoDUMP_SetDumpFlag( ++ IN gctBOOL DumpState ++ ); ++ ++/******************************************************************************\ ++******************************* gcsRECT Structure ****************************** ++\******************************************************************************/ ++ ++/* Initialize rectangle structure. */ ++gceSTATUS ++gcsRECT_Set( ++ OUT gcsRECT_PTR Rect, ++ IN gctINT32 Left, ++ IN gctINT32 Top, ++ IN gctINT32 Right, ++ IN gctINT32 Bottom ++ ); ++ ++/* Return the width of the rectangle. */ ++gceSTATUS ++gcsRECT_Width( ++ IN gcsRECT_PTR Rect, ++ OUT gctINT32 * Width ++ ); ++ ++/* Return the height of the rectangle. */ ++gceSTATUS ++gcsRECT_Height( ++ IN gcsRECT_PTR Rect, ++ OUT gctINT32 * Height ++ ); ++ ++/* Ensure that top left corner is to the left and above the right bottom. */ ++gceSTATUS ++gcsRECT_Normalize( ++ IN OUT gcsRECT_PTR Rect ++ ); ++ ++/* Compare two rectangles. */ ++gceSTATUS ++gcsRECT_IsEqual( ++ IN gcsRECT_PTR Rect1, ++ IN gcsRECT_PTR Rect2, ++ OUT gctBOOL * Equal ++ ); ++ ++/* Compare the sizes of two rectangles. */ ++gceSTATUS ++gcsRECT_IsOfEqualSize( ++ IN gcsRECT_PTR Rect1, ++ IN gcsRECT_PTR Rect2, ++ OUT gctBOOL * EqualSize ++ ); ++ ++gceSTATUS ++gcsRECT_RelativeRotation( ++ IN gceSURF_ROTATION Orientation, ++ IN OUT gceSURF_ROTATION *Relation); ++ ++gceSTATUS ++ ++gcsRECT_Rotate( ++ ++ IN OUT gcsRECT_PTR Rect, ++ ++ IN gceSURF_ROTATION Rotation, ++ ++ IN gceSURF_ROTATION toRotation, ++ ++ IN gctINT32 SurfaceWidth, ++ ++ IN gctINT32 SurfaceHeight ++ ++ ); ++ ++/******************************************************************************\ ++**************************** gcsBOUNDARY Structure ***************************** ++\******************************************************************************/ ++ ++typedef struct _gcsBOUNDARY ++{ ++ gctINT x; ++ gctINT y; ++ gctINT width; ++ gctINT height; ++} ++gcsBOUNDARY; ++ ++/******************************************************************************\ ++********************************* gcoHEAP Object ******************************** ++\******************************************************************************/ ++ ++typedef struct _gcoHEAP * gcoHEAP; ++ ++/* Construct a new gcoHEAP object. */ ++gceSTATUS ++gcoHEAP_Construct( ++ IN gcoOS Os, ++ IN gctSIZE_T AllocationSize, ++ OUT gcoHEAP * Heap ++ ); ++ ++/* Destroy an gcoHEAP object. */ ++gceSTATUS ++gcoHEAP_Destroy( ++ IN gcoHEAP Heap ++ ); ++ ++/* Allocate memory. */ ++gceSTATUS ++gcoHEAP_Allocate( ++ IN gcoHEAP Heap, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Node ++ ); ++ ++gceSTATUS ++gcoHEAP_GetMemorySize( ++ IN gcoHEAP Heap, ++ IN gctPOINTER Memory, ++ OUT gctSIZE_T_PTR MemorySize ++ ); ++ ++/* Free memory. */ ++gceSTATUS ++gcoHEAP_Free( ++ IN gcoHEAP Heap, ++ IN gctPOINTER Node ++ ); ++ ++#if (VIVANTE_PROFILER || gcdDEBUG) ++/* Profile the heap. */ ++gceSTATUS ++gcoHEAP_ProfileStart( ++ IN gcoHEAP Heap ++ ); ++ ++gceSTATUS ++gcoHEAP_ProfileEnd( ++ IN gcoHEAP Heap, ++ IN gctCONST_STRING Title ++ ); ++#endif ++ ++ ++/******************************************************************************\ ++******************************* Debugging Macros ******************************* ++\******************************************************************************/ ++ ++void ++gcoOS_SetDebugLevel( ++ IN gctUINT32 Level ++ ); ++ ++void ++gcoOS_GetDebugLevel( ++ OUT gctUINT32_PTR DebugLevel ++ ); ++ ++void ++gcoOS_SetDebugZone( ++ IN gctUINT32 Zone ++ ); ++ ++void ++gcoOS_GetDebugZone( ++ IN gctUINT32 Zone, ++ OUT gctUINT32_PTR DebugZone ++ ); ++ ++void ++gcoOS_SetDebugLevelZone( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone ++ ); ++ ++void ++gcoOS_SetDebugZones( ++ IN gctUINT32 Zones, ++ IN gctBOOL Enable ++ ); ++ ++void ++gcoOS_SetDebugFile( ++ IN gctCONST_STRING FileName ++ ); ++ ++gctFILE ++gcoOS_ReplaceDebugFile( ++ IN gctFILE fp ++ ); ++ ++void ++gcoOS_SysTraceBegin( ++ IN gctCONST_STRING FuncName ++ ); ++ ++void ++gcoOS_SysTraceEnd( ++ IN void); ++ ++/******************************************************************************* ++** ++** gcmFATAL ++** ++** Print a message to the debugger and execute a break point. ++** ++** ARGUMENTS: ++** ++** message Message. ++** ... Optional arguments. ++*/ ++ ++void ++gckOS_DebugFatal( ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gcoOS_DebugFatal( ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++#if gcmIS_DEBUG(gcdDEBUG_FATAL) ++# define gcmFATAL gcoOS_DebugFatal ++# define gcmkFATAL gckOS_DebugFatal ++#elif gcdHAS_ELLIPSIS ++# define gcmFATAL(...) ++# define gcmkFATAL(...) ++#else ++ gcmINLINE static void ++ __dummy_fatal( ++ IN gctCONST_STRING Message, ++ ... ++ ) ++ { ++ } ++# define gcmFATAL __dummy_fatal ++# define gcmkFATAL __dummy_fatal ++#endif ++ ++#define gcmENUM2TEXT(e) case e: return #e ++ ++/******************************************************************************* ++** ++** gcmTRACE ++** ++** Print a message to the debugfer if the correct level has been set. In ++** retail mode this macro does nothing. ++** ++** ARGUMENTS: ++** ++** level Level of message. ++** message Message. ++** ... Optional arguments. ++*/ ++#define gcvLEVEL_NONE -1 ++#define gcvLEVEL_ERROR 0 ++#define gcvLEVEL_WARNING 1 ++#define gcvLEVEL_INFO 2 ++#define gcvLEVEL_VERBOSE 3 ++ ++void ++gckOS_DebugTrace( ++ IN gctUINT32 Level, ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gckOS_DebugTraceN( ++ IN gctUINT32 Level, ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gcoOS_DebugTrace( ++ IN gctUINT32 Level, ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++# define gcmTRACE gcoOS_DebugTrace ++# define gcmkTRACE gckOS_DebugTrace ++# define gcmkTRACE_N gckOS_DebugTraceN ++#elif gcdHAS_ELLIPSIS ++# define gcmTRACE(...) ++# define gcmkTRACE(...) ++# define gcmkTRACE_N(...) ++#else ++ gcmINLINE static void ++ __dummy_trace( ++ IN gctUINT32 Level, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++ { ++ } ++ ++ gcmINLINE static void ++ __dummy_trace_n( ++ IN gctUINT32 Level, ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++ { ++ } ++ ++# define gcmTRACE __dummy_trace ++# define gcmkTRACE __dummy_trace ++# define gcmkTRACE_N __dummy_trace_n ++#endif ++ ++/* Zones common for kernel and user. */ ++#define gcvZONE_OS (1 << 0) ++#define gcvZONE_HARDWARE (1 << 1) ++#define gcvZONE_HEAP (1 << 2) ++#define gcvZONE_SIGNAL (1 << 27) ++ ++/* Kernel zones. */ ++#define gcvZONE_KERNEL (1 << 3) ++#define gcvZONE_VIDMEM (1 << 4) ++#define gcvZONE_COMMAND (1 << 5) ++#define gcvZONE_DRIVER (1 << 6) ++#define gcvZONE_CMODEL (1 << 7) ++#define gcvZONE_MMU (1 << 8) ++#define gcvZONE_EVENT (1 << 9) ++#define gcvZONE_DEVICE (1 << 10) ++#define gcvZONE_DATABASE (1 << 11) ++#define gcvZONE_INTERRUPT (1 << 12) ++#define gcvZONE_POWER (1 << 13) ++ ++/* User zones. */ ++#define gcvZONE_HAL (1 << 3) ++#define gcvZONE_BUFFER (1 << 4) ++#define gcvZONE_CONTEXT (1 << 5) ++#define gcvZONE_SURFACE (1 << 6) ++#define gcvZONE_INDEX (1 << 7) ++#define gcvZONE_STREAM (1 << 8) ++#define gcvZONE_TEXTURE (1 << 9) ++#define gcvZONE_2D (1 << 10) ++#define gcvZONE_3D (1 << 11) ++#define gcvZONE_COMPILER (1 << 12) ++#define gcvZONE_MEMORY (1 << 13) ++#define gcvZONE_STATE (1 << 14) ++#define gcvZONE_AUX (1 << 15) ++#define gcvZONE_VERTEX (1 << 16) ++#define gcvZONE_CL (1 << 17) ++#define gcvZONE_COMPOSITION (1 << 17) ++#define gcvZONE_VG (1 << 18) ++#define gcvZONE_IMAGE (1 << 19) ++#define gcvZONE_UTILITY (1 << 20) ++#define gcvZONE_PARAMETERS (1 << 21) ++#define gcvZONE_BUFOBJ (1 << 22) ++#define gcvZONE_SHADER (1 << 23) ++#define gcvZONE_STREAM_OUT (1 << 24) ++ ++/* API definitions. */ ++#define gcvZONE_API_HAL (1 << 28) ++#define gcvZONE_API_EGL (2 << 28) ++#define gcvZONE_API_ES11 (3 << 28) ++#define gcvZONE_API_ES20 (4 << 28) ++#define gcvZONE_API_VG11 (5 << 28) ++#define gcvZONE_API_GL (6 << 28) ++#define gcvZONE_API_DFB (7 << 28) ++#define gcvZONE_API_GDI ((gctUINT32)8 << 28) ++#define gcvZONE_API_D3D ((gctUINT32)9 << 28) ++#define gcvZONE_API_ES30 ((gctUINT32)10 << 28) ++ ++ ++#define gcmZONE_GET_API(zone) ((zone) >> 28) ++/*Set gcdZONE_MASE like 0x0 | gcvZONE_API_EGL ++will enable print EGL module debug info*/ ++#define gcdZONE_MASK 0x0FFFFFFF ++ ++/* Handy zones. */ ++#define gcvZONE_NONE 0 ++#define gcvZONE_ALL 0x0FFFFFFF ++ ++/*Dump API depth set 1 for API, 2 for API and API behavior*/ ++#define gcvDUMP_API_DEPTH 1 ++ ++/******************************************************************************* ++** ++** gcmTRACE_ZONE ++** ++** Print a message to the debugger if the correct level and zone has been ++** set. In retail mode this macro does nothing. ++** ++** ARGUMENTS: ++** ++** Level Level of message. ++** Zone Zone of message. ++** Message Message. ++** ... Optional arguments. ++*/ ++ ++void ++gckOS_DebugTraceZone( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone, ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gckOS_DebugTraceZoneN( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone, ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gcoOS_DebugTraceZone( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone, ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++# define gcmTRACE_ZONE gcoOS_DebugTraceZone ++# define gcmkTRACE_ZONE gckOS_DebugTraceZone ++# define gcmkTRACE_ZONE_N gckOS_DebugTraceZoneN ++#elif gcdHAS_ELLIPSIS ++# define gcmTRACE_ZONE(...) ++# define gcmkTRACE_ZONE(...) ++# define gcmkTRACE_ZONE_N(...) ++#else ++ gcmINLINE static void ++ __dummy_trace_zone( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++ { ++ } ++ ++ gcmINLINE static void ++ __dummy_trace_zone_n( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone, ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++ { ++ } ++ ++# define gcmTRACE_ZONE __dummy_trace_zone ++# define gcmkTRACE_ZONE __dummy_trace_zone ++# define gcmkTRACE_ZONE_N __dummy_trace_zone_n ++#endif ++ ++/******************************************************************************* ++** ++** gcmDEBUG_ONLY ++** ++** Execute a statement or function only in DEBUG mode. ++** ++** ARGUMENTS: ++** ++** f Statement or function to execute. ++*/ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++# define gcmDEBUG_ONLY(f) f ++#else ++# define gcmDEBUG_ONLY(f) ++#endif ++ ++/******************************************************************************* ++** ++** gcmSTACK_PUSH ++** gcmSTACK_POP ++** gcmSTACK_DUMP ++** ++** Push or pop a function with entry arguments on the trace stack. ++** ++** ARGUMENTS: ++** ++** Function Name of function. ++** Line Line number. ++** Text Optional text. ++** ... Optional arguments for text. ++*/ ++#if gcmIS_DEBUG(gcdDEBUG_STACK) ++ void gcoOS_StackPush(IN gctINT8_PTR Identity, IN gctCONST_STRING Function, IN gctINT Line, IN gctCONST_STRING Text, ...); ++ void gcoOS_StackPop(IN gctINT8_PTR Identity, IN gctCONST_STRING Function); ++ void gcoOS_StackDump(void); ++ void gcoOS_StackRemove(IN gctHANDLE Thread); ++ ++# define gcmSTACK_PUSH gcoOS_StackPush ++# define gcmSTACK_POP gcoOS_StackPop ++# define gcmSTACK_DUMP gcoOS_StackDump ++# define gcmSTACK_REMOVE gcoOS_StackRemove ++#elif gcdHAS_ELLIPSIS ++# define gcmSTACK_PUSH(...) do { } while (0) ++# define gcmSTACK_POP(...) do { } while (0) ++# define gcmSTACK_DUMP() do { } while (0) ++# define gcmSTACK_REMOVE(...) do { } while (0) ++#else ++ gcmINLINE static void ++ __dummy_stack_push( ++ IN gctCONST_STRING Function, ++ IN gctINT Line, ++ IN gctCONST_STRING Text, ... ++ ) ++ { ++ } ++# define gcmSTACK_PUSH __dummy_stack_push ++# define gcmSTACK_POP(a,b) do { } while (0) ++# define gcmSTACK_DUMP() do { } while (0) ++# define gcmSTACK_REMOVE(a) do { } while (0) ++#endif ++ ++/******************************************************************************\ ++******************************** Binary Trace ********************************** ++\******************************************************************************/ ++typedef struct _gcsBINARY_TRACE_MESSAGE * gcsBINARY_TRACE_MESSAGE_PTR; ++typedef struct _gcsBINARY_TRACE_MESSAGE ++{ ++ gctUINT32 signature; ++ gctUINT32 pid; ++ gctUINT32 tid; ++ gctUINT32 line; ++ gctUINT32 numArguments; ++ gctUINT8 payload; ++} ++gcsBINARY_TRACE_MESSAGE; ++ ++#define gcdBINARY_TRACE_MESSAGE_SIZE 240 ++ ++#if gcdBINARY_TRACE ++ void ++ gcoOS_BinaryTrace( ++ IN gctCONST_STRING Function, ++ IN gctINT Line, ++ IN gctCONST_STRING Text OPTIONAL, ++ ... ++ ); ++ ++ void ++ gckOS_BinaryTrace( ++ IN gctCONST_STRING Function, ++ IN gctINT Line, ++ IN gctCONST_STRING Text OPTIONAL, ++ ... ++ ); ++ ++# define gcmBINARY_TRACE gcoOS_BinaryTrace ++# define gcmkBINARY_TRACE gckOS_BinaryTrace ++#elif gcdHAS_ELLIPSIS ++# define gcmBINARY_TRACE(Function, Line, Text, ...) ++# define gcmkBINARY_TRACE(Function, Line, Text, ...) ++#else ++ gcmINLINE static void ++ __dummy_binary_trace( ++ IN gctCONST_STRING Function, ++ IN gctINT Line, ++ IN gctCONST_STRING Text, ++ ) ++ { ++ } ++ ++# define gcmBINARY_TRACE __dummy_binary_trace ++# define gcmkBINARY_TRACE __dummy_binary_trace ++#endif ++ ++/******************************************************************************\ ++******************************** Logging Macros ******************************** ++\******************************************************************************/ ++ ++#define gcdHEADER_LEVEL gcvLEVEL_VERBOSE ++ ++#ifndef gcdEMPTY_HEADER_FOOTER ++#define gcdEMPTY_HEADER_FOOTER 0 ++#endif ++ ++#if gcdENABLE_PROFILING ++void ++gcoOS_ProfileDB( ++ IN gctCONST_STRING Function, ++ IN OUT gctBOOL_PTR Initialized ++ ); ++ ++#define gcmHEADER() \ ++ gctINT8 __user__ = 1; \ ++ static gctBOOL __profile__initialized__ = gcvFALSE; \ ++ gcmSTACK_PUSH(&__user__, __FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__) ++#define gcmHEADER_ARG(...) \ ++ gctINT8 __user__ = 1; \ ++ static gctBOOL __profile__initialized__ = gcvFALSE; \ ++ gcmSTACK_PUSH(&__user__, __FUNCTION__, __LINE__, Text, __VA_ARGS__); \ ++ gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__) ++#define gcmFOOTER() \ ++ gcmSTACK_POP(&__user__, __FUNCTION__); \ ++ gcoOS_ProfileDB(__FUNCTION__, gcvNULL) ++#define gcmFOOTER_NO() \ ++ gcmSTACK_POP(&__user__, __FUNCTION__); \ ++ gcoOS_ProfileDB(__FUNCTION__, gcvNULL) ++#define gcmFOOTER_ARG(...) \ ++ gcmSTACK_POP(&__user__, __FUNCTION__); \ ++ gcoOS_ProfileDB(__FUNCTION__, gcvNULL) ++#define gcmFOOTER_KILL() \ ++ gcmSTACK_POP(&__user__, __FUNCTION__); \ ++ gcoOS_ProfileDB(gcvNULL, gcvNULL) ++ ++#else /* gcdENABLE_PROFILING */ ++ ++#ifdef gcdFSL_REL_BUILD ++#define gcmHEADER() ++#elif gcdEMPTY_HEADER_FOOTER ++# define gcmHEADER() ++#elif gcdHAS_ELLIPSIS ++#define gcmHEADER() \ ++ gctINT8 __user__ = 1; \ ++ gctINT8_PTR __user_ptr__ = &__user__; \ ++ gcmSTACK_PUSH(__user_ptr__, __FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "++%s(%d)", __FUNCTION__, __LINE__) ++#else ++ gcmINLINE static void ++ __dummy_header(void) ++ { ++ } ++# define gcmHEADER __dummy_header ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++#define gcmHEADER_ARG(Text, ...) ++#elif gcdHAS_ELLIPSIS ++#if gcdEMPTY_HEADER_FOOTER ++# define gcmHEADER_ARG(Text, ...) ++#else ++# define gcmHEADER_ARG(Text, ...) \ ++ gctINT8 __user__ = 1; \ ++ gctINT8_PTR __user_ptr__ = &__user__; \ ++ gcmSTACK_PUSH(__user_ptr__, __FUNCTION__, __LINE__, Text, __VA_ARGS__); \ ++ gcmBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \ ++ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) ++#endif ++#else ++ gcmINLINE static void ++ __dummy_header_arg( ++ IN gctCONST_STRING Text, ++ ... ++ ) ++ { ++ } ++# define gcmHEADER_ARG __dummy_header_arg ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++# define gcmFOOTER() ++#elif gcdEMPTY_HEADER_FOOTER ++# define gcmFOOTER() ++#elif gcdHAS_ELLIPSIS ++# define gcmFOOTER() \ ++ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \ ++ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "--%s(%d): status=%d(%s)", \ ++ __FUNCTION__, __LINE__, \ ++ status, gcoOS_DebugStatus2Name(status)); \ ++ *__user_ptr__ -= 1 ++#else ++ gcmINLINE static void ++ __dummy_footer(void) ++ { ++ } ++# define gcmFOOTER __dummy_footer ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++#define gcmFOOTER_NO() ++#elif gcdEMPTY_HEADER_FOOTER ++# define gcmFOOTER_NO() ++#elif gcdHAS_ELLIPSIS ++#define gcmFOOTER_NO() \ ++ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \ ++ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "--%s(%d)", __FUNCTION__, __LINE__); \ ++ *__user_ptr__ -= 1 ++#else ++ gcmINLINE static void ++ __dummy_footer_no(void) ++ { ++ } ++# define gcmFOOTER_NO __dummy_footer_no ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++#define gcmFOOTER_KILL() ++#elif gcdEMPTY_HEADER_FOOTER ++# define gcmFOOTER_KILL() ++#elif gcdHAS_ELLIPSIS ++#define gcmFOOTER_KILL() \ ++ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \ ++ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "--%s(%d)", __FUNCTION__, __LINE__); \ ++ *__user_ptr__ -= 1 ++#else ++ gcmINLINE static void ++ __dummy_footer_kill(void) ++ { ++ } ++# define gcmFOOTER_KILL __dummy_footer_kill ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++# define gcmFOOTER_ARG(Text, ...) ++#elif gcdHAS_ELLIPSIS ++#if gcdEMPTY_HEADER_FOOTER ++# define gcmFOOTER_ARG(Text, ...) ++#else ++# define gcmFOOTER_ARG(Text, ...) \ ++ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \ ++ gcmBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \ ++ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "--%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__); \ ++ *__user_ptr__ -= 1 ++#endif ++#else ++ gcmINLINE static void ++ __dummy_footer_arg( ++ IN gctCONST_STRING Text, ++ ... ++ ) ++ { ++ } ++# define gcmFOOTER_ARG __dummy_footer_arg ++#endif ++ ++#endif /* gcdENABLE_PROFILING */ ++ ++#ifdef gcdFSL_REL_BUILD ++#define gcmkHEADER() ++#elif gcdHAS_ELLIPSIS ++#define gcmkHEADER() \ ++ gctINT8 __kernel__ = 1; \ ++ gctINT8_PTR __kernel_ptr__ = &__kernel__; \ ++ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "++%s(%d)", __FUNCTION__, __LINE__) ++#else ++ gcmINLINE static void ++ __dummy_kheader(void) ++ { ++ } ++# define gcmkHEADER __dummy_kheader ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++# define gcmkHEADER_ARG(Text, ...) ++#elif gcdHAS_ELLIPSIS ++# define gcmkHEADER_ARG(Text, ...) \ ++ gctINT8 __kernel__ = 1; \ ++ gctINT8_PTR __kernel_ptr__ = &__kernel__; \ ++ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \ ++ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) ++#else ++ gcmINLINE static void ++ __dummy_kheader_arg( ++ IN gctCONST_STRING Text, ++ ... ++ ) ++ { ++ } ++# define gcmkHEADER_ARG __dummy_kheader_arg ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++#define gcmkFOOTER() ++#elif gcdHAS_ELLIPSIS ++#define gcmkFOOTER() \ ++ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, status); \ ++ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "--%s(%d): status=%d(%s)", \ ++ __FUNCTION__, __LINE__, status, gckOS_DebugStatus2Name(status)); \ ++ *__kernel_ptr__ -= 1 ++#else ++ gcmINLINE static void ++ __dummy_kfooter(void) ++ { ++ } ++# define gcmkFOOTER __dummy_kfooter ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++#define gcmkFOOTER_NO() ++#elif gcdHAS_ELLIPSIS ++#define gcmkFOOTER_NO() \ ++ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ ++ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "--%s(%d)", __FUNCTION__, __LINE__); \ ++ *__kernel_ptr__ -= 1 ++#else ++ gcmINLINE static void ++ __dummy_kfooter_no(void) ++ { ++ } ++# define gcmkFOOTER_NO __dummy_kfooter_no ++#endif ++ ++#ifdef gcdFSL_REL_BUILD ++# define gcmkFOOTER_ARG(Text, ...) ++#elif gcdHAS_ELLIPSIS ++# define gcmkFOOTER_ARG(Text, ...) \ ++ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \ ++ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ ++ "--%s(%d): " Text, \ ++ __FUNCTION__, __LINE__, __VA_ARGS__); \ ++ *__kernel_ptr__ -= 1 ++#else ++ gcmINLINE static void ++ __dummy_kfooter_arg( ++ IN gctCONST_STRING Text, ++ ... ++ ) ++ { ++ } ++# define gcmkFOOTER_ARG __dummy_kfooter_arg ++#endif ++ ++#define gcmOPT_VALUE(ptr) (((ptr) == gcvNULL) ? 0 : *(ptr)) ++#define gcmOPT_VALUE_INDEX(ptr, index) (((ptr) == gcvNULL) ? 0 : ptr[index]) ++#define gcmOPT_POINTER(ptr) (((ptr) == gcvNULL) ? gcvNULL : *(ptr)) ++#define gcmOPT_STRING(ptr) (((ptr) == gcvNULL) ? "(nil)" : (ptr)) ++ ++void ++gckOS_Print( ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gckOS_PrintN( ++ IN gctUINT ArgumentSize, ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gckOS_CopyPrint( ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gcoOS_Print( ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++#define gcmPRINT gcoOS_Print ++#define gcmkPRINT gckOS_Print ++#define gcmkPRINT_N gckOS_PrintN ++ ++#if gcdPRINT_VERSION ++# define gcmPRINT_VERSION() do { \ ++ _gcmPRINT_VERSION(gcm); \ ++ gcmSTACK_DUMP(); \ ++ } while (0) ++# define gcmkPRINT_VERSION() _gcmPRINT_VERSION(gcmk) ++# define _gcmPRINT_VERSION(prefix) \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ "Vivante HAL version %d.%d.%d build %d %s %s", \ ++ gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, \ ++ gcvVERSION_BUILD, gcvVERSION_DATE, gcvVERSION_TIME ) ++#else ++# define gcmPRINT_VERSION() do { gcmSTACK_DUMP(); } while (gcvFALSE) ++# define gcmkPRINT_VERSION() do { } while (gcvFALSE) ++#endif ++ ++typedef enum _gceDUMP_BUFFER ++{ ++ gceDUMP_BUFFER_CONTEXT, ++ gceDUMP_BUFFER_USER, ++ gceDUMP_BUFFER_KERNEL, ++ gceDUMP_BUFFER_LINK, ++ gceDUMP_BUFFER_WAITLINK, ++ gceDUMP_BUFFER_FROM_USER, ++} ++gceDUMP_BUFFER; ++ ++void ++gckOS_DumpBuffer( ++ IN gckOS Os, ++ IN gctPOINTER Buffer, ++ IN gctUINT Size, ++ IN gceDUMP_BUFFER Type, ++ IN gctBOOL CopyMessage ++ ); ++ ++#define gcmkDUMPBUFFER gckOS_DumpBuffer ++ ++#if gcdDUMP_COMMAND ++# define gcmkDUMPCOMMAND(Os, Buffer, Size, Type, CopyMessage) \ ++ gcmkDUMPBUFFER(Os, Buffer, Size, Type, CopyMessage) ++#else ++# define gcmkDUMPCOMMAND(Os, Buffer, Size, Type, CopyMessage) ++#endif ++ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++ ++void ++gckOS_DebugFlush( ++ gctCONST_STRING CallerName, ++ gctUINT LineNumber, ++ gctUINT32 DmaAddress ++ ); ++ ++# define gcmkDEBUGFLUSH(DmaAddress) \ ++ gckOS_DebugFlush(__FUNCTION__, __LINE__, DmaAddress) ++#else ++# define gcmkDEBUGFLUSH(DmaAddress) ++#endif ++ ++/******************************************************************************* ++** ++** gcmDUMP_FRAMERATE ++** ++** Print average frame rate ++** ++*/ ++#if gcdDUMP_FRAMERATE ++ gceSTATUS ++ gcfDumpFrameRate( ++ void ++ ); ++# define gcmDUMP_FRAMERATE gcfDumpFrameRate ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_FRAMERATE(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_frame_rate( ++ void ++ ) ++ { ++ } ++# define gcmDUMP_FRAMERATE __dummy_dump_frame_rate ++#endif ++ ++ ++/******************************************************************************* ++** ++** gcmDUMP ++** ++** Print a dump message. ++** ++** ARGUMENTS: ++** ++** gctSTRING Message. ++** ++** ... Optional arguments. ++*/ ++#if gcdDUMP ++ gceSTATUS ++ gcfDump( ++ IN gcoOS Os, ++ IN gctCONST_STRING String, ++ ... ++ ); ++# define gcmDUMP gcfDump ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP(...) ++#else ++ gcmINLINE static void ++ __dummy_dump( ++ IN gcoOS Os, ++ IN gctCONST_STRING Message, ++ ... ++ ) ++ { ++ } ++# define gcmDUMP __dummy_dump ++#endif ++ ++/******************************************************************************* ++** ++** gcmDUMP_DATA ++** ++** Add data to the dump. ++** ++** ARGUMENTS: ++** ++** gctSTRING Tag ++** Tag for dump. ++** ++** gctPOINTER Logical ++** Logical address of buffer. ++** ++** gctSIZE_T Bytes ++** Number of bytes. ++*/ ++ ++#if gcdDUMP || gcdDUMP_COMMAND ++ gceSTATUS ++ gcfDumpData( ++ IN gcoOS Os, ++ IN gctSTRING Tag, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ); ++# define gcmDUMP_DATA gcfDumpData ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_DATA(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_data( ++ IN gcoOS Os, ++ IN gctSTRING Tag, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ) ++ { ++ } ++# define gcmDUMP_DATA __dummy_dump_data ++#endif ++ ++/******************************************************************************* ++** ++** gcmDUMP_BUFFER ++** ++** Print a buffer to the dump. ++** ++** ARGUMENTS: ++** ++** gctSTRING Tag ++** Tag for dump. ++** ++** gctUINT32 Physical ++** Physical address of buffer. ++** ++** gctPOINTER Logical ++** Logical address of buffer. ++** ++** gctUINT32 Offset ++** Offset into buffer. ++** ++** gctSIZE_T Bytes ++** Number of bytes. ++*/ ++ ++#if gcdDUMP || gcdDUMP_COMMAND ++gceSTATUS ++gcfDumpBuffer( ++ IN gcoOS Os, ++ IN gctSTRING Tag, ++ IN gctUINT32 Physical, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Offset, ++ IN gctSIZE_T Bytes ++ ); ++# define gcmDUMP_BUFFER gcfDumpBuffer ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_BUFFER(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_buffer( ++ IN gcoOS Os, ++ IN gctSTRING Tag, ++ IN gctUINT32 Physical, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Offset, ++ IN gctSIZE_T Bytes ++ ) ++ { ++ } ++# define gcmDUMP_BUFFER __dummy_dump_buffer ++#endif ++ ++/******************************************************************************* ++** ++** gcmDUMP_API ++** ++** Print a dump message for a high level API prefixed by the function name. ++** ++** ARGUMENTS: ++** ++** gctSTRING Message. ++** ++** ... Optional arguments. ++*/ ++gceSTATUS gcfDumpApi(IN gctCONST_STRING String, ...); ++#if gcdDUMP_API ++# define gcmDUMP_API gcfDumpApi ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_API(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_api( ++ IN gctCONST_STRING Message, ++ ... ++ ) ++ { ++ } ++# define gcmDUMP_API __dummy_dump_api ++#endif ++ ++/******************************************************************************* ++** ++** gcmDUMP_API_ARRAY ++** ++** Print an array of data. ++** ++** ARGUMENTS: ++** ++** gctUINT32_PTR Pointer to array. ++** gctUINT32 Size. ++*/ ++gceSTATUS gcfDumpArray(IN gctCONST_POINTER Data, IN gctUINT32 Size); ++#if gcdDUMP_API ++# define gcmDUMP_API_ARRAY gcfDumpArray ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_API_ARRAY(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_api_array( ++ IN gctCONST_POINTER Data, ++ IN gctUINT32 Size ++ ) ++ { ++ } ++# define gcmDUMP_API_ARRAY __dummy_dump_api_array ++#endif ++ ++/******************************************************************************* ++** ++** gcmDUMP_API_ARRAY_TOKEN ++** ++** Print an array of data terminated by a token. ++** ++** ARGUMENTS: ++** ++** gctUINT32_PTR Pointer to array. ++** gctUINT32 Termination. ++*/ ++gceSTATUS gcfDumpArrayToken(IN gctCONST_POINTER Data, IN gctUINT32 Termination); ++#if gcdDUMP_API ++# define gcmDUMP_API_ARRAY_TOKEN gcfDumpArrayToken ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_API_ARRAY_TOKEN(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_api_array_token( ++ IN gctCONST_POINTER Data, ++ IN gctUINT32 Termination ++ ) ++ { ++ } ++# define gcmDUMP_API_ARRAY_TOKEN __dummy_dump_api_array_token ++#endif ++ ++/******************************************************************************* ++** ++** gcmDUMP_API_DATA ++** ++** Print an array of bytes. ++** ++** ARGUMENTS: ++** ++** gctCONST_POINTER Pointer to array. ++** gctSIZE_T Size. ++*/ ++gceSTATUS gcfDumpApiData(IN gctCONST_POINTER Data, IN gctSIZE_T Size); ++#if gcdDUMP_API ++# define gcmDUMP_API_DATA gcfDumpApiData ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_API_DATA(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_api_data( ++ IN gctCONST_POINTER Data, ++ IN gctSIZE_T Size ++ ) ++ { ++ } ++# define gcmDUMP_API_DATA __dummy_dump_api_data ++#endif ++ ++/******************************************************************************* ++** gcmDUMP_2D_COMMAND ++** ++** Print the 2D command buffer. ++** ++** ARGUMENTS: ++** ++** gctUINT32_PTR Pointer to the command buffer. ++** gctUINT32 Command buffer size. ++*/ ++gceSTATUS gcfDump2DCommand(IN gctUINT32_PTR Command, IN gctUINT32 Size); ++#if gcdDUMP_2D ++# define gcmDUMP_2D_COMMAND gcfDump2DCommand ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_2D_COMMAND(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_2d_command( ++ IN gctUINT32_PTR Command, ++ IN gctUINT32 Size ++ ) ++ { ++ } ++# define gcmDUMP_2D_COMMAND __dummy_dump_2d_command ++#endif ++ ++/******************************************************************************* ++** gcmDUMP_2D_SURFACE ++** ++** Print the 2D surface memory. ++** ++** ARGUMENTS: ++** ++** gctBOOL Src. ++** gctUINT32 Address. ++*/ ++gceSTATUS gcfDump2DSurface(IN gctBOOL Src, IN gctUINT32 Address); ++#if gcdDUMP_2D ++# define gcmDUMP_2D_SURFACE gcfDump2DSurface ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_2D_SURFACE(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_2d_surface( ++ IN gctBOOL Src, ++ IN gctUINT32 Address ++ ) ++ { ++ } ++# define gcmDUMP_2D_SURFACE __dummy_dump_2d_surface ++#endif ++ ++/******************************************************************************* ++** gcmDUMP_ADD_MEMORY_INFO ++** ++** Record the memory info. ++** ++** ARGUMENTS: ++** ++** gctUINT32 Address. ++** gctSIZE_T Size. ++*/ ++gceSTATUS gcfAddMemoryInfo(IN gctUINT32 GPUAddress, IN gctPOINTER Logical, IN gctUINT32 Physical, IN gctUINT32 Size); ++#if gcdDUMP_2D ++# define gcmDUMP_ADD_MEMORY_INFO gcfAddMemoryInfo ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_ADD_MEMORY_INFO(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_add_memory_info( ++ IN gctUINT32 GPUAddress, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Physical, ++ IN gctUINT32 Size ++ ) ++ { ++ } ++# define gcmDUMP_ADD_MEMORY_INFO __dummy_dump_add_memory_info ++#endif ++ ++/******************************************************************************* ++** gcmDUMP_DEL_MEMORY_INFO ++** ++** Record the memory info. ++** ++** ARGUMENTS: ++** ++** gctUINT32 Address. ++*/ ++gceSTATUS gcfDelMemoryInfo(IN gctUINT32 Address); ++#if gcdDUMP_2D ++# define gcmDUMP_DEL_MEMORY_INFO gcfDelMemoryInfo ++#elif gcdHAS_ELLIPSIS ++# define gcmDUMP_DEL_MEMORY_INFO(...) ++#else ++ gcmINLINE static void ++ __dummy_dump_del_memory_info( ++ IN gctUINT32 Address ++ ) ++ { ++ } ++# define gcmDUMP_DEL_MEMORY_INFO __dummy_dump_del_memory_info ++#endif ++ ++#if gcdDUMP_2D ++extern gctPOINTER dumpMemInfoListMutex; ++extern gctBOOL dump2DFlag; ++#endif ++ ++/******************************************************************************* ++** ++** gcmTRACE_RELEASE ++** ++** Print a message to the shader debugger. ++** ++** ARGUMENTS: ++** ++** message Message. ++** ... Optional arguments. ++*/ ++ ++#define gcmTRACE_RELEASE gcoOS_DebugShaderTrace ++ ++void ++gcoOS_DebugShaderTrace( ++ IN gctCONST_STRING Message, ++ ... ++ ); ++ ++void ++gcoOS_SetDebugShaderFiles( ++ IN gctCONST_STRING VSFileName, ++ IN gctCONST_STRING FSFileName ++ ); ++ ++void ++gcoOS_SetDebugShaderFileType( ++ IN gctUINT32 ShaderType ++ ); ++ ++void ++gcoOS_EnableDebugBuffer( ++ IN gctBOOL Enable ++ ); ++ ++/******************************************************************************* ++** ++** gcmBREAK ++** ++** Break into the debugger. In retail mode this macro does nothing. ++** ++** ARGUMENTS: ++** ++** None. ++*/ ++ ++void ++gcoOS_DebugBreak( ++ void ++ ); ++ ++void ++gckOS_DebugBreak( ++ void ++ ); ++ ++#if gcmIS_DEBUG(gcdDEBUG_BREAK) ++# define gcmBREAK gcoOS_DebugBreak ++# define gcmkBREAK gckOS_DebugBreak ++#else ++# define gcmBREAK() ++# define gcmkBREAK() ++#endif ++ ++/******************************************************************************* ++** ++** gcmASSERT ++** ++** Evaluate an expression and break into the debugger if the expression ++** evaluates to false. In retail mode this macro does nothing. ++** ++** ARGUMENTS: ++** ++** exp Expression to evaluate. ++*/ ++#if gcmIS_DEBUG(gcdDEBUG_ASSERT) ++# define _gcmASSERT(prefix, exp) \ ++ do \ ++ { \ ++ if (!(exp)) \ ++ { \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ASSERT at %s(%d)", \ ++ __FUNCTION__, __LINE__); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ "(%s)", #exp); \ ++ prefix##BREAK(); \ ++ } \ ++ } \ ++ while (gcvFALSE) ++# define gcmASSERT(exp) _gcmASSERT(gcm, exp) ++# define gcmkASSERT(exp) _gcmASSERT(gcmk, exp) ++#else ++# define gcmASSERT(exp) ++# define gcmkASSERT(exp) ++#endif ++ ++/******************************************************************************* ++** ++** gcmVERIFY ++** ++** Verify if an expression returns true. If the expression does not ++** evaluates to true, an assertion will happen in debug mode. ++** ++** ARGUMENTS: ++** ++** exp Expression to evaluate. ++*/ ++#if gcmIS_DEBUG(gcdDEBUG_ASSERT) ++# define gcmVERIFY(exp) gcmASSERT(exp) ++# define gcmkVERIFY(exp) gcmkASSERT(exp) ++#else ++# define gcmVERIFY(exp) exp ++# define gcmkVERIFY(exp) exp ++#endif ++ ++/******************************************************************************* ++** ++** gcmVERIFY_OK ++** ++** Verify a fucntion returns gcvSTATUS_OK. If the function does not return ++** gcvSTATUS_OK, an assertion will happen in debug mode. ++** ++** ARGUMENTS: ++** ++** func Function to evaluate. ++*/ ++ ++void ++gcoOS_Verify( ++ IN gceSTATUS status ++ ); ++ ++void ++gckOS_Verify( ++ IN gceSTATUS status ++ ); ++ ++#if gcmIS_DEBUG(gcdDEBUG_ASSERT) ++# define gcmVERIFY_OK(func) \ ++ do \ ++ { \ ++ gceSTATUS verifyStatus = func; \ ++ gcoOS_Verify(verifyStatus); \ ++ if (verifyStatus != gcvSTATUS_OK) \ ++ { \ ++ gcmTRACE( \ ++ gcvLEVEL_ERROR, \ ++ "gcmVERIFY_OK(%d): function returned %d", \ ++ __LINE__, verifyStatus \ ++ ); \ ++ } \ ++ gcmASSERT(verifyStatus == gcvSTATUS_OK); \ ++ } \ ++ while (gcvFALSE) ++# define gcmkVERIFY_OK(func) \ ++ do \ ++ { \ ++ gceSTATUS verifyStatus = func; \ ++ if (verifyStatus != gcvSTATUS_OK) \ ++ { \ ++ gcmkTRACE( \ ++ gcvLEVEL_ERROR, \ ++ "gcmkVERIFY_OK(%d): function returned %d", \ ++ __LINE__, verifyStatus \ ++ ); \ ++ } \ ++ gckOS_Verify(verifyStatus); \ ++ gcmkASSERT(verifyStatus == gcvSTATUS_OK); \ ++ } \ ++ while (gcvFALSE) ++#else ++# define gcmVERIFY_OK(func) func ++# define gcmkVERIFY_OK(func) func ++#endif ++ ++gctCONST_STRING ++gcoOS_DebugStatus2Name( ++ gceSTATUS status ++ ); ++ ++gctCONST_STRING ++gckOS_DebugStatus2Name( ++ gceSTATUS status ++ ); ++ ++/******************************************************************************* ++** ++** gcmERR_BREAK ++** ++** Executes a break statement on error. ++** ++** ASSUMPTIONS: ++** ++** 'status' variable of gceSTATUS type must be defined. ++** ++** ARGUMENTS: ++** ++** func Function to evaluate. ++*/ ++#define _gcmERR_BREAK(prefix, func) \ ++ status = func; \ ++ if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \ ++ status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ break; \ ++ } \ ++ do { } while (gcvFALSE) ++#define _gcmkERR_BREAK(prefix, func) \ ++ status = func; \ ++ if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \ ++ status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ break; \ ++ } \ ++ do { } while (gcvFALSE) ++#define gcmERR_BREAK(func) _gcmERR_BREAK(gcm, func) ++#define gcmkERR_BREAK(func) _gcmkERR_BREAK(gcmk, func) ++ ++/******************************************************************************* ++** ++** gcmERR_RETURN ++** ++** Executes a return on error. ++** ++** ASSUMPTIONS: ++** ++** 'status' variable of gceSTATUS type must be defined. ++** ++** ARGUMENTS: ++** ++** func Function to evaluate. ++*/ ++#define _gcmERR_RETURN(prefix, func) \ ++ status = func; \ ++ if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \ ++ status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ prefix##FOOTER(); \ ++ return status; \ ++ } \ ++ do { } while (gcvFALSE) ++#define _gcmkERR_RETURN(prefix, func) \ ++ status = func; \ ++ if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \ ++ status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ prefix##FOOTER(); \ ++ return status; \ ++ } \ ++ do { } while (gcvFALSE) ++#define gcmERR_RETURN(func) _gcmERR_RETURN(gcm, func) ++#define gcmkERR_RETURN(func) _gcmkERR_RETURN(gcmk, func) ++ ++/******************************************************************************* ++** ++** gcmONWARNING ++** ++** Jump to the error handler in case there is an error, but only report at ++** the WARNING debug level. This is for non fatal errors. ++** ++** ASSUMPTIONS: ++** ++** 'status' variable of gceSTATUS type must be defined. ++** ++** ARGUMENTS: ++** ++** func Function to evaluate. ++*/ ++#define _gcmONWARNING(prefix, func) \ ++ do \ ++ { \ ++ status = func; \ ++ if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_WARNING, \ ++ #prefix "ONWARNING: status=%d(%s) @ %s(%d)", \ ++ status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ status = gcvSTATUS_WARNING; \ ++ goto OnError; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++#define _gcmkONWARNING(prefix, func) \ ++ do \ ++ { \ ++ status = func; \ ++ if (gcmIS_WARNING(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_WARNING, \ ++ #prefix "ONWARNING: status=%d(%s) @ %s(%d)", \ ++ status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ status = gcvSTATUS_WARNING; \ ++ goto OnError; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++#define gcmONWARNING(func) _gcmONWARNING(gcm, func) ++#define gcmkONWARNING(func) _gcmkONWARNING(gcmk, func) ++ ++/******************************************************************************* ++** ++** gcmONERROR ++** ++** Jump to the error handler in case there is an error. ++** ++** ASSUMPTIONS: ++** ++** 'status' variable of gceSTATUS type must be defined. ++** ++** ARGUMENTS: ++** ++** func Function to evaluate. ++*/ ++#define _gcmONERROR(prefix, func) \ ++ do \ ++ { \ ++ status = func; \ ++ if (gcmIS_WARNING(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_WARNING, \ ++ #prefix "ONWARNING: status=%d(%s) @ %s(%d)", \ ++ status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ goto OnError; \ ++ } \ ++ else if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ONERROR: status=%d(%s) @ %s(%d)", \ ++ status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ goto OnError; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++#define _gcmkONERROR(prefix, func) \ ++ do \ ++ { \ ++ status = func; \ ++ if (gcmIS_WARNING(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_WARNING, \ ++ #prefix "ONWARNING: status=%d(%s) @ %s(%d)", \ ++ status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ goto OnError; \ ++ } \ ++ else if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ONERROR: status=%d(%s) @ %s(%d)", \ ++ status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ goto OnError; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++#define gcmONERROR(func) _gcmONERROR(gcm, func) ++#define gcmkONERROR(func) _gcmkONERROR(gcmk, func) ++ ++/******************************************************************************* ++** ++** gcmkSAFECASTSIZET ++** ++** Check wether value of a gctSIZE_T varible beyond the capability ++** of 32bits GPU hardware. ++** ++** ASSUMPTIONS: ++** ++** ++** ++** ARGUMENTS: ++** ++** x A gctUINT32 variable ++** y A gctSIZE_T variable ++*/ ++#define gcmkSAFECASTSIZET(x, y) \ ++ do \ ++ { \ ++ gctUINT32 tmp = (gctUINT32)(y); \ ++ if (gcmSIZEOF(gctSIZE_T) > gcmSIZEOF(gctUINT32)) \ ++ { \ ++ gcmkASSERT(tmp <= gcvMAXUINT32); \ ++ } \ ++ (x) = tmp; \ ++ } \ ++ while (gcvFALSE) ++ ++#define gcmSAFECASTSIZET(x, y) \ ++ do \ ++ { \ ++ gctUINT32 tmp = (gctUINT32)(y); \ ++ if (gcmSIZEOF(gctSIZE_T) > gcmSIZEOF(gctUINT32)) \ ++ { \ ++ gcmASSERT(tmp <= gcvMAXUINT32); \ ++ } \ ++ (x) = tmp; \ ++ } \ ++ while (gcvFALSE) ++ ++/******************************************************************************* ++** ++** gcmVERIFY_LOCK ++** ++** Verifies whether the surface is locked. ++** ++** ARGUMENTS: ++** ++** surfaceInfo Pointer to the surface iniformational structure. ++*/ ++#define gcmVERIFY_LOCK(surfaceInfo) \ ++ if (!surfaceInfo->node.valid) \ ++ { \ ++ gcmONERROR(gcvSTATUS_MEMORY_UNLOCKED); \ ++ } \ ++ ++/******************************************************************************* ++** ++** gcmVERIFY_NODE_LOCK ++** ++** Verifies whether the surface node is locked. ++** ++** ARGUMENTS: ++** ++** surfaceInfo Pointer to the surface iniformational structure. ++*/ ++#define gcmVERIFY_NODE_LOCK(surfaceNode) \ ++ if (!(surfaceNode)->valid) \ ++ { \ ++ status = gcvSTATUS_MEMORY_UNLOCKED; \ ++ break; \ ++ } \ ++ do { } while (gcvFALSE) ++ ++/******************************************************************************* ++** ++** gcmBADOBJECT_BREAK ++** ++** Executes a break statement on bad object. ++** ++** ARGUMENTS: ++** ++** obj Object to test. ++** t Expected type of the object. ++*/ ++#define gcmBADOBJECT_BREAK(obj, t) \ ++ if ((obj == gcvNULL) \ ++ || (((gcsOBJECT *)(obj))->type != t) \ ++ ) \ ++ { \ ++ status = gcvSTATUS_INVALID_OBJECT; \ ++ break; \ ++ } \ ++ do { } while (gcvFALSE) ++ ++/******************************************************************************* ++** ++** gcmCHECK_STATUS ++** ++** Executes a break statement on error. ++** ++** ASSUMPTIONS: ++** ++** 'status' variable of gceSTATUS type must be defined. ++** ++** ARGUMENTS: ++** ++** func Function to evaluate. ++*/ ++#define _gcmCHECK_STATUS(prefix, func) \ ++ do \ ++ { \ ++ last = func; \ ++ if (gcmIS_ERROR(last)) \ ++ { \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \ ++ last, gcoOS_DebugStatus2Name(last), __FUNCTION__, __LINE__); \ ++ status = last; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++#define _gcmkCHECK_STATUS(prefix, func) \ ++ do \ ++ { \ ++ last = func; \ ++ if (gcmIS_ERROR(last)) \ ++ { \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \ ++ last, gckOS_DebugStatus2Name(last), __FUNCTION__, __LINE__); \ ++ status = last; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++#define gcmCHECK_STATUS(func) _gcmCHECK_STATUS(gcm, func) ++#define gcmkCHECK_STATUS(func) _gcmkCHECK_STATUS(gcmk, func) ++ ++/******************************************************************************* ++** ++** gcmVERIFY_ARGUMENT ++** ++** Assert if an argument does not apply to the specified expression. If ++** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be ++** returned from the current function. In retail mode this macro does ++** nothing. ++** ++** ARGUMENTS: ++** ++** arg Argument to evaluate. ++*/ ++# define _gcmVERIFY_ARGUMENT(prefix, arg) \ ++ do \ ++ { \ ++ if (!(arg)) \ ++ { \ ++ prefix##TRACE(gcvLEVEL_ERROR, #prefix "VERIFY_ARGUMENT failed:"); \ ++ prefix##ASSERT(arg); \ ++ prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); \ ++ return gcvSTATUS_INVALID_ARGUMENT; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++# define gcmVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg) ++# define gcmkVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcmk, arg) ++ ++/******************************************************************************* ++** ++** gcmDEBUG_VERIFY_ARGUMENT ++** ++** Works just like gcmVERIFY_ARGUMENT, but is only valid in debug mode. ++** Use this to verify arguments inside non-public API functions. ++*/ ++#if gcdDEBUG ++# define gcmDEBUG_VERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg) ++# define gcmkDEBUG_VERIFY_ARGUMENT(arg) _gcmkVERIFY_ARGUMENT(gcm, arg) ++#else ++# define gcmDEBUG_VERIFY_ARGUMENT(arg) ++# define gcmkDEBUG_VERIFY_ARGUMENT(arg) ++#endif ++ ++/******************************************************************************* ++** ++** gcmVERIFY_ARGUMENT_RETURN ++** ++** Assert if an argument does not apply to the specified expression. If ++** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be ++** returned from the current function. In retail mode this macro does ++** nothing. ++** ++** ARGUMENTS: ++** ++** arg Argument to evaluate. ++*/ ++# define _gcmVERIFY_ARGUMENT_RETURN(prefix, arg, value) \ ++ do \ ++ { \ ++ if (!(arg)) \ ++ { \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "gcmVERIFY_ARGUMENT_RETURN failed:"); \ ++ prefix##ASSERT(arg); \ ++ prefix##FOOTER_ARG("value=%d", value); \ ++ return value; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++# define gcmVERIFY_ARGUMENT_RETURN(arg, value) \ ++ _gcmVERIFY_ARGUMENT_RETURN(gcm, arg, value) ++# define gcmkVERIFY_ARGUMENT_RETURN(arg, value) \ ++ _gcmVERIFY_ARGUMENT_RETURN(gcmk, arg, value) ++ ++#define MAX_LOOP_COUNT 0x7FFFFFFF ++ ++/******************************************************************************\ ++****************************** User Debug Option ****************************** ++\******************************************************************************/ ++ ++/* User option. */ ++typedef enum _gceDEBUG_MSG ++{ ++ gcvDEBUG_MSG_NONE, ++ gcvDEBUG_MSG_ERROR, ++ gcvDEBUG_MSG_WARNING ++} ++gceDEBUG_MSG; ++ ++typedef struct _gcsUSER_DEBUG_OPTION ++{ ++ gceDEBUG_MSG debugMsg; ++} ++gcsUSER_DEBUG_OPTION; ++ ++gcsUSER_DEBUG_OPTION * ++gcGetUserDebugOption( ++ void ++ ); ++ ++#if defined(ANDROID) ++struct _gcoOS_SymbolsList ++{ ++#if gcdENABLE_3D ++ gcePATCH_ID patchId; ++#endif ++ const char * symList[10]; ++}; ++#endif ++ ++#if gcdHAS_ELLIPSIS ++#define gcmUSER_DEBUG_MSG(level, ...) \ ++ do \ ++ { \ ++ if (level <= gcGetUserDebugOption()->debugMsg) \ ++ { \ ++ gcoOS_Print(__VA_ARGS__); \ ++ } \ ++ } while (gcvFALSE) ++ ++#define gcmUSER_DEBUG_ERROR_MSG(...) gcmUSER_DEBUG_MSG(gcvDEBUG_MSG_ERROR, "Error: " __VA_ARGS__) ++#define gcmUSER_DEBUG_WARNING_MSG(...) gcmUSER_DEBUG_MSG(gcvDEBUG_MSG_WARNING, "Warring: " __VA_ARGS__) ++#else ++#define gcmUSER_DEBUG_MSG ++#define gcmUSER_DEBUG_ERROR_MSG ++#define gcmUSER_DEBUG_WARNING_MSG ++#endif ++ ++/******************************************************************************* ++** ++** A set of macros to aid state loading. ++** ++** ARGUMENTS: ++** ++** CommandBuffer Pointer to a gcoCMDBUF object. ++** StateDelta Pointer to a gcsSTATE_DELTA state delta structure. ++** Memory Destination memory pointer of gctUINT32_PTR type. ++** PartOfContext Whether or not the state is a part of the context. ++** FixedPoint Whether or not the state is of the fixed point format. ++** Count Number of consecutive states to be loaded. ++** Address State address. ++** Data Data to be set to the state. ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++ ++# define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count) \ ++ CommandBuffer->lastLoadStatePtr = gcmPTR_TO_UINT64(Memory); \ ++ CommandBuffer->lastLoadStateAddress = Address; \ ++ CommandBuffer->lastLoadStateCount = Count ++ ++# define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address) \ ++ gcmASSERT( \ ++ (gctUINT) (Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastLoadStatePtr, gctUINT32_PTR) - 1) \ ++ == \ ++ (gctUINT) (Address - CommandBuffer->lastLoadStateAddress) \ ++ ); \ ++ \ ++ gcmASSERT(CommandBuffer->lastLoadStateCount > 0); \ ++ \ ++ CommandBuffer->lastLoadStateCount -= 1 ++ ++# define gcmVERIFYLOADSTATEDONE(CommandBuffer) \ ++ gcmASSERT(CommandBuffer->lastLoadStateCount == 0); ++ ++# define gcmDEFINELOADSTATEBASE() \ ++ gctUINT32_PTR LoadStateBase; ++ ++# define gcmSETLOADSTATEBASE(CommandBuffer, OutSide) \ ++ if (OutSide) \ ++ {\ ++ LoadStateBase = (gctUINT32_PTR)*OutSide; \ ++ }\ ++ else\ ++ {\ ++ LoadStateBase = (gctUINT_PTR)CommandBuffer->buffer;\ ++ } ++ ++ ++# define gcmVERIFYLOADSTATEALIGNED(CommandBuffer, Memory) \ ++ gcmASSERT(((Memory - LoadStateBase) & 1) == 0); ++ ++# define gcmUNSETLOADSTATEBASE() \ ++ LoadStateBase = LoadStateBase; ++ ++#else ++ ++# define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count) ++# define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address) ++# define gcmVERIFYLOADSTATEDONE(CommandBuffer) ++ ++# define gcmDEFINELOADSTATEBASE() ++# define gcmSETLOADSTATEBASE(CommandBuffer, OutSide) ++# define gcmVERIFYLOADSTATEALIGNED(CommandBuffer, Memory) ++# define gcmUNSETLOADSTATEBASE() ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++ ++#if gcdDUMP ++# define gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, Data) \ ++ if (FixedPoint) \ ++ { \ ++ gcmDUMP(gcvNULL, "#[state.x 0x%04X 0x%08X]", \ ++ Address, Data \ ++ ); \ ++ } \ ++ else \ ++ { \ ++ gcmDUMP(gcvNULL, "#[state 0x%04X 0x%08X]", \ ++ Address, Data \ ++ ); \ ++ } ++#else ++# define gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, Data) ++#endif ++ ++#define gcmDEFINESTATEBUFFER(CommandBuffer, StateDelta, Memory, ReserveSize) \ ++ gcmDEFINESECUREUSER() \ ++ gctSIZE_T ReserveSize; \ ++ gcoCMDBUF CommandBuffer; \ ++ gctUINT32_PTR Memory; \ ++ gcsSTATE_DELTA_PTR StateDelta ++ ++#define gcmBEGINSTATEBUFFER(Hardware, CommandBuffer, StateDelta, Memory, ReserveSize) \ ++{ \ ++ gcmONERROR(gcoBUFFER_Reserve( \ ++ Hardware->buffer, ReserveSize, gcvTRUE, gcvCOMMAND_3D, &CommandBuffer \ ++ )); \ ++ \ ++ Memory = (gctUINT32_PTR) gcmUINT64_TO_PTR(CommandBuffer->lastReserve); \ ++ \ ++ StateDelta = Hardware->delta; \ ++ \ ++ gcmBEGINSECUREUSER(); \ ++} ++ ++#define gcmENDSTATEBUFFER(Hardware, CommandBuffer, Memory, ReserveSize) \ ++{ \ ++ gcmENDSECUREUSER(); \ ++ \ ++ gcmASSERT( \ ++ gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT8_PTR) + ReserveSize \ ++ == \ ++ (gctUINT8_PTR) Memory \ ++ ); \ ++} ++ ++/*----------------------------------------------------------------------------*/ ++ ++#define gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, Count) \ ++{ \ ++ gcmASSERT(((Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT32_PTR)) & 1) == 0); \ ++ gcmASSERT((gctUINT32)Count <= 1024); \ ++ \ ++ gcmVERIFYLOADSTATEDONE(CommandBuffer); \ ++ \ ++ gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count); \ ++ \ ++ *Memory++ \ ++ = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, FLOAT, FixedPoint) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, Count) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, Address); \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++#define gcmENDSTATEBATCH(CommandBuffer, Memory) \ ++{ \ ++ gcmVERIFYLOADSTATEDONE(CommandBuffer); \ ++ \ ++ gcmASSERT(((Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT32_PTR)) & 1) == 0); \ ++} ++ ++/*----------------------------------------------------------------------------*/ ++ ++#define gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \ ++ \ ++ gcmSAFECASTSIZET(__temp_data32__, Data); \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcoHARDWARE_UpdateDelta( \ ++ StateDelta, Address, 0, __temp_data32__ \ ++ ); \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++#define gcmSETSTATEDATAWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcoHARDWARE_UpdateDelta( \ ++ StateDelta, Address, Mask, __temp_data32__ \ ++ ); \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++ ++#define gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, gcvFALSE, Address, __temp_data32__); \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++#define gcmSETFILLER(CommandBuffer, Memory) \ ++{ \ ++ gcmVERIFYLOADSTATEDONE(CommandBuffer); \ ++ \ ++ Memory += 1; \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++/*----------------------------------------------------------------------------*/ ++ ++#define gcmSETSINGLESTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data); \ ++ gcmENDSTATEBATCH(CommandBuffer, Memory); \ ++} ++ ++#define gcmSETSINGLESTATEWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATAWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data); \ ++ gcmENDSTATEBATCH(CommandBuffer, Memory); \ ++} ++ ++ ++#define gcmSETSINGLECTRLSTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data); \ ++ gcmENDSTATEBATCH(CommandBuffer, Memory); \ ++} ++ ++ ++ ++#define gcmSETSEMASTALLPIPE(StateDelta, CommandBuffer, Memory, Data) \ ++{ \ ++ gcmSETSINGLESTATE(StateDelta, CommandBuffer, Memory, gcvFALSE, AQSemaphoreRegAddrs, Data); \ ++ \ ++ *Memory++ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \ ++ \ ++ *Memory++ = Data; \ ++ \ ++ gcmDUMP(gcvNULL, "#[stall 0x%08X 0x%08X]", \ ++ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END), \ ++ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE)); \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++/******************************************************************************* ++** ++** gcmSETSTARTDECOMMAND ++** ++** Form a START_DE command. ++** ++** ARGUMENTS: ++** ++** Memory Destination memory pointer of gctUINT32_PTR type. ++** Count Number of the rectangles. ++*/ ++ ++#define gcmSETSTARTDECOMMAND(Memory, Count) \ ++{ \ ++ *Memory++ \ ++ = gcmSETFIELDVALUE(0, AQ_COMMAND_START_DE_COMMAND, OPCODE, START_DE) \ ++ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, COUNT, Count) \ ++ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, DATA_COUNT, 0); \ ++ \ ++ *Memory++ = 0xDEADDEED; \ ++} ++ ++/***************************************** ++** Temp command buffer macro ++*/ ++#define gcmDEFINESTATEBUFFER_NEW(CommandBuffer, StateDelta, Memory) \ ++ gcmDEFINESECUREUSER() \ ++ gcmDEFINELOADSTATEBASE() \ ++ gcsTEMPCMDBUF CommandBuffer = gcvNULL; \ ++ gctUINT32_PTR Memory; \ ++ gcsSTATE_DELTA_PTR StateDelta ++ ++ ++#define gcmBEGINSTATEBUFFER_NEW(Hardware, CommandBuffer, StateDelta, Memory, OutSide) \ ++{ \ ++ if (OutSide) \ ++ {\ ++ Memory = (gctUINT32_PTR)*OutSide; \ ++ }\ ++ else \ ++ {\ ++ gcmONERROR(gcoBUFFER_StartTEMPCMDBUF( \ ++ Hardware->buffer, &CommandBuffer \ ++ ));\ ++ \ ++ Memory = (gctUINT32_PTR)(CommandBuffer->buffer); \ ++ \ ++ }\ ++ StateDelta = Hardware->delta; \ ++ \ ++ gcmBEGINSECUREUSER(); \ ++ gcmSETLOADSTATEBASE(CommandBuffer,OutSide);\ ++} ++ ++#define gcmENDSTATEBUFFER_NEW(Hardware, CommandBuffer, Memory, OutSide) \ ++{ \ ++ gcmENDSECUREUSER(); \ ++ \ ++ if (OutSide) \ ++ {\ ++ *OutSide = Memory; \ ++ }\ ++ else \ ++ {\ ++ CommandBuffer->currentByteSize = (gctUINT32)((gctUINT8_PTR)Memory - \ ++ (gctUINT8_PTR)CommandBuffer->buffer); \ ++ \ ++ gcmONERROR(gcoBUFFER_EndTEMPCMDBUF(Hardware->buffer));\ ++ }\ ++ gcmUNSETLOADSTATEBASE()\ ++} ++ ++/*----------------------------------------------------------------------------*/ ++ ++#define gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, Count) \ ++{ \ ++ gcmVERIFYLOADSTATEALIGNED(CommandBuffer,Memory);\ ++ gcmASSERT((gctUINT32)Count <= 1024); \ ++ \ ++ *Memory++ \ ++ = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, FLOAT, FixedPoint) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, Count) \ ++ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, Address); \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++#define gcmENDSTATEBATCH_NEW(CommandBuffer, Memory) \ ++ gcmVERIFYLOADSTATEALIGNED(CommandBuffer,Memory); ++ ++/*----------------------------------------------------------------------------*/ ++ ++#define gcmSETSTATEDATA_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcoHARDWARE_UpdateDelta( \ ++ StateDelta, Address, 0, __temp_data32__ \ ++ ); \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++#define gcmSETSTATEDATAWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcoHARDWARE_UpdateDelta( \ ++ StateDelta, Address, Mask, __temp_data32__ \ ++ ); \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++ ++#define gcmSETCTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, Address, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, gcvFALSE, Address, __temp_data32__); \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++#define gcmSETFILLER_NEW(CommandBuffer, Memory) \ ++{ \ ++ Memory += 1; \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++/*----------------------------------------------------------------------------*/ ++ ++#define gcmSETSINGLESTATE_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATA_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data); \ ++ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \ ++} ++ ++#define gcmSETSINGLESTATEWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATAWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data); \ ++ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \ ++} ++ ++ ++#define gcmSETSINGLECTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETCTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, Address, Data); \ ++ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \ ++} ++ ++ ++ ++#define gcmSETSEMASTALLPIPE_NEW(StateDelta, CommandBuffer, Memory, Data) \ ++{ \ ++ gcmSETSINGLESTATE_NEW(StateDelta, CommandBuffer, Memory, gcvFALSE, AQSemaphoreRegAddrs, Data); \ ++ \ ++ *Memory++ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \ ++ \ ++ *Memory++ = Data; \ ++ \ ++ gcmDUMP(gcvNULL, "#[stall 0x%08X 0x%08X]", \ ++ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END), \ ++ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE)); \ ++ \ ++ gcmSKIPSECUREUSER(); \ ++} ++ ++#define gcmSETSTARTDECOMMAND_NEW(CommandBuffer, Memory, Count) \ ++{ \ ++ *Memory++ \ ++ = gcmSETFIELDVALUE(0, AQ_COMMAND_START_DE_COMMAND, OPCODE, START_DE) \ ++ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, COUNT, Count) \ ++ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, DATA_COUNT, 0); \ ++ \ ++ *Memory++ = 0xDEADDEED; \ ++ \ ++} ++ ++#define gcmSETSTATEDATA_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++#define gcmSETSTATEDATAWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++#define gcmSETSINGLESTATE_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATA_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data); \ ++ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \ ++} ++ ++#define gcmSETSINGLESTATEWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATAWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data); \ ++ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \ ++} ++ ++#define gcmSETSTATEDATA_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \ ++ \ ++ gcmSAFECASTSIZET(__temp_data32__, Data); \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++#define gcmSETSTATEDATAWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gctUINT32 __temp_data32__; \ ++ \ ++ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \ ++ \ ++ __temp_data32__ = Data; \ ++ \ ++ *Memory++ = __temp_data32__; \ ++ \ ++ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ ++ \ ++ gcmUPDATESECUREUSER(); \ ++} ++ ++#define gcmSETSINGLESTATE_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATA_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Data); \ ++ gcmENDSTATEBATCH(CommandBuffer, Memory); \ ++} ++ ++#define gcmSETSINGLESTATEWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data) \ ++{ \ ++ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \ ++ gcmSETSTATEDATAWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \ ++ Address, Mask, Data); \ ++ gcmENDSTATEBATCH(CommandBuffer, Memory); \ ++} ++ ++#define gcmDEFINESTATEBUFFER_NEW_FAST(CommandBuffer, Memory) \ ++ gcmDEFINESECUREUSER() \ ++ gcmDEFINELOADSTATEBASE() \ ++ gcsTEMPCMDBUF CommandBuffer = gcvNULL; \ ++ gctUINT32_PTR Memory; ++ ++#define gcmDEFINESTATEBUFFER_FAST(CommandBuffer, Memory, ReserveSize) \ ++ gcmDEFINESECUREUSER() \ ++ gctSIZE_T ReserveSize; \ ++ gcoCMDBUF CommandBuffer; \ ++ gctUINT32_PTR Memory; ++ ++#define gcmBEGINSTATEBUFFER_FAST(Hardware, CommandBuffer, Memory, ReserveSize) \ ++{ \ ++ gcmONERROR(gcoBUFFER_Reserve( \ ++ Hardware->buffer, ReserveSize, gcvTRUE, &CommandBuffer \ ++ )); \ ++ \ ++ Memory = (gctUINT32_PTR) gcmUINT64_TO_PTR(CommandBuffer->lastReserve); \ ++ \ ++ gcmBEGINSECUREUSER(); \ ++} ++ ++#define gcmBEGINSTATEBUFFER_NEW_FAST(Hardware, CommandBuffer, Memory, OutSide) \ ++{ \ ++ if (OutSide) \ ++ {\ ++ Memory = (gctUINT32_PTR)*OutSide; \ ++ }\ ++ else \ ++ {\ ++ gcmONERROR(gcoBUFFER_StartTEMPCMDBUF( \ ++ Hardware->buffer, &CommandBuffer \ ++ ));\ ++ \ ++ Memory = (gctUINT32_PTR)(CommandBuffer->buffer); \ ++ \ ++ }\ ++ \ ++ gcmBEGINSECUREUSER(); \ ++ gcmSETLOADSTATEBASE(CommandBuffer,OutSide);\ ++} ++/******************************************************************************* ++** ++** gcmCONFIGUREUNIFORMS ++** ++** Configure uniforms according to chip and numConstants. ++*/ ++#if !gcdENABLE_UNIFIED_CONSTANT ++#define gcmCONFIGUREUNIFORMS(ChipModel, ChipRevision, NumConstants, \ ++ UnifiedConst, VsConstBase, PsConstBase, VsConstMax, PsConstMax, ConstMax) \ ++{ \ ++ if (ChipModel == gcv2000 && ChipRevision == 0x5118) \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 256; \ ++ PsConstMax = 64; \ ++ ConstMax = 320; \ ++ } \ ++ else if (NumConstants == 320) \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 256; \ ++ PsConstMax = 64; \ ++ ConstMax = 320; \ ++ } \ ++ /* All GC1000 series chips can only support 64 uniforms for ps on non-unified const mode. */ \ ++ else if (NumConstants > 256 && ChipModel == gcv1000) \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 256; \ ++ PsConstMax = 64; \ ++ ConstMax = 320; \ ++ } \ ++ else if (NumConstants > 256) \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 256; \ ++ PsConstMax = 256; \ ++ ConstMax = 512; \ ++ } \ ++ else if (NumConstants == 256) \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 256; \ ++ PsConstMax = 256; \ ++ ConstMax = 512; \ ++ } \ ++ else \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 168; \ ++ PsConstMax = 64; \ ++ ConstMax = 232; \ ++ } \ ++} ++#else ++#define gcmCONFIGUREUNIFORMS(ChipModel, ChipRevision, NumConstants, \ ++ UnifiedConst, VsConstBase, PsConstBase, VsConstMax, PsConstMax, ConstMax) \ ++{ \ ++ if (NumConstants > 256) \ ++ { \ ++ UnifiedConst = gcvTRUE; \ ++ VsConstBase = gcregSHUniformsRegAddrs; \ ++ PsConstBase = gcregSHUniformsRegAddrs; \ ++ ConstMax = NumConstants; \ ++ VsConstMax = 256; \ ++ PsConstMax = ConstMax - VsConstMax; \ ++ } \ ++ else if (NumConstants == 256) \ ++ { \ ++ if (ChipModel == gcv2000 && ChipRevision == 0x5118) \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 256; \ ++ PsConstMax = 64; \ ++ ConstMax = 320; \ ++ } \ ++ else \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 256; \ ++ PsConstMax = 256; \ ++ ConstMax = 512; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ UnifiedConst = gcvFALSE; \ ++ VsConstBase = AQVertexShaderConstRegAddrs; \ ++ PsConstBase = AQPixelShaderConstRegAddrs; \ ++ VsConstMax = 168; \ ++ PsConstMax = 64; \ ++ ConstMax = 232; \ ++ } \ ++} ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_base_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_driver.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_driver.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_driver.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_driver.h 2016-06-19 22:11:55.153149980 +0200 +@@ -0,0 +1,1064 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++#ifndef __gc_hal_driver_h_ ++#define __gc_hal_driver_h_ ++ ++#include "gc_hal_enum.h" ++#include "gc_hal_types.h" ++ ++#if gcdENABLE_VG ++#include "gc_hal_driver_vg.h" ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++******************************* I/O Control Codes ****************************** ++\******************************************************************************/ ++ ++#define gcvHAL_CLASS "galcore" ++#define IOCTL_GCHAL_INTERFACE 30000 ++#define IOCTL_GCHAL_KERNEL_INTERFACE 30001 ++#define IOCTL_GCHAL_TERMINATE 30002 ++ ++#undef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT ++/******************************************************************************\ ++********************************* Command Codes ******************************** ++\******************************************************************************/ ++ ++typedef enum _gceHAL_COMMAND_CODES ++{ ++ /* Generic query. */ ++ gcvHAL_QUERY_VIDEO_MEMORY, ++ gcvHAL_QUERY_CHIP_IDENTITY, ++ ++ /* Contiguous memory. */ ++ gcvHAL_ALLOCATE_NON_PAGED_MEMORY, ++ gcvHAL_FREE_NON_PAGED_MEMORY, ++ gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY, ++ gcvHAL_FREE_CONTIGUOUS_MEMORY, ++ ++ /* Video memory allocation. */ ++ gcvHAL_ALLOCATE_VIDEO_MEMORY, /* Enforced alignment. */ ++ gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY, /* No alignment. */ ++ gcvHAL_RELEASE_VIDEO_MEMORY, ++ ++ /* Physical-to-logical mapping. */ ++ gcvHAL_MAP_MEMORY, ++ gcvHAL_UNMAP_MEMORY, ++ ++ /* Logical-to-physical mapping. */ ++ gcvHAL_MAP_USER_MEMORY, ++ gcvHAL_UNMAP_USER_MEMORY, ++ ++ /* Surface lock/unlock. */ ++ gcvHAL_LOCK_VIDEO_MEMORY, ++ gcvHAL_UNLOCK_VIDEO_MEMORY, ++ ++ /* Event queue. */ ++ gcvHAL_EVENT_COMMIT, ++ ++ gcvHAL_USER_SIGNAL, ++ gcvHAL_SIGNAL, ++ gcvHAL_WRITE_DATA, ++ ++ gcvHAL_COMMIT, ++ gcvHAL_STALL, ++ ++ gcvHAL_READ_REGISTER, ++ gcvHAL_WRITE_REGISTER, ++ ++ gcvHAL_GET_PROFILE_SETTING, ++ gcvHAL_SET_PROFILE_SETTING, ++ ++ gcvHAL_READ_ALL_PROFILE_REGISTERS, ++ gcvHAL_PROFILE_REGISTERS_2D, ++#if VIVANTE_PROFILER_PERDRAW ++ gcvHAL_READ_PROFILER_REGISTER_SETTING, ++#endif ++ ++ /* Power management. */ ++ gcvHAL_SET_POWER_MANAGEMENT_STATE, ++ gcvHAL_QUERY_POWER_MANAGEMENT_STATE, ++ ++ gcvHAL_GET_BASE_ADDRESS, ++ ++ gcvHAL_SET_IDLE, /* reserved */ ++ ++ /* Queries. */ ++ gcvHAL_QUERY_KERNEL_SETTINGS, ++ ++ /* Reset. */ ++ gcvHAL_RESET, ++ ++ /* Map physical address into handle. */ ++ gcvHAL_MAP_PHYSICAL, ++ ++ /* Debugger stuff. */ ++ gcvHAL_DEBUG, ++ ++ /* Cache stuff. */ ++ gcvHAL_CACHE, ++ ++ /* TimeStamp */ ++ gcvHAL_TIMESTAMP, ++ ++ /* Database. */ ++ gcvHAL_DATABASE, ++ ++ /* Version. */ ++ gcvHAL_VERSION, ++ ++ /* Chip info */ ++ gcvHAL_CHIP_INFO, ++ ++ /* Process attaching/detaching. */ ++ gcvHAL_ATTACH, ++ gcvHAL_DETACH, ++ ++ /* Composition. */ ++ gcvHAL_COMPOSE, ++ ++ /* Set timeOut value */ ++ gcvHAL_SET_TIMEOUT, ++ ++ /* Frame database. */ ++ gcvHAL_GET_FRAME_INFO, ++ ++ gcvHAL_QUERY_COMMAND_BUFFER, ++ ++ gcvHAL_COMMIT_DONE, ++ ++ /* GPU and event dump */ ++ gcvHAL_DUMP_GPU_STATE, ++ gcvHAL_DUMP_EVENT, ++ ++ /* Virtual command buffer. */ ++ gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER, ++ gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER, ++ ++ /* FSCALE_VAL. */ ++ gcvHAL_SET_FSCALE_VALUE, ++ gcvHAL_GET_FSCALE_VALUE, ++ ++ gcvHAL_NAME_VIDEO_MEMORY, ++ gcvHAL_IMPORT_VIDEO_MEMORY, ++ ++ /* Reset time stamp. */ ++ gcvHAL_QUERY_RESET_TIME_STAMP, ++ ++ /* Multi-GPU read/write. */ ++ gcvHAL_READ_REGISTER_EX, ++ gcvHAL_WRITE_REGISTER_EX, ++ ++ /* Sync point operations. */ ++ gcvHAL_SYNC_POINT, ++ ++ /* Create native fence and return its fd. */ ++ gcvHAL_CREATE_NATIVE_FENCE, ++ ++ /* Destory MMU. */ ++ gcvHAL_DESTROY_MMU, ++ ++ /* Shared buffer. */ ++ gcvHAL_SHBUF, ++ ++ /* Config power management. */ ++ gcvHAL_CONFIG_POWER_MANAGEMENT, ++ ++ /* Connect a video node to an OS native fd. */ ++ gcvHAL_GET_VIDEO_MEMORY_FD, ++} ++gceHAL_COMMAND_CODES; ++ ++/******************************************************************************\ ++****************************** Interface Structure ***************************** ++\******************************************************************************/ ++ ++#define gcdMAX_PROFILE_FILE_NAME 128 ++ ++/* Kernel settings. */ ++typedef struct _gcsKERNEL_SETTINGS ++{ ++ /* Used RealTime signal between kernel and user. */ ++ gctINT signal; ++} ++gcsKERNEL_SETTINGS; ++ ++ ++/* gcvHAL_QUERY_CHIP_IDENTITY */ ++typedef struct _gcsHAL_QUERY_CHIP_IDENTITY * gcsHAL_QUERY_CHIP_IDENTITY_PTR; ++typedef struct _gcsHAL_QUERY_CHIP_IDENTITY ++{ ++ ++ /* Chip model. */ ++ gceCHIPMODEL chipModel; ++ ++ /* Revision value.*/ ++ gctUINT32 chipRevision; ++ ++ /* Supported feature fields. */ ++ gctUINT32 chipFeatures; ++ ++ /* Supported minor feature fields. */ ++ gctUINT32 chipMinorFeatures; ++ ++ /* Supported minor feature 1 fields. */ ++ gctUINT32 chipMinorFeatures1; ++ ++ /* Supported minor feature 2 fields. */ ++ gctUINT32 chipMinorFeatures2; ++ ++ /* Supported minor feature 3 fields. */ ++ gctUINT32 chipMinorFeatures3; ++ ++ /* Supported minor feature 4 fields. */ ++ gctUINT32 chipMinorFeatures4; ++ ++ /* Supported minor feature 5 fields. */ ++ gctUINT32 chipMinorFeatures5; ++ ++ /* Number of streams supported. */ ++ gctUINT32 streamCount; ++ ++ /* Total number of temporary registers per thread. */ ++ gctUINT32 registerMax; ++ ++ /* Maximum number of threads. */ ++ gctUINT32 threadCount; ++ ++ /* Number of shader cores. */ ++ gctUINT32 shaderCoreCount; ++ ++ /* Size of the vertex cache. */ ++ gctUINT32 vertexCacheSize; ++ ++ /* Number of entries in the vertex output buffer. */ ++ gctUINT32 vertexOutputBufferSize; ++ ++ /* Number of pixel pipes. */ ++ gctUINT32 pixelPipes; ++ ++ /* Number of instructions. */ ++ gctUINT32 instructionCount; ++ ++ /* Number of constants. */ ++ gctUINT32 numConstants; ++ ++ /* Buffer size */ ++ gctUINT32 bufferSize; ++ ++ /* Number of varyings */ ++ gctUINT32 varyingsCount; ++ ++ /* Supertile layout style in hardware */ ++ gctUINT32 superTileMode; ++ ++ /* Special control bits for 2D chip. */ ++ gctUINT32 chip2DControl; ++ ++ /* Product ID */ ++ gctUINT32 productID; ++} ++gcsHAL_QUERY_CHIP_IDENTITY; ++ ++/* gcvHAL_COMPOSE. */ ++typedef struct _gcsHAL_COMPOSE * gcsHAL_COMPOSE_PTR; ++typedef struct _gcsHAL_COMPOSE ++{ ++ /* Composition state buffer. */ ++ gctUINT64 physical; ++ gctUINT64 logical; ++ gctUINT offset; ++ gctUINT size; ++ ++ /* Composition end signal. */ ++ gctUINT64 process; ++ gctUINT64 signal; ++ ++ /* User signals. */ ++ gctUINT64 userProcess; ++ gctUINT64 userSignal1; ++ gctUINT64 userSignal2; ++} ++gcsHAL_COMPOSE; ++ ++ ++typedef struct _gcsHAL_INTERFACE ++{ ++ /* Command code. */ ++ gceHAL_COMMAND_CODES command; ++ ++ /* Hardware type. */ ++ gceHARDWARE_TYPE hardwareType; ++ ++ /* Status value. */ ++ gceSTATUS status; ++ ++ /* Handle to this interface channel. */ ++ gctUINT64 handle; ++ ++ /* Pid of the client. */ ++ gctUINT32 pid; ++ ++ /* Union of command structures. */ ++ union _u ++ { ++ /* gcvHAL_GET_BASE_ADDRESS */ ++ struct _gcsHAL_GET_BASE_ADDRESS ++ { ++ /* Physical memory address of internal memory. */ ++ OUT gctUINT32 baseAddress; ++ } ++ GetBaseAddress; ++ ++ /* gcvHAL_QUERY_VIDEO_MEMORY */ ++ struct _gcsHAL_QUERY_VIDEO_MEMORY ++ { ++ /* Physical memory address of internal memory. Just a name. */ ++ OUT gctUINT32 internalPhysical; ++ ++ /* Size in bytes of internal memory. */ ++ OUT gctUINT64 internalSize; ++ ++ /* Physical memory address of external memory. Just a name. */ ++ OUT gctUINT32 externalPhysical; ++ ++ /* Size in bytes of external memory.*/ ++ OUT gctUINT64 externalSize; ++ ++ /* Physical memory address of contiguous memory. Just a name. */ ++ OUT gctUINT32 contiguousPhysical; ++ ++ /* Size in bytes of contiguous memory.*/ ++ OUT gctUINT64 contiguousSize; ++ } ++ QueryVideoMemory; ++ ++ /* gcvHAL_QUERY_CHIP_IDENTITY */ ++ gcsHAL_QUERY_CHIP_IDENTITY QueryChipIdentity; ++ ++ /* gcvHAL_MAP_MEMORY */ ++ struct _gcsHAL_MAP_MEMORY ++ { ++ /* Physical memory address to map. Just a name on Linux/Qnx. */ ++ IN gctUINT32 physical; ++ ++ /* Number of bytes in physical memory to map. */ ++ IN gctUINT64 bytes; ++ ++ /* Address of mapped memory. */ ++ OUT gctUINT64 logical; ++ } ++ MapMemory; ++ ++ /* gcvHAL_UNMAP_MEMORY */ ++ struct _gcsHAL_UNMAP_MEMORY ++ { ++ /* Physical memory address to unmap. Just a name on Linux/Qnx. */ ++ IN gctUINT32 physical; ++ ++ /* Number of bytes in physical memory to unmap. */ ++ IN gctUINT64 bytes; ++ ++ /* Address of mapped memory to unmap. */ ++ IN gctUINT64 logical; ++ } ++ UnmapMemory; ++ ++ /* gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY */ ++ struct _gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY ++ { ++ /* Number of bytes to allocate. */ ++ IN OUT gctUINT bytes; ++ ++ /* Buffer alignment. */ ++ IN gctUINT alignment; ++ ++ /* Type of allocation. */ ++ IN gceSURF_TYPE type; ++ ++ /* Flag of allocation. */ ++ IN gctUINT32 flag; ++ ++ /* Memory pool to allocate from. */ ++ IN OUT gcePOOL pool; ++ ++ /* Allocated video memory. */ ++ OUT gctUINT32 node; ++ } ++ AllocateLinearVideoMemory; ++ ++ /* gcvHAL_ALLOCATE_VIDEO_MEMORY */ ++ struct _gcsHAL_ALLOCATE_VIDEO_MEMORY ++ { ++ /* Width of rectangle to allocate. */ ++ IN OUT gctUINT width; ++ ++ /* Height of rectangle to allocate. */ ++ IN OUT gctUINT height; ++ ++ /* Depth of rectangle to allocate. */ ++ IN gctUINT depth; ++ ++ /* Format rectangle to allocate in gceSURF_FORMAT. */ ++ IN gceSURF_FORMAT format; ++ ++ /* Type of allocation. */ ++ IN gceSURF_TYPE type; ++ ++ /* Memory pool to allocate from. */ ++ IN OUT gcePOOL pool; ++ ++ /* Allocated video memory. */ ++ OUT gctUINT32 node; ++ } ++ AllocateVideoMemory; ++ ++ /* gcvHAL_RELEASE_VIDEO_MEMORY */ ++ struct _gcsHAL_RELEASE_VIDEO_MEMORY ++ { ++ /* Allocated video memory. */ ++ IN gctUINT32 node; ++ } ++ ReleaseVideoMemory; ++ ++ /* gcvHAL_LOCK_VIDEO_MEMORY */ ++ struct _gcsHAL_LOCK_VIDEO_MEMORY ++ { ++ /* Allocated video memory. */ ++ IN gctUINT32 node; ++ ++ /* Cache configuration. */ ++ /* Only gcvPOOL_CONTIGUOUS and gcvPOOL_VIRUTAL ++ ** can be configured */ ++ IN gctBOOL cacheable; ++ ++ /* Hardware specific address. */ ++ OUT gctUINT32 address; ++ ++ /* Mapped logical address. */ ++ OUT gctUINT64 memory; ++ ++ /* Customer priviate handle*/ ++ OUT gctUINT32 gid; ++ ++ /* Bus address of a contiguous video node. */ ++ OUT gctUINT64 physicalAddress; ++ } ++ LockVideoMemory; ++ ++ /* gcvHAL_UNLOCK_VIDEO_MEMORY */ ++ struct _gcsHAL_UNLOCK_VIDEO_MEMORY ++ { ++ /* Allocated video memory. */ ++ IN gctUINT64 node; ++ ++ /* Type of surface. */ ++ IN gceSURF_TYPE type; ++ ++ /* Flag to unlock surface asynchroneously. */ ++ IN OUT gctBOOL asynchroneous; ++ } ++ UnlockVideoMemory; ++ ++ /* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */ ++ struct _gcsHAL_ALLOCATE_NON_PAGED_MEMORY ++ { ++ /* Number of bytes to allocate. */ ++ IN OUT gctUINT64 bytes; ++ ++ /* Physical address of allocation. Just a name. */ ++ OUT gctUINT32 physical; ++ ++ /* Logical address of allocation. */ ++ OUT gctUINT64 logical; ++ } ++ AllocateNonPagedMemory; ++ ++ /* gcvHAL_FREE_NON_PAGED_MEMORY */ ++ struct _gcsHAL_FREE_NON_PAGED_MEMORY ++ { ++ /* Number of bytes allocated. */ ++ IN gctUINT64 bytes; ++ ++ /* Physical address of allocation. Just a name. */ ++ IN gctUINT32 physical; ++ ++ /* Logical address of allocation. */ ++ IN gctUINT64 logical; ++ } ++ FreeNonPagedMemory; ++ ++ /* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */ ++ struct _gcsHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER ++ { ++ /* Number of bytes to allocate. */ ++ IN OUT gctUINT64 bytes; ++ ++ /* Physical address of allocation. Just a name. */ ++ OUT gctUINT32 physical; ++ ++ /* Logical address of allocation. */ ++ OUT gctUINT64 logical; ++ } ++ AllocateVirtualCommandBuffer; ++ ++ /* gcvHAL_FREE_NON_PAGED_MEMORY */ ++ struct _gcsHAL_FREE_VIRTUAL_COMMAND_BUFFER ++ { ++ /* Number of bytes allocated. */ ++ IN gctUINT64 bytes; ++ ++ /* Physical address of allocation. Just a name. */ ++ IN gctUINT32 physical; ++ ++ /* Logical address of allocation. */ ++ IN gctUINT64 logical; ++ } ++ FreeVirtualCommandBuffer; ++ ++ /* gcvHAL_EVENT_COMMIT. */ ++ struct _gcsHAL_EVENT_COMMIT ++ { ++ /* Event queue in gcsQUEUE. */ ++ IN gctUINT64 queue; ++ } ++ Event; ++ ++ /* gcvHAL_COMMIT */ ++ struct _gcsHAL_COMMIT ++ { ++ /* Context buffer object gckCONTEXT. */ ++ IN gctUINT64 context; ++ ++ /* Command buffer gcoCMDBUF. */ ++ IN gctUINT64 commandBuffer; ++ ++ /* State delta buffer in gcsSTATE_DELTA. */ ++ gctUINT64 delta; ++ ++ /* Event queue in gcsQUEUE. */ ++ IN gctUINT64 queue; ++ } ++ Commit; ++ ++ /* gcvHAL_MAP_USER_MEMORY */ ++ struct _gcsHAL_MAP_USER_MEMORY ++ { ++ /* Base address of user memory to map. */ ++ IN gctUINT64 memory; ++ ++ /* Physical address of user memory to map. */ ++ IN gctUINT32 physical; ++ ++ /* Size of user memory in bytes to map. */ ++ IN gctUINT64 size; ++ ++ /* Info record required by gcvHAL_UNMAP_USER_MEMORY. Just a name. */ ++ OUT gctUINT32 info; ++ ++ /* Physical address of mapped memory. */ ++ OUT gctUINT32 address; ++ } ++ MapUserMemory; ++ ++ /* gcvHAL_UNMAP_USER_MEMORY */ ++ struct _gcsHAL_UNMAP_USER_MEMORY ++ { ++ /* Base address of user memory to unmap. */ ++ IN gctUINT64 memory; ++ ++ /* Size of user memory in bytes to unmap. */ ++ IN gctUINT64 size; ++ ++ /* Info record returned by gcvHAL_MAP_USER_MEMORY. Just a name. */ ++ IN gctUINT32 info; ++ ++ /* Physical address of mapped memory as returned by ++ gcvHAL_MAP_USER_MEMORY. */ ++ IN gctUINT32 address; ++ } ++ UnmapUserMemory; ++ /* gcsHAL_USER_SIGNAL */ ++ struct _gcsHAL_USER_SIGNAL ++ { ++ /* Command. */ ++ gceUSER_SIGNAL_COMMAND_CODES command; ++ ++ /* Signal ID. */ ++ IN OUT gctINT id; ++ ++ /* Reset mode. */ ++ IN gctBOOL manualReset; ++ ++ /* Wait timedout. */ ++ IN gctUINT32 wait; ++ ++ /* State. */ ++ IN gctBOOL state; ++ } ++ UserSignal; ++ ++ /* gcvHAL_SIGNAL. */ ++ struct _gcsHAL_SIGNAL ++ { ++ /* Signal handle to signal gctSIGNAL. */ ++ IN gctUINT64 signal; ++ ++ /* Reserved gctSIGNAL. */ ++ IN gctUINT64 auxSignal; ++ ++ /* Process owning the signal gctHANDLE. */ ++ IN gctUINT64 process; ++ /* Event generated from where of pipeline */ ++ IN gceKERNEL_WHERE fromWhere; ++ } ++ Signal; ++ ++ /* gcvHAL_WRITE_DATA. */ ++ struct _gcsHAL_WRITE_DATA ++ { ++ /* Address to write data to. */ ++ IN gctUINT32 address; ++ ++ /* Data to write. */ ++ IN gctUINT32 data; ++ } ++ WriteData; ++ ++ /* gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY */ ++ struct _gcsHAL_ALLOCATE_CONTIGUOUS_MEMORY ++ { ++ /* Number of bytes to allocate. */ ++ IN OUT gctUINT64 bytes; ++ ++ /* Hardware address of allocation. */ ++ OUT gctUINT32 address; ++ ++ /* Physical address of allocation. Just a name. */ ++ OUT gctUINT32 physical; ++ ++ /* Logical address of allocation. */ ++ OUT gctUINT64 logical; ++ } ++ AllocateContiguousMemory; ++ ++ /* gcvHAL_FREE_CONTIGUOUS_MEMORY */ ++ struct _gcsHAL_FREE_CONTIGUOUS_MEMORY ++ { ++ /* Number of bytes allocated. */ ++ IN gctUINT64 bytes; ++ ++ /* Physical address of allocation. Just a name. */ ++ IN gctUINT32 physical; ++ ++ /* Logical address of allocation. */ ++ IN gctUINT64 logical; ++ } ++ FreeContiguousMemory; ++ ++ /* gcvHAL_READ_REGISTER */ ++ struct _gcsHAL_READ_REGISTER ++ { ++ /* Logical address of memory to write data to. */ ++ IN gctUINT32 address; ++ ++ /* Data read. */ ++ OUT gctUINT32 data; ++ } ++ ReadRegisterData; ++ ++ /* gcvHAL_WRITE_REGISTER */ ++ struct _gcsHAL_WRITE_REGISTER ++ { ++ /* Logical address of memory to write data to. */ ++ IN gctUINT32 address; ++ ++ /* Data read. */ ++ IN gctUINT32 data; ++ } ++ WriteRegisterData; ++ ++#if VIVANTE_PROFILER ++ /* gcvHAL_GET_PROFILE_SETTING */ ++ struct _gcsHAL_GET_PROFILE_SETTING ++ { ++ /* Enable profiling */ ++ OUT gctBOOL enable; ++ } ++ GetProfileSetting; ++ ++ /* gcvHAL_SET_PROFILE_SETTING */ ++ struct _gcsHAL_SET_PROFILE_SETTING ++ { ++ /* Enable profiling */ ++ IN gctBOOL enable; ++ } ++ SetProfileSetting; ++ ++#if VIVANTE_PROFILER_PERDRAW ++ /* gcvHAL_READ_PROFILER_REGISTER_SETTING */ ++ struct _gcsHAL_READ_PROFILER_REGISTER_SETTING ++ { ++ /*Should Clear Register*/ ++ IN gctBOOL bclear; ++ } ++ SetProfilerRegisterClear; ++#endif ++ ++ /* gcvHAL_READ_ALL_PROFILE_REGISTERS */ ++ struct _gcsHAL_READ_ALL_PROFILE_REGISTERS ++ { ++#if VIVANTE_PROFILER_CONTEXT ++ /* Context buffer object gckCONTEXT. Just a name. */ ++ IN gctUINT32 context; ++#endif ++ ++ /* Data read. */ ++ OUT gcsPROFILER_COUNTERS counters; ++ } ++ RegisterProfileData; ++ ++ /* gcvHAL_PROFILE_REGISTERS_2D */ ++ struct _gcsHAL_PROFILE_REGISTERS_2D ++ { ++ /* Data read in gcs2D_PROFILE. */ ++ OUT gctUINT64 hwProfile2D; ++ } ++ RegisterProfileData2D; ++#endif ++ ++ /* Power management. */ ++ /* gcvHAL_SET_POWER_MANAGEMENT_STATE */ ++ struct _gcsHAL_SET_POWER_MANAGEMENT ++ { ++ /* Data read. */ ++ IN gceCHIPPOWERSTATE state; ++ } ++ SetPowerManagement; ++ ++ /* gcvHAL_QUERY_POWER_MANAGEMENT_STATE */ ++ struct _gcsHAL_QUERY_POWER_MANAGEMENT ++ { ++ /* Data read. */ ++ OUT gceCHIPPOWERSTATE state; ++ ++ /* Idle query. */ ++ OUT gctBOOL isIdle; ++ } ++ QueryPowerManagement; ++ ++ /* gcvHAL_QUERY_KERNEL_SETTINGS */ ++ struct _gcsHAL_QUERY_KERNEL_SETTINGS ++ { ++ /* Settings.*/ ++ OUT gcsKERNEL_SETTINGS settings; ++ } ++ QueryKernelSettings; ++ ++ /* gcvHAL_MAP_PHYSICAL */ ++ struct _gcsHAL_MAP_PHYSICAL ++ { ++ /* gcvTRUE to map, gcvFALSE to unmap. */ ++ IN gctBOOL map; ++ ++ /* Physical address. */ ++ IN OUT gctUINT64 physical; ++ } ++ MapPhysical; ++ ++ /* gcvHAL_DEBUG */ ++ struct _gcsHAL_DEBUG ++ { ++ /* If gcvTRUE, set the debug information. */ ++ IN gctBOOL set; ++ IN gctUINT32 level; ++ IN gctUINT32 zones; ++ IN gctBOOL enable; ++ ++ IN gceDEBUG_MESSAGE_TYPE type; ++ IN gctUINT32 messageSize; ++ ++ /* Message to print if not empty. */ ++ IN gctCHAR message[80]; ++ } ++ Debug; ++ ++ /* gcvHAL_CACHE */ ++ struct _gcsHAL_CACHE ++ { ++ IN gceCACHEOPERATION operation; ++ IN gctUINT64 process; ++ IN gctUINT64 logical; ++ IN gctUINT64 bytes; ++ IN gctUINT32 node; ++ } ++ Cache; ++ ++ /* gcvHAL_TIMESTAMP */ ++ struct _gcsHAL_TIMESTAMP ++ { ++ /* Timer select. */ ++ IN gctUINT32 timer; ++ ++ /* Timer request type (0-stop, 1-start, 2-send delta). */ ++ IN gctUINT32 request; ++ ++ /* Result of delta time in microseconds. */ ++ OUT gctINT32 timeDelta; ++ } ++ TimeStamp; ++ ++ /* gcvHAL_DATABASE */ ++ struct _gcsHAL_DATABASE ++ { ++ /* Set to gcvTRUE if you want to query a particular process ID. ++ ** Set to gcvFALSE to query the last detached process. */ ++ IN gctBOOL validProcessID; ++ ++ /* Process ID to query. */ ++ IN gctUINT32 processID; ++ ++ /* Information. */ ++ OUT gcuDATABASE_INFO vidMem; ++ OUT gcuDATABASE_INFO nonPaged; ++ OUT gcuDATABASE_INFO contiguous; ++ OUT gcuDATABASE_INFO gpuIdle; ++ ++ /* Detail information about video memory. */ ++ OUT gcuDATABASE_INFO vidMemPool[3]; ++ } ++ Database; ++ ++ /* gcvHAL_VERSION */ ++ struct _gcsHAL_VERSION ++ { ++ /* Major version: N.n.n. */ ++ OUT gctINT32 major; ++ ++ /* Minor version: n.N.n. */ ++ OUT gctINT32 minor; ++ ++ /* Patch version: n.n.N. */ ++ OUT gctINT32 patch; ++ ++ /* Build version. */ ++ OUT gctUINT32 build; ++ } ++ Version; ++ ++ /* gcvHAL_CHIP_INFO */ ++ struct _gcsHAL_CHIP_INFO ++ { ++ /* Chip count. */ ++ OUT gctINT32 count; ++ ++ /* Chip types. */ ++ OUT gceHARDWARE_TYPE types[gcdCHIP_COUNT]; ++ } ++ ChipInfo; ++ ++ /* gcvHAL_ATTACH */ ++ struct _gcsHAL_ATTACH ++ { ++ /* Handle of context buffer object. */ ++ OUT gctUINT32 context; ++ ++ /* Number of states in the buffer. */ ++ OUT gctUINT64 stateCount; ++ ++ /* Map context buffer to user or not. */ ++ IN gctBOOL map; ++ ++ /* Physical of context buffer. */ ++ OUT gctUINT32 physicals[2]; ++ ++ /* Physical of context buffer. */ ++ OUT gctUINT64 logicals[2]; ++ ++ /* Bytes of context buffer. */ ++ OUT gctUINT32 bytes; ++ } ++ Attach; ++ ++ /* gcvHAL_DETACH */ ++ struct _gcsHAL_DETACH ++ { ++ /* Context buffer object gckCONTEXT. Just a name. */ ++ IN gctUINT32 context; ++ } ++ Detach; ++ ++ /* gcvHAL_COMPOSE. */ ++ gcsHAL_COMPOSE Compose; ++ ++ /* gcvHAL_GET_FRAME_INFO. */ ++ struct _gcsHAL_GET_FRAME_INFO ++ { ++ /* gcsHAL_FRAME_INFO* */ ++ OUT gctUINT64 frameInfo; ++ } ++ GetFrameInfo; ++ ++ /* gcvHAL_SET_TIME_OUT. */ ++ struct _gcsHAL_SET_TIMEOUT ++ { ++ gctUINT32 timeOut; ++ } ++ SetTimeOut; ++ ++#if gcdENABLE_VG ++ /* gcvHAL_COMMIT */ ++ struct _gcsHAL_VGCOMMIT ++ { ++ /* Context buffer. gcsVGCONTEXT_PTR */ ++ IN gctUINT64 context; ++ ++ /* Command queue. gcsVGCMDQUEUE_PTR */ ++ IN gctUINT64 queue; ++ ++ /* Number of entries in the queue. */ ++ IN gctUINT entryCount; ++ ++ /* Task table. gcsTASK_MASTER_TABLE_PTR */ ++ IN gctUINT64 taskTable; ++ } ++ VGCommit; ++ ++ /* gcvHAL_QUERY_COMMAND_BUFFER */ ++ struct _gcsHAL_QUERY_COMMAND_BUFFER ++ { ++ /* Command buffer attributes. */ ++ OUT gcsCOMMAND_BUFFER_INFO information; ++ } ++ QueryCommandBuffer; ++ ++#endif ++ ++ struct _gcsHAL_SET_FSCALE_VALUE ++ { ++ IN gctUINT value; ++ } ++ SetFscaleValue; ++ ++ struct _gcsHAL_GET_FSCALE_VALUE ++ { ++ OUT gctUINT value; ++ OUT gctUINT minValue; ++ OUT gctUINT maxValue; ++ } ++ GetFscaleValue; ++ ++ struct _gcsHAL_NAME_VIDEO_MEMORY ++ { ++ IN gctUINT32 handle; ++ OUT gctUINT32 name; ++ } ++ NameVideoMemory; ++ ++ struct _gcsHAL_IMPORT_VIDEO_MEMORY ++ { ++ IN gctUINT32 name; ++ OUT gctUINT32 handle; ++ } ++ ImportVideoMemory; ++ ++ struct _gcsHAL_QUERY_RESET_TIME_STAMP ++ { ++ OUT gctUINT64 timeStamp; ++ } ++ QueryResetTimeStamp; ++ ++ struct _gcsHAL_SYNC_POINT ++ { ++ /* Command. */ ++ gceSYNC_POINT_COMMAND_CODES command; ++ ++ /* Sync point. */ ++ IN OUT gctUINT64 syncPoint; ++ ++ /* From where. */ ++ IN gceKERNEL_WHERE fromWhere; ++ ++ /* Signaled state. */ ++ OUT gctBOOL state; ++ } ++ SyncPoint; ++ ++ struct _gcsHAL_CREATE_NATIVE_FENCE ++ { ++ /* Signal id to dup. */ ++ IN gctUINT64 syncPoint; ++ ++ /* Native fence file descriptor. */ ++ OUT gctINT fenceFD; ++ ++ } ++ CreateNativeFence; ++ ++ struct _gcsHAL_DESTROY_MMU ++ { ++ /* Mmu object. */ ++ IN gctUINT64 mmu; ++ } ++ DestroyMmu; ++ ++ struct _gcsHAL_SHBUF ++ { ++ gceSHBUF_COMMAND_CODES command; ++ ++ /* Shared buffer. */ ++ IN OUT gctUINT64 id; ++ ++ /* User data to be shared. */ ++ IN gctUINT64 data; ++ ++ /* Data size. */ ++ IN OUT gctUINT32 bytes; ++ } ++ ShBuf; ++ ++ struct _gcsHAL_CONFIG_POWER_MANAGEMENT ++ { ++ IN gctBOOL enable; ++ } ++ ConfigPowerManagement; ++ ++ struct _gcsHAL_GET_VIDEO_MEMORY_FD ++ { ++ IN gctUINT32 handle; ++ OUT gctINT fd; ++ } ++ GetVideoMemoryFd; ++ } ++ u; ++} ++gcsHAL_INTERFACE; ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_driver_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_driver_vg.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_driver_vg.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_driver_vg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_driver_vg.h 2016-06-19 22:11:55.153149980 +0200 +@@ -0,0 +1,265 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_driver_vg_h_ ++#define __gc_hal_driver_vg_h_ ++ ++ ++ ++#include "gc_hal_types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++******************************* I/O Control Codes ****************************** ++\******************************************************************************/ ++ ++#define gcvHAL_CLASS "galcore" ++#define IOCTL_GCHAL_INTERFACE 30000 ++ ++/******************************************************************************\ ++********************************* Command Codes ******************************** ++\******************************************************************************/ ++ ++/******************************************************************************\ ++********************* Command buffer information structure. ******************** ++\******************************************************************************/ ++ ++typedef struct _gcsCOMMAND_BUFFER_INFO * gcsCOMMAND_BUFFER_INFO_PTR; ++typedef struct _gcsCOMMAND_BUFFER_INFO ++{ ++ /* FE command buffer interrupt ID. */ ++ gctINT32 feBufferInt; ++ ++ /* TS overflow interrupt ID. */ ++ gctINT32 tsOverflowInt; ++ ++ /* Alignment and mask for the buffer address. */ ++ gctUINT addressMask; ++ gctUINT32 addressAlignment; ++ ++ /* Alignment for each command. */ ++ gctUINT32 commandAlignment; ++ ++ /* Number of bytes required by the STATE command. */ ++ gctUINT32 stateCommandSize; ++ ++ /* Number of bytes required by the RESTART command. */ ++ gctUINT32 restartCommandSize; ++ ++ /* Number of bytes required by the FETCH command. */ ++ gctUINT32 fetchCommandSize; ++ ++ /* Number of bytes required by the CALL command. */ ++ gctUINT32 callCommandSize; ++ ++ /* Number of bytes required by the RETURN command. */ ++ gctUINT32 returnCommandSize; ++ ++ /* Number of bytes required by the EVENT command. */ ++ gctUINT32 eventCommandSize; ++ ++ /* Number of bytes required by the END command. */ ++ gctUINT32 endCommandSize; ++ ++ /* Number of bytes reserved at the tail of a static command buffer. */ ++ gctUINT32 staticTailSize; ++ ++ /* Number of bytes reserved at the tail of a dynamic command buffer. */ ++ gctUINT32 dynamicTailSize; ++} ++gcsCOMMAND_BUFFER_INFO; ++ ++/******************************************************************************\ ++******************************** Task Structures ******************************* ++\******************************************************************************/ ++ ++typedef enum _gceTASK ++{ ++ gcvTASK_LINK, ++ gcvTASK_CLUSTER, ++ gcvTASK_INCREMENT, ++ gcvTASK_DECREMENT, ++ gcvTASK_SIGNAL, ++ gcvTASK_LOCKDOWN, ++ gcvTASK_UNLOCK_VIDEO_MEMORY, ++ gcvTASK_FREE_VIDEO_MEMORY, ++ gcvTASK_FREE_CONTIGUOUS_MEMORY, ++ gcvTASK_UNMAP_USER_MEMORY ++} ++gceTASK; ++ ++typedef struct _gcsTASK_HEADER * gcsTASK_HEADER_PTR; ++typedef struct _gcsTASK_HEADER ++{ ++ /* Task ID. */ ++ IN gceTASK id; ++} ++gcsTASK_HEADER; ++ ++typedef struct _gcsTASK_LINK * gcsTASK_LINK_PTR; ++typedef struct _gcsTASK_LINK ++{ ++ /* Task ID (gcvTASK_LINK). */ ++ IN gceTASK id; ++ ++ /* Pointer to the next task container. */ ++ IN gctPOINTER cotainer; ++ ++ /* Pointer to the next task from the next task container. */ ++ IN gcsTASK_HEADER_PTR task; ++} ++gcsTASK_LINK; ++ ++typedef struct _gcsTASK_CLUSTER * gcsTASK_CLUSTER_PTR; ++typedef struct _gcsTASK_CLUSTER ++{ ++ /* Task ID (gcvTASK_CLUSTER). */ ++ IN gceTASK id; ++ ++ /* Number of tasks in the cluster. */ ++ IN gctUINT taskCount; ++} ++gcsTASK_CLUSTER; ++ ++typedef struct _gcsTASK_INCREMENT * gcsTASK_INCREMENT_PTR; ++typedef struct _gcsTASK_INCREMENT ++{ ++ /* Task ID (gcvTASK_INCREMENT). */ ++ IN gceTASK id; ++ ++ /* Address of the variable to increment. */ ++ IN gctUINT32 address; ++} ++gcsTASK_INCREMENT; ++ ++typedef struct _gcsTASK_DECREMENT * gcsTASK_DECREMENT_PTR; ++typedef struct _gcsTASK_DECREMENT ++{ ++ /* Task ID (gcvTASK_DECREMENT). */ ++ IN gceTASK id; ++ ++ /* Address of the variable to decrement. */ ++ IN gctUINT32 address; ++} ++gcsTASK_DECREMENT; ++ ++typedef struct _gcsTASK_SIGNAL * gcsTASK_SIGNAL_PTR; ++typedef struct _gcsTASK_SIGNAL ++{ ++ /* Task ID (gcvTASK_SIGNAL). */ ++ IN gceTASK id; ++ ++ /* Process owning the signal. */ ++ IN gctHANDLE process; ++ ++ /* Signal handle to signal. */ ++ IN gctSIGNAL signal; ++} ++gcsTASK_SIGNAL; ++ ++typedef struct _gcsTASK_LOCKDOWN * gcsTASK_LOCKDOWN_PTR; ++typedef struct _gcsTASK_LOCKDOWN ++{ ++ /* Task ID (gcvTASK_LOCKDOWN). */ ++ IN gceTASK id; ++ ++ /* Address of the user space counter. */ ++ IN gctUINT32 userCounter; ++ ++ /* Address of the kernel space counter. */ ++ IN gctUINT32 kernelCounter; ++ ++ /* Process owning the signal. */ ++ IN gctHANDLE process; ++ ++ /* Signal handle to signal. */ ++ IN gctSIGNAL signal; ++} ++gcsTASK_LOCKDOWN; ++ ++typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY * gcsTASK_UNLOCK_VIDEO_MEMORY_PTR; ++typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY ++{ ++ /* Task ID (gcvTASK_UNLOCK_VIDEO_MEMORY). */ ++ IN gceTASK id; ++ ++ /* Allocated video memory. */ ++ IN gctUINT64 node; ++} ++gcsTASK_UNLOCK_VIDEO_MEMORY; ++ ++typedef struct _gcsTASK_FREE_VIDEO_MEMORY * gcsTASK_FREE_VIDEO_MEMORY_PTR; ++typedef struct _gcsTASK_FREE_VIDEO_MEMORY ++{ ++ /* Task ID (gcvTASK_FREE_VIDEO_MEMORY). */ ++ IN gceTASK id; ++ ++ /* Allocated video memory. */ ++ IN gctUINT32 node; ++} ++gcsTASK_FREE_VIDEO_MEMORY; ++ ++typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY * gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR; ++typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY ++{ ++ /* Task ID (gcvTASK_FREE_CONTIGUOUS_MEMORY). */ ++ IN gceTASK id; ++ ++ /* Number of bytes allocated. */ ++ IN gctSIZE_T bytes; ++ ++ /* Physical address of allocation. */ ++ IN gctPHYS_ADDR physical; ++ ++ /* Logical address of allocation. */ ++ IN gctPOINTER logical; ++} ++gcsTASK_FREE_CONTIGUOUS_MEMORY; ++ ++typedef struct _gcsTASK_UNMAP_USER_MEMORY * gcsTASK_UNMAP_USER_MEMORY_PTR; ++typedef struct _gcsTASK_UNMAP_USER_MEMORY ++{ ++ /* Task ID (gcvTASK_UNMAP_USER_MEMORY). */ ++ IN gceTASK id; ++ ++ /* Base address of user memory to unmap. */ ++ IN gctPOINTER memory; ++ ++ /* Size of user memory in bytes to unmap. */ ++ IN gctSIZE_T size; ++ ++ /* Info record returned by gcvHAL_MAP_USER_MEMORY. */ ++ IN gctPOINTER info; ++ ++ /* Physical address of mapped memory as returned by ++ gcvHAL_MAP_USER_MEMORY. */ ++ IN gctUINT32 address; ++} ++gcsTASK_UNMAP_USER_MEMORY; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_driver_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_dump.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_dump.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_dump.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_dump.h 2016-06-19 22:11:55.153149980 +0200 +@@ -0,0 +1,89 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_dump_h_ ++#define __gc_hal_dump_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++** FILE LAYOUT: ++** ++** gcsDUMP_FILE structure ++** ++** gcsDUMP_DATA frame ++** gcsDUMP_DATA or gcDUMP_DATA_SIZE records rendingring the frame ++** gctUINT8 data[length] ++*/ ++ ++#define gcvDUMP_FILE_SIGNATURE gcmCC('g','c','D','B') ++ ++typedef struct _gcsDUMP_FILE ++{ ++ gctUINT32 signature; /* File signature */ ++ gctSIZE_T length; /* Length of file */ ++ gctUINT32 frames; /* Number of frames in file */ ++} ++gcsDUMP_FILE; ++ ++typedef enum _gceDUMP_TAG ++{ ++ gcvTAG_SURFACE = gcmCC('s','u','r','f'), ++ gcvTAG_FRAME = gcmCC('f','r','m',' '), ++ gcvTAG_COMMAND = gcmCC('c','m','d',' '), ++ gcvTAG_INDEX = gcmCC('i','n','d','x'), ++ gcvTAG_STREAM = gcmCC('s','t','r','m'), ++ gcvTAG_TEXTURE = gcmCC('t','e','x','t'), ++ gcvTAG_RENDER_TARGET = gcmCC('r','n','d','r'), ++ gcvTAG_DEPTH = gcmCC('z','b','u','f'), ++ gcvTAG_RESOLVE = gcmCC('r','s','l','v'), ++ gcvTAG_DELETE = gcmCC('d','e','l',' '), ++ gcvTAG_BUFOBJ = gcmCC('b','u','f','o'), ++} ++gceDUMP_TAG; ++ ++typedef struct _gcsDUMP_SURFACE ++{ ++ gceDUMP_TAG type; /* Type of record. */ ++ gctUINT32 address; /* Address of the surface. */ ++ gctINT16 width; /* Width of surface. */ ++ gctINT16 height; /* Height of surface. */ ++ gceSURF_FORMAT format; /* Surface pixel format. */ ++ gctSIZE_T length; /* Number of bytes inside the surface. */ ++} ++gcsDUMP_SURFACE; ++ ++typedef struct _gcsDUMP_DATA ++{ ++ gceDUMP_TAG type; /* Type of record. */ ++ gctSIZE_T length; /* Number of bytes of data. */ ++ gctUINT32 address; /* Address for the data. */ ++} ++gcsDUMP_DATA; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_dump_h_ */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_eglplatform.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_eglplatform.h 2016-06-19 22:11:55.153149980 +0200 +@@ -0,0 +1,651 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_eglplatform_h_ ++#define __gc_hal_eglplatform_h_ ++ ++/* Include VDK types. */ ++#include "gc_hal_types.h" ++#include "gc_hal_base.h" ++#include "gc_hal_eglplatform_type.h" ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#if defined(LINUX) && defined(EGL_API_DFB) ++#include ++typedef struct _DFBDisplay * HALNativeDisplayType; ++typedef struct _DFBWindow * HALNativeWindowType; ++typedef struct _DFBPixmap * HALNativePixmapType; ++ ++#elif defined(LINUX) && defined(EGL_API_FB) ++ ++#if defined(EGL_API_WL) ++ ++#if defined(__GNUC__) ++# define inline __inline__ /* GNU keyword. */ ++#endif ++ ++/* Wayland platform. */ ++#include ++ ++#define WL_EGL_NUM_BACKBUFFERS 3 ++ ++typedef struct _gcsWL_VIV_BUFFER ++{ ++ struct wl_resource *wl_buffer; ++ gcoSURF surface; ++ gctINT32 width, height; ++} gcsWL_VIV_BUFFER; ++ ++typedef struct _gcsWL_EGL_DISPLAY ++{ ++ struct wl_display* wl_display; ++ struct wl_viv* wl_viv; ++ struct wl_registry *registry; ++ struct wl_event_queue *wl_queue; ++ gctINT swapInterval; ++} gcsWL_EGL_DISPLAY; ++ ++typedef struct _gcsWL_EGL_BUFFER_INFO ++{ ++ gctINT32 width; ++ gctINT32 height; ++ gctINT32 stride; ++ gceSURF_FORMAT format; ++ gcuVIDMEM_NODE_PTR node; ++ gcePOOL pool; ++ gctUINT bytes; ++ gcoSURF surface; ++ gcoSURF attached_surface; ++ gctINT32 invalidate; ++ gctBOOL locked; ++} gcsWL_EGL_BUFFER_INFO; ++ ++typedef struct _gcsWL_EGL_BUFFER ++{ ++ struct wl_buffer* wl_buffer; ++ gcsWL_EGL_BUFFER_INFO info; ++} gcsWL_EGL_BUFFER; ++ ++typedef struct _gcsWL_EGL_WINDOW_INFO ++{ ++ gctINT32 dx; ++ gctINT32 dy; ++ gctUINT width; ++ gctUINT height; ++ gctINT32 attached_width; ++ gctINT32 attached_height; ++ gceSURF_FORMAT format; ++ gctUINT bpp; ++} gcsWL_EGL_WINDOW_INFO; ++ ++struct wl_egl_window ++{ ++ gcsWL_EGL_DISPLAY* display; ++ gcsWL_EGL_BUFFER backbuffers[WL_EGL_NUM_BACKBUFFERS]; ++ gcsWL_EGL_WINDOW_INFO info; ++ gctUINT current; ++ struct wl_surface* surface; ++ struct wl_callback* frame_callback; ++}; ++ ++typedef void* HALNativeDisplayType; ++typedef void* HALNativeWindowType; ++typedef void* HALNativePixmapType; ++#else ++/* Linux platform for FBDEV. */ ++typedef struct _FBDisplay * HALNativeDisplayType; ++typedef struct _FBWindow * HALNativeWindowType; ++typedef struct _FBPixmap * HALNativePixmapType; ++#endif ++#elif defined(__ANDROID__) || defined(ANDROID) ++ ++struct egl_native_pixmap_t; ++ ++#if ANDROID_SDK_VERSION >= 9 ++ #include ++ ++ typedef struct ANativeWindow* HALNativeWindowType; ++ typedef struct egl_native_pixmap_t* HALNativePixmapType; ++ typedef void* HALNativeDisplayType; ++#else ++ struct android_native_window_t; ++ typedef struct android_native_window_t* HALNativeWindowType; ++ typedef struct egl_native_pixmap_t * HALNativePixmapType; ++ typedef void* HALNativeDisplayType; ++#endif ++ ++#elif defined(LINUX) ++/* X11 platform. */ ++#include ++#include ++ ++typedef Display * HALNativeDisplayType; ++typedef Window HALNativeWindowType; ++ ++#ifdef CUSTOM_PIXMAP ++typedef void * HALNativePixmapType; ++#else ++typedef Pixmap HALNativePixmapType; ++#endif /* CUSTOM_PIXMAP */ ++ ++/* Rename some badly named X defines. */ ++#ifdef Status ++# define XStatus int ++# undef Status ++#endif ++#ifdef Always ++# define XAlways 2 ++# undef Always ++#endif ++#ifdef CurrentTime ++# undef CurrentTime ++# define XCurrentTime 0 ++#endif ++ ++#else ++ ++#error "Platform not recognized" ++ ++/* VOID */ ++typedef void * HALNativeDisplayType; ++typedef void * HALNativeWindowType; ++typedef void * HALNativePixmapType; ++ ++#endif ++ ++/* define DUMMY according to the system */ ++#if defined(EGL_API_WL) ++# define WL_DUMMY (31415926) ++# define EGL_DUMMY WL_DUMMY ++#elif defined(__ANDROID__) || defined(ANDROID) ++# define ANDROID_DUMMY (31415926) ++# define EGL_DUMMY ANDROID_DUMMY ++#else ++# define EGL_DUMMY (31415926) ++#endif ++ ++/******************************************************************************* ++** Display. ******************************************************************** ++*/ ++ ++gceSTATUS ++gcoOS_GetDisplay( ++ OUT HALNativeDisplayType * Display, ++ IN gctPOINTER Context ++ ); ++ ++gceSTATUS ++gcoOS_GetDisplayByIndex( ++ IN gctINT DisplayIndex, ++ OUT HALNativeDisplayType * Display, ++ IN gctPOINTER Context ++ ); ++ ++gceSTATUS ++gcoOS_GetDisplayInfo( ++ IN HALNativeDisplayType Display, ++ OUT gctINT * Width, ++ OUT gctINT * Height, ++ OUT gctSIZE_T * Physical, ++ OUT gctINT * Stride, ++ OUT gctINT * BitsPerPixel ++ ); ++ ++ ++ ++gceSTATUS ++gcoOS_GetDisplayInfoEx( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctUINT DisplayInfoSize, ++ OUT halDISPLAY_INFO * DisplayInfo ++ ); ++ ++gceSTATUS ++gcoOS_GetNextDisplayInfoExByIndex( ++ IN gctINT Index, ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctUINT DisplayInfoSize, ++ OUT halDISPLAY_INFO * DisplayInfo ++ ); ++ ++gceSTATUS ++gcoOS_GetDisplayVirtual( ++ IN HALNativeDisplayType Display, ++ OUT gctINT * Width, ++ OUT gctINT * Height ++ ); ++ ++gceSTATUS ++gcoOS_GetDisplayBackbuffer( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ OUT gctPOINTER * context, ++ OUT gcoSURF * surface, ++ OUT gctUINT * Offset, ++ OUT gctINT * X, ++ OUT gctINT * Y ++ ); ++ ++gceSTATUS ++gcoOS_SetDisplayVirtual( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctUINT Offset, ++ IN gctINT X, ++ IN gctINT Y ++ ); ++ ++gceSTATUS ++gcoOS_SetDisplayVirtualEx( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctPOINTER Context, ++ IN gcoSURF Surface, ++ IN gctUINT Offset, ++ IN gctINT X, ++ IN gctINT Y ++ ); ++ ++gceSTATUS ++gcoOS_SetSwapInterval( ++ IN HALNativeDisplayType Display, ++ IN gctINT Interval ++); ++ ++gceSTATUS ++gcoOS_SetSwapIntervalEx( ++ IN HALNativeDisplayType Display, ++ IN gctINT Interval, ++ IN gctPOINTER localDisplay); ++ ++gceSTATUS ++gcoOS_GetSwapInterval( ++ IN HALNativeDisplayType Display, ++ IN gctINT_PTR Min, ++ IN gctINT_PTR Max ++); ++ ++gceSTATUS ++gcoOS_DisplayBufferRegions( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctINT NumRects, ++ IN gctINT_PTR Rects ++ ); ++ ++gceSTATUS ++gcoOS_DestroyDisplay( ++ IN HALNativeDisplayType Display ++ ); ++ ++gceSTATUS ++gcoOS_InitLocalDisplayInfo( ++ IN HALNativeDisplayType Display, ++ IN OUT gctPOINTER * localDisplay ++ ); ++ ++gceSTATUS ++gcoOS_DeinitLocalDisplayInfo( ++ IN HALNativeDisplayType Display, ++ IN OUT gctPOINTER * localDisplay ++ ); ++ ++gceSTATUS ++gcoOS_GetDisplayInfoEx2( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctPOINTER localDisplay, ++ IN gctUINT DisplayInfoSize, ++ OUT halDISPLAY_INFO * DisplayInfo ++ ); ++ ++gceSTATUS ++gcoOS_GetDisplayBackbufferEx( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctPOINTER localDisplay, ++ OUT gctPOINTER * context, ++ OUT gcoSURF * surface, ++ OUT gctUINT * Offset, ++ OUT gctINT * X, ++ OUT gctINT * Y ++ ); ++ ++gceSTATUS ++gcoOS_IsValidDisplay( ++ IN HALNativeDisplayType Display ++ ); ++ ++gceSTATUS ++gcoOS_GetNativeVisualId( ++ IN HALNativeDisplayType Display, ++ OUT gctINT* nativeVisualId ++ ); ++ ++gctBOOL ++gcoOS_SynchronousFlip( ++ IN HALNativeDisplayType Display ++ ); ++ ++/******************************************************************************* ++** Windows. ******************************************************************** ++*/ ++ ++gceSTATUS ++gcoOS_CreateWindow( ++ IN HALNativeDisplayType Display, ++ IN gctINT X, ++ IN gctINT Y, ++ IN gctINT Width, ++ IN gctINT Height, ++ OUT HALNativeWindowType * Window ++ ); ++ ++gceSTATUS ++gcoOS_GetWindowInfo( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ OUT gctINT * X, ++ OUT gctINT * Y, ++ OUT gctINT * Width, ++ OUT gctINT * Height, ++ OUT gctINT * BitsPerPixel, ++ OUT gctUINT * Offset ++ ); ++ ++gceSTATUS ++gcoOS_DestroyWindow( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window ++ ); ++ ++gceSTATUS ++gcoOS_DrawImage( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctINT Left, ++ IN gctINT Top, ++ IN gctINT Right, ++ IN gctINT Bottom, ++ IN gctINT Width, ++ IN gctINT Height, ++ IN gctINT BitsPerPixel, ++ IN gctPOINTER Bits ++ ); ++ ++gceSTATUS ++gcoOS_GetImage( ++ IN HALNativeWindowType Window, ++ IN gctINT Left, ++ IN gctINT Top, ++ IN gctINT Right, ++ IN gctINT Bottom, ++ OUT gctINT * BitsPerPixel, ++ OUT gctPOINTER * Bits ++ ); ++ ++gceSTATUS ++gcoOS_GetWindowInfoEx( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ OUT gctINT * X, ++ OUT gctINT * Y, ++ OUT gctINT * Width, ++ OUT gctINT * Height, ++ OUT gctINT * BitsPerPixel, ++ OUT gctUINT * Offset, ++ OUT gceSURF_FORMAT * Format ++ ); ++ ++gceSTATUS ++gcoOS_DrawImageEx( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctINT Left, ++ IN gctINT Top, ++ IN gctINT Right, ++ IN gctINT Bottom, ++ IN gctINT Width, ++ IN gctINT Height, ++ IN gctINT BitsPerPixel, ++ IN gctPOINTER Bits, ++ IN gceSURF_FORMAT Format ++ ); ++ ++/******************************************************************************* ++** Pixmaps. ******************************************************************** ++*/ ++ ++gceSTATUS ++gcoOS_CreatePixmap( ++ IN HALNativeDisplayType Display, ++ IN gctINT Width, ++ IN gctINT Height, ++ IN gctINT BitsPerPixel, ++ OUT HALNativePixmapType * Pixmap ++ ); ++ ++gceSTATUS ++gcoOS_GetPixmapInfo( ++ IN HALNativeDisplayType Display, ++ IN HALNativePixmapType Pixmap, ++ OUT gctINT * Width, ++ OUT gctINT * Height, ++ OUT gctINT * BitsPerPixel, ++ OUT gctINT * Stride, ++ OUT gctPOINTER * Bits ++ ); ++ ++gceSTATUS ++gcoOS_DrawPixmap( ++ IN HALNativeDisplayType Display, ++ IN HALNativePixmapType Pixmap, ++ IN gctINT Left, ++ IN gctINT Top, ++ IN gctINT Right, ++ IN gctINT Bottom, ++ IN gctINT Width, ++ IN gctINT Height, ++ IN gctINT BitsPerPixel, ++ IN gctPOINTER Bits ++ ); ++ ++gceSTATUS ++gcoOS_DestroyPixmap( ++ IN HALNativeDisplayType Display, ++ IN HALNativePixmapType Pixmap ++ ); ++ ++gceSTATUS ++gcoOS_GetPixmapInfoEx( ++ IN HALNativeDisplayType Display, ++ IN HALNativePixmapType Pixmap, ++ OUT gctINT * Width, ++ OUT gctINT * Height, ++ OUT gctINT * BitsPerPixel, ++ OUT gctINT * Stride, ++ OUT gctPOINTER * Bits, ++ OUT gceSURF_FORMAT * Format ++ ); ++ ++gceSTATUS ++gcoOS_CopyPixmapBits( ++ IN HALNativeDisplayType Display, ++ IN HALNativePixmapType Pixmap, ++ IN gctUINT DstWidth, ++ IN gctUINT DstHeight, ++ IN gctINT DstStride, ++ IN gceSURF_FORMAT DstFormat, ++ OUT gctPOINTER DstBits ++ ); ++ ++/******************************************************************************* ++** OS relative. **************************************************************** ++*/ ++gceSTATUS ++gcoOS_LoadEGLLibrary( ++ OUT gctHANDLE * Handle ++ ); ++ ++gceSTATUS ++gcoOS_FreeEGLLibrary( ++ IN gctHANDLE Handle ++ ); ++ ++gceSTATUS ++gcoOS_ShowWindow( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window ++ ); ++ ++gceSTATUS ++gcoOS_HideWindow( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window ++ ); ++ ++gceSTATUS ++gcoOS_SetWindowTitle( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ IN gctCONST_STRING Title ++ ); ++ ++gceSTATUS ++gcoOS_CapturePointer( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window ++ ); ++ ++gceSTATUS ++gcoOS_GetEvent( ++ IN HALNativeDisplayType Display, ++ IN HALNativeWindowType Window, ++ OUT halEvent * Event ++ ); ++ ++gceSTATUS ++gcoOS_CreateClientBuffer( ++ IN gctINT Width, ++ IN gctINT Height, ++ IN gctINT Format, ++ IN gctINT Type, ++ OUT gctPOINTER * ClientBuffer ++ ); ++ ++gceSTATUS ++gcoOS_GetClientBufferInfo( ++ IN gctPOINTER ClientBuffer, ++ OUT gctINT * Width, ++ OUT gctINT * Height, ++ OUT gctINT * Stride, ++ OUT gctPOINTER * Bits ++ ); ++ ++gceSTATUS ++gcoOS_DestroyClientBuffer( ++ IN gctPOINTER ClientBuffer ++ ); ++ ++gceSTATUS ++gcoOS_DestroyContext( ++ IN gctPOINTER Display, ++ IN gctPOINTER Context ++ ); ++ ++gceSTATUS ++gcoOS_CreateContext( ++ IN gctPOINTER LocalDisplay, ++ IN gctPOINTER Context ++ ); ++ ++gceSTATUS ++gcoOS_MakeCurrent( ++ IN gctPOINTER LocalDisplay, ++ IN HALNativeWindowType DrawDrawable, ++ IN HALNativeWindowType ReadDrawable, ++ IN gctPOINTER Context, ++ IN gcoSURF ResolveTarget ++ ); ++ ++gceSTATUS ++gcoOS_CreateDrawable( ++ IN gctPOINTER LocalDisplay, ++ IN HALNativeWindowType Drawable ++ ); ++ ++gceSTATUS ++gcoOS_DestroyDrawable( ++ IN gctPOINTER LocalDisplay, ++ IN HALNativeWindowType Drawable ++ ); ++gceSTATUS ++gcoOS_SwapBuffers( ++ IN gctPOINTER LocalDisplay, ++ IN HALNativeWindowType Drawable, ++ IN gcoSURF RenderTarget, ++ IN gcoSURF ResolveTarget, ++ IN gctPOINTER ResolveBits, ++ OUT gctUINT *Width, ++ OUT gctUINT *Height ++ ); ++ ++#ifdef EGL_API_DRI ++gceSTATUS ++gcoOS_ResizeWindow( ++ IN gctPOINTER localDisplay, ++ IN HALNativeWindowType Drawable, ++ IN gctUINT Width, ++ IN gctUINT Height) ++ ; ++ ++#ifdef USE_FREESCALE_EGL_ACCEL ++gceSTATUS ++gcoOS_SwapBuffersGeneric_Async( ++ IN gctPOINTER localDisplay, ++ IN HALNativeWindowType Drawable, ++ IN gcoSURF RenderTarget, ++ IN gcoSURF ResolveTarget, ++ IN gctPOINTER ResolveBits, ++ OUT gctUINT *Width, ++ OUT gctUINT *Height, ++ IN void * resolveRect ++ ); ++ ++gceSTATUS ++gcoOS_DrawSurface( ++ IN gctPOINTER localDisplay, ++ IN HALNativeWindowType Drawable ++ ); ++#endif ++ ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_eglplatform_h_ */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h 2016-06-19 22:11:55.153149980 +0200 +@@ -0,0 +1,280 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_eglplatform_type_h_ ++#define __gc_hal_eglplatform_type_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************* ++** Events. ********************************************************************* ++*/ ++ ++typedef enum _halEventType ++{ ++ /* Keyboard event. */ ++ HAL_KEYBOARD, ++ ++ /* Mouse move event. */ ++ HAL_POINTER, ++ ++ /* Mouse button event. */ ++ HAL_BUTTON, ++ ++ /* Application close event. */ ++ HAL_CLOSE, ++ ++ /* Application window has been updated. */ ++ HAL_WINDOW_UPDATE ++} ++halEventType; ++ ++/* Scancodes for keyboard. */ ++typedef enum _halKeys ++{ ++ HAL_UNKNOWN = -1, ++ ++ HAL_BACKSPACE = 0x08, ++ HAL_TAB, ++ HAL_ENTER = 0x0D, ++ HAL_ESCAPE = 0x1B, ++ ++ HAL_SPACE = 0x20, ++ HAL_SINGLEQUOTE = 0x27, ++ HAL_PAD_ASTERISK = 0x2A, ++ HAL_COMMA = 0x2C, ++ HAL_HYPHEN, ++ HAL_PERIOD, ++ HAL_SLASH, ++ HAL_0, ++ HAL_1, ++ HAL_2, ++ HAL_3, ++ HAL_4, ++ HAL_5, ++ HAL_6, ++ HAL_7, ++ HAL_8, ++ HAL_9, ++ HAL_SEMICOLON = 0x3B, ++ HAL_EQUAL = 0x3D, ++ HAL_A = 0x41, ++ HAL_B, ++ HAL_C, ++ HAL_D, ++ HAL_E, ++ HAL_F, ++ HAL_G, ++ HAL_H, ++ HAL_I, ++ HAL_J, ++ HAL_K, ++ HAL_L, ++ HAL_M, ++ HAL_N, ++ HAL_O, ++ HAL_P, ++ HAL_Q, ++ HAL_R, ++ HAL_S, ++ HAL_T, ++ HAL_U, ++ HAL_V, ++ HAL_W, ++ HAL_X, ++ HAL_Y, ++ HAL_Z, ++ HAL_LBRACKET, ++ HAL_BACKSLASH, ++ HAL_RBRACKET, ++ HAL_BACKQUOTE = 0x60, ++ ++ HAL_F1 = 0x80, ++ HAL_F2, ++ HAL_F3, ++ HAL_F4, ++ HAL_F5, ++ HAL_F6, ++ HAL_F7, ++ HAL_F8, ++ HAL_F9, ++ HAL_F10, ++ HAL_F11, ++ HAL_F12, ++ ++ HAL_LCTRL, ++ HAL_RCTRL, ++ HAL_LSHIFT, ++ HAL_RSHIFT, ++ HAL_LALT, ++ HAL_RALT, ++ HAL_CAPSLOCK, ++ HAL_NUMLOCK, ++ HAL_SCROLLLOCK, ++ HAL_PAD_0, ++ HAL_PAD_1, ++ HAL_PAD_2, ++ HAL_PAD_3, ++ HAL_PAD_4, ++ HAL_PAD_5, ++ HAL_PAD_6, ++ HAL_PAD_7, ++ HAL_PAD_8, ++ HAL_PAD_9, ++ HAL_PAD_HYPHEN, ++ HAL_PAD_PLUS, ++ HAL_PAD_SLASH, ++ HAL_PAD_PERIOD, ++ HAL_PAD_ENTER, ++ HAL_SYSRQ, ++ HAL_PRNTSCRN, ++ HAL_BREAK, ++ HAL_UP, ++ HAL_LEFT, ++ HAL_RIGHT, ++ HAL_DOWN, ++ HAL_HOME, ++ HAL_END, ++ HAL_PGUP, ++ HAL_PGDN, ++ HAL_INSERT, ++ HAL_DELETE, ++ HAL_LWINDOW, ++ HAL_RWINDOW, ++ HAL_MENU, ++ HAL_POWER, ++ HAL_SLEEP, ++ HAL_WAKE ++} ++halKeys; ++ ++/* Structure that defined keyboard mapping. */ ++typedef struct _halKeyMap ++{ ++ /* Normal key. */ ++ halKeys normal; ++ ++ /* Extended key. */ ++ halKeys extended; ++} ++halKeyMap; ++ ++/* Event structure. */ ++typedef struct _halEvent ++{ ++ /* Event type. */ ++ halEventType type; ++ ++ /* Event data union. */ ++ union _halEventData ++ { ++ /* Event data for keyboard. */ ++ struct _halKeyboard ++ { ++ /* Scancode. */ ++ halKeys scancode; ++ ++ /* ASCII characte of the key pressed. */ ++ char key; ++ ++ /* Flag whether the key was pressed (1) or released (0). */ ++ char pressed; ++ } ++ keyboard; ++ ++ /* Event data for pointer. */ ++ struct _halPointer ++ { ++ /* Current pointer coordinate. */ ++ int x; ++ int y; ++ } ++ pointer; ++ ++ /* Event data for mouse buttons. */ ++ struct _halButton ++ { ++ /* Left button state. */ ++ int left; ++ ++ /* Middle button state. */ ++ int middle; ++ ++ /* Right button state. */ ++ int right; ++ ++ /* Current pointer coordinate. */ ++ int x; ++ int y; ++ } ++ button; ++ } ++ data; ++} ++halEvent; ++ ++/* VFK_DISPLAY_INFO structure defining information returned by ++ vdkGetDisplayInfoEx. */ ++typedef struct _halDISPLAY_INFO ++{ ++ /* The size of the display in pixels. */ ++ int width; ++ int height; ++ ++ /* The stride of the dispay. -1 is returned if the stride is not known ++ ** for the specified display.*/ ++ int stride; ++ ++ /* The color depth of the display in bits per pixel. */ ++ int bitsPerPixel; ++ ++ /* The logical pointer to the display memory buffer. NULL is returned ++ ** if the pointer is not known for the specified display. */ ++ void * logical; ++ ++ /* The physical address of the display memory buffer. ~0 is returned ++ ** if the address is not known for the specified display. */ ++ unsigned long physical; ++ ++ int wrapFB; /* true if compositor, false otherwise. */ ++ ++ /* The color info of the display. */ ++ unsigned int alphaLength; ++ unsigned int alphaOffset; ++ unsigned int redLength; ++ unsigned int redOffset; ++ unsigned int greenLength; ++ unsigned int greenOffset; ++ unsigned int blueLength; ++ unsigned int blueOffset; ++ ++ /* Display flip support. */ ++ int flip; ++} ++halDISPLAY_INFO; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_eglplatform_type_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_engine.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_engine.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_engine.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_engine.h 2016-06-19 22:11:55.153149980 +0200 +@@ -0,0 +1,2587 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_engine_h_ ++#define __gc_hal_engine_h_ ++ ++#include "gc_hal_types.h" ++#include "gc_hal_enum.h" ++ ++#if gcdENABLE_3D ++#if gcdENABLE_VG ++#include "gc_hal_engine_vg.h" ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++****************************** Object Declarations ***************************** ++\******************************************************************************/ ++ ++typedef struct _gcoSTREAM * gcoSTREAM; ++typedef struct _gcoVERTEX * gcoVERTEX; ++typedef struct _gcoTEXTURE * gcoTEXTURE; ++typedef struct _gcoINDEX * gcoINDEX; ++typedef struct _gcsVERTEX_ATTRIBUTES * gcsVERTEX_ATTRIBUTES_PTR; ++typedef struct _gcoVERTEXARRAY * gcoVERTEXARRAY; ++typedef struct _gcoBUFOBJ * gcoBUFOBJ; ++ ++#define gcdATTRIBUTE_COUNT 16 ++ ++typedef enum _gcePROGRAM_STAGE ++{ ++ gcvPROGRAM_STAGE_VERTEX = 0x0, ++ gcvPROGRAM_STAGE_TES = 0x1, ++ gcvPROGRAM_STAGE_TCS = 0x2, ++ gcvPROGRAM_STAGE_GEOMETRY = 0x3, ++ gcvPROGRAM_STAGE_FRAGMENT = 0x4, ++ gcvPROGRAM_STAGE_COMPUTE = 0x5, ++ gcvPROGRAM_STAGE_OPENCL = 0x6, ++ gcvPROGRAM_STAGE_LAST ++} ++gcePROGRAM_STAGE; ++ ++typedef enum _gcePROGRAM_STAGE_BIT ++{ ++ gcvPROGRAM_STAGE_VERTEX_BIT = 1 << gcvPROGRAM_STAGE_VERTEX, ++ gcvPROGRAM_STAGE_TES_BIT = 1 << gcvPROGRAM_STAGE_TES, ++ gcvPROGRAM_STAGE_TCS_BIT = 1 << gcvPROGRAM_STAGE_TCS, ++ gcvPROGRAM_STAGE_GEOMETRY_BIT = 1 << gcvPROGRAM_STAGE_GEOMETRY, ++ gcvPROGRAM_STAGE_FRAGMENT_BIT = 1 << gcvPROGRAM_STAGE_FRAGMENT, ++ gcvPROGRAM_STAGE_COMPUTE_BIT = 1 << gcvPROGRAM_STAGE_COMPUTE, ++ gcvPROGRAM_STAGE_OPENCL_BIT = 1 << gcvPROGRAM_STAGE_OPENCL, ++} ++gcePROGRAM_STAGE_BIT; ++ ++ ++/******************************************************************************\ ++********************************* gcoHAL Object ********************************* ++\******************************************************************************/ ++ ++gceSTATUS ++gcoHAL_QueryShaderCaps( ++ IN gcoHAL Hal, ++ OUT gctUINT * VertexUniforms, ++ OUT gctUINT * FragmentUniforms, ++ OUT gctUINT * Varyings ++ ); ++ ++gceSTATUS ++gcoHAL_QueryShaderCapsEx( ++ IN gcoHAL Hal, ++ OUT gctUINT * ShaderCoreCount, ++ OUT gctUINT * ThreadCount, ++ OUT gctUINT * VertexInstructionCount, ++ OUT gctUINT * FragmentInstructionCount ++ ); ++ ++gceSTATUS ++gcoHAL_QuerySamplerBase( ++ IN gcoHAL Hal, ++ OUT gctUINT32 * VertexCount, ++ OUT gctINT_PTR VertexBase, ++ OUT gctUINT32 * FragmentCount, ++ OUT gctINT_PTR FragmentBase ++ ); ++ ++gceSTATUS ++gcoHAL_QueryUniformBase( ++ IN gcoHAL Hal, ++ OUT gctUINT32 * VertexBase, ++ OUT gctUINT32 * FragmentBase ++ ); ++ ++gceSTATUS ++gcoHAL_QueryTextureCaps( ++ IN gcoHAL Hal, ++ OUT gctUINT * MaxWidth, ++ OUT gctUINT * MaxHeight, ++ OUT gctUINT * MaxDepth, ++ OUT gctBOOL * Cubic, ++ OUT gctBOOL * NonPowerOfTwo, ++ OUT gctUINT * VertexSamplers, ++ OUT gctUINT * PixelSamplers ++ ); ++ ++gceSTATUS ++gcoHAL_QueryTextureMaxAniso( ++ IN gcoHAL Hal, ++ OUT gctUINT * MaxAnisoValue ++ ); ++ ++gceSTATUS ++gcoHAL_QueryStreamCaps( ++ IN gcoHAL Hal, ++ OUT gctUINT32 * MaxAttributes, ++ OUT gctUINT32 * MaxStreamSize, ++ OUT gctUINT32 * NumberOfStreams, ++ OUT gctUINT32 * Alignment ++ ); ++ ++/******************************************************************************\ ++********************************* gcoSURF Object ******************************** ++\******************************************************************************/ ++ ++/*----------------------------------------------------------------------------*/ ++/*--------------------------------- gcoSURF 3D --------------------------------*/ ++typedef enum _gceBLIT_FLAG ++{ ++ gcvBLIT_FLAG_SKIP_DEPTH_WRITE = 0x1, ++ gcvBLIT_FLAG_SKIP_STENCIL_WRITE = 0x2, ++} gceBLIT_FLAG; ++ ++typedef struct _gcsSURF_BLIT_ARGS ++{ ++ gcoSURF srcSurface; ++ gctINT srcX, srcY, srcZ; ++ gctINT srcWidth, srcHeight, srcDepth; ++ gcoSURF dstSurface; ++ gctINT dstX, dstY, dstZ; ++ gctINT dstWidth, dstHeight, dstDepth; ++ gctBOOL xReverse; ++ gctBOOL yReverse; ++ gctBOOL scissorTest; ++ gcsRECT scissor; ++ gctUINT flags; ++} ++gcsSURF_BLIT_ARGS; ++ ++ ++ ++ ++/* Clear flags. */ ++typedef enum _gceCLEAR ++{ ++ gcvCLEAR_COLOR = 0x1, ++ gcvCLEAR_DEPTH = 0x2, ++ gcvCLEAR_STENCIL = 0x4, ++ gcvCLEAR_HZ = 0x8, ++ gcvCLEAR_HAS_VAA = 0x10, ++ gcvCLEAR_WITH_GPU_ONLY = 0x100, ++ gcvCLEAR_WITH_CPU_ONLY = 0x200, ++} ++gceCLEAR; ++ ++typedef struct _gcsSURF_CLEAR_ARGS ++{ ++ /* ++ ** Color to fill the color portion of the framebuffer when clear ++ ** is called. ++ */ ++ struct { ++ gcuVALUE r; ++ gcuVALUE g; ++ gcuVALUE b; ++ gcuVALUE a; ++ /* ++ ** Color has multiple value type so we must specify it. ++ */ ++ gceVALUE_TYPE valueType; ++ } color; ++ ++ gcuVALUE depth; ++ ++ gctUINT stencil; ++ ++ ++ ++ /* ++ ** stencil bit-wise mask ++ */ ++ gctUINT8 stencilMask; ++ /* ++ ** Depth Write Mask ++ */ ++ gctBOOL depthMask; ++ /* ++ ** 4-bit channel Mask: ABGR:MSB->LSB ++ */ ++ gctUINT8 colorMask; ++ /* ++ ** If ClearRect is NULL, it means full clear ++ */ ++ gcsRECT_PTR clearRect; ++ /* ++ ** clear flags ++ */ ++ gceCLEAR flags; ++ ++ /* ++ ** Offset in surface to cube/array/3D ++ */ ++ gctUINT32 offset; ++ ++} gcsSURF_CLEAR_ARGS; ++ ++ ++typedef gcsSURF_CLEAR_ARGS* gcsSURF_CLEAR_ARGS_PTR; ++ ++typedef struct _gscSURF_BLITDRAW_BLIT ++{ ++ gcoSURF srcSurface; ++ gcoSURF dstSurface; ++ gcsRECT srcRect; ++ gcsRECT dstRect; ++ gceTEXTURE_FILTER filterMode; ++ gctBOOL xReverse; ++ gctBOOL yReverse; ++ gctBOOL scissorEnabled; ++ gcsRECT scissor; ++}gscSURF_BLITDRAW_BLIT; ++ ++ ++typedef enum _gceBLITDRAW_TYPE ++{ ++ gcvBLITDRAW_CLEAR = 0, ++ gcvBLITDRAW_BLIT = 1, ++ ++ /* last number, not a real type */ ++ gcvBLITDRAW_NUM_TYPE ++ } ++gceBLITDRAW_TYPE; ++ ++ ++typedef struct _gscSURF_BLITDRAW_ARGS ++{ ++ /* always the fist member */ ++ gceHAL_ARG_VERSION version; ++ ++ union _gcsSURF_BLITDRAW_ARGS_UNION ++ { ++ struct _gscSURF_BLITDRAW_ARG_v1 ++ { ++ /* Whether it's clear or blit operation, can be extended. */ ++ gceBLITDRAW_TYPE type; ++ ++ union _gscSURF_BLITDRAW_UNION ++ { ++ gscSURF_BLITDRAW_BLIT blit; ++ ++ struct _gscSURF_BLITDRAW_CLEAR ++ { ++ gcsSURF_CLEAR_ARGS clearArgs; ++ gcoSURF rtSurface; ++ gcoSURF dsSurface; ++ } clear; ++ } u; ++ } v1; ++ } uArgs; ++} ++gcsSURF_BLITDRAW_ARGS; ++ ++ ++typedef struct _gcsSURF_RESOLVE_ARGS ++{ ++ gceHAL_ARG_VERSION version; ++ union _gcsSURF_RESOLVE_ARGS_UNION ++ { ++ struct _gcsSURF_RESOLVE_ARG_v1 ++ { ++ gctBOOL yInverted; ++ }v1; ++ } uArgs; ++} ++gcsSURF_RESOLVE_ARGS; ++ ++ ++/* CPU Blit with format (including linear <-> tile) conversion*/ ++gceSTATUS ++gcoSURF_BlitCPU( ++ gcsSURF_BLIT_ARGS* args ++ ); ++ ++ ++gceSTATUS ++gcoSURF_BlitDraw( ++ IN gcsSURF_BLITDRAW_ARGS *args ++ ); ++#endif /* gcdENABLE_3D */ ++ ++ ++ ++#if gcdENABLE_3D ++/* Clear surface function. */ ++gceSTATUS ++gcoSURF_Clear( ++ IN gcoSURF Surface, ++ IN gcsSURF_CLEAR_ARGS_PTR clearArg ++ ); ++ ++/* Preserve pixels from source. */ ++gceSTATUS ++gcoSURF_Preserve( ++ IN gcoSURF Source, ++ IN gcoSURF Dest, ++ IN gcsRECT_PTR MaskRect ++ ); ++ ++ ++/* TO BE REMOVED */ ++ gceSTATUS ++ depr_gcoSURF_Resolve( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gctUINT32 DestAddress, ++ IN gctPOINTER DestBits, ++ IN gctINT DestStride, ++ IN gceSURF_TYPE DestType, ++ IN gceSURF_FORMAT DestFormat, ++ IN gctUINT DestWidth, ++ IN gctUINT DestHeight ++ ); ++ ++ gceSTATUS ++ depr_gcoSURF_ResolveRect( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gctUINT32 DestAddress, ++ IN gctPOINTER DestBits, ++ IN gctINT DestStride, ++ IN gceSURF_TYPE DestType, ++ IN gceSURF_FORMAT DestFormat, ++ IN gctUINT DestWidth, ++ IN gctUINT DestHeight, ++ IN gcsPOINT_PTR SrcOrigin, ++ IN gcsPOINT_PTR DestOrigin, ++ IN gcsPOINT_PTR RectSize ++ ); ++ ++/* Resample surface. */ ++gceSTATUS ++gcoSURF_Resample( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface ++ ); ++ ++/* Resolve surface. */ ++gceSTATUS ++gcoSURF_Resolve( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface ++ ); ++ ++gceSTATUS ++gcoSURF_ResolveEx( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gcsSURF_RESOLVE_ARGS *args ++ ); ++ ++ ++/* Resolve rectangular area of a surface. */ ++gceSTATUS ++gcoSURF_ResolveRect( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gcsPOINT_PTR SrcOrigin, ++ IN gcsPOINT_PTR DestOrigin, ++ IN gcsPOINT_PTR RectSize ++ ); ++ ++/* Resolve rectangular area of a surface. */ ++gceSTATUS ++gcoSURF_ResolveRectEx( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gcsPOINT_PTR SrcOrigin, ++ IN gcsPOINT_PTR DestOrigin, ++ IN gcsPOINT_PTR RectSize, ++ IN gcsSURF_RESOLVE_ARGS *args ++ ); ++ ++ ++gceSTATUS ++gcoSURF_GetResolveAlignment( ++ IN gcoSURF Surface, ++ OUT gctUINT *originX, ++ OUT gctUINT *originY, ++ OUT gctUINT *sizeX, ++ OUT gctUINT *sizeY ++ ); ++ ++gceSTATUS ++gcoSURF_IsHWResolveable( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gcsPOINT_PTR SrcOrigin, ++ IN gcsPOINT_PTR DestOrigin, ++ IN gcsPOINT_PTR RectSize ++ ); ++ ++/* Set surface resolvability. */ ++gceSTATUS ++gcoSURF_SetResolvability( ++ IN gcoSURF Surface, ++ IN gctBOOL Resolvable ++ ); ++ ++gceSTATUS ++gcoSURF_IsRenderable( ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoSURF_IsFormatRenderableAsRT( ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoSURF_GetFence( ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoBUFOBJ_GetFence( ++ IN gcoBUFOBJ bufObj ++ ); ++ ++gceSTATUS ++gcoBUFOBJ_WaitFence( ++ IN gcoBUFOBJ bufObj ++ ); ++ ++gceSTATUS ++gcoBUFOBJ_IsFenceEnabled( ++ IN gcoBUFOBJ bufObj ++ ); ++ ++gceSTATUS ++gcoSURF_WaitFence( ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoSTREAM_GetFence( ++ IN gcoSTREAM stream ++ ); ++ ++gceSTATUS ++gcoSTREAM_WaitFence( ++ IN gcoSTREAM stream ++ ); ++ ++gceSTATUS ++gcoINDEX_GetFence( ++ IN gcoINDEX index ++ ); ++ ++gceSTATUS ++gcoINDEX_WaitFence( ++ IN gcoINDEX index ++ ); ++ ++gceSTATUS ++gcoSURF_3DBlitClearRect( ++ IN gcoSURF Surface, ++ IN gcsSURF_CLEAR_ARGS_PTR ClearArgs ++ ); ++ ++ ++gceSTATUS ++gcoSURF_3DBlitBltRect( ++ IN gcoSURF SrcSurf, ++ IN gcoSURF DestSurf, ++ IN gcsPOINT_PTR SrcOrigin, ++ IN gcsPOINT_PTR DestOrigin, ++ IN gcsPOINT_PTR RectSize ++ ); ++ ++gceSTATUS ++gcoSURF_3DBlitCopy( ++ IN gctUINT32 SrcAddress, ++ IN gctUINT32 DestAddress, ++ IN gctUINT32 Bytes ++ ); ++ ++ ++/******************************************************************************\ ++******************************** gcoINDEX Object ******************************* ++\******************************************************************************/ ++ ++/* Construct a new gcoINDEX object. */ ++gceSTATUS ++gcoINDEX_Construct( ++ IN gcoHAL Hal, ++ OUT gcoINDEX * Index ++ ); ++ ++/* Destroy a gcoINDEX object. */ ++gceSTATUS ++gcoINDEX_Destroy( ++ IN gcoINDEX Index ++ ); ++ ++/* Lock index in memory. */ ++gceSTATUS ++gcoINDEX_Lock( ++ IN gcoINDEX Index, ++ OUT gctUINT32 * Address, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Unlock index that was previously locked with gcoINDEX_Lock. */ ++gceSTATUS ++gcoINDEX_Unlock( ++ IN gcoINDEX Index ++ ); ++ ++/* Upload index data into the memory. */ ++gceSTATUS ++gcoINDEX_Load( ++ IN gcoINDEX Index, ++ IN gceINDEX_TYPE IndexType, ++ IN gctUINT32 IndexCount, ++ IN gctPOINTER IndexBuffer ++ ); ++ ++/* Bind an index object to the hardware. */ ++gceSTATUS ++gcoINDEX_Bind( ++ IN gcoINDEX Index, ++ IN gceINDEX_TYPE Type ++ ); ++ ++/* Bind an index object to the hardware. */ ++gceSTATUS ++gcoINDEX_BindOffset( ++ IN gcoINDEX Index, ++ IN gceINDEX_TYPE Type, ++ IN gctUINT32 Offset ++ ); ++ ++/* Free existing index buffer. */ ++gceSTATUS ++gcoINDEX_Free( ++ IN gcoINDEX Index ++ ); ++ ++/* Upload data into an index buffer. */ ++gceSTATUS ++gcoINDEX_Upload( ++ IN gcoINDEX Index, ++ IN gctCONST_POINTER Buffer, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Upload data into an index buffer starting at an offset. */ ++gceSTATUS ++gcoINDEX_UploadOffset( ++ IN gcoINDEX Index, ++ IN gctSIZE_T Offset, ++ IN gctCONST_POINTER Buffer, ++ IN gctSIZE_T Bytes ++ ); ++ ++/*Merge index2 to index1 from 0, index2 must subset of inex1*/ ++gceSTATUS ++gcoINDEX_Merge( ++ IN gcoINDEX Index1, ++ IN gcoINDEX Index2 ++ ); ++ ++/*check if index buffer is enough for this draw*/ ++gctBOOL ++gcoINDEX_CheckRange( ++ IN gcoINDEX Index, ++ IN gceINDEX_TYPE Type, ++ IN gctINT Count, ++ IN gctUINT32 Indices ++ ); ++ ++/* Query the index capabilities. */ ++gceSTATUS ++gcoINDEX_QueryCaps( ++ OUT gctBOOL * Index8, ++ OUT gctBOOL * Index16, ++ OUT gctBOOL * Index32, ++ OUT gctUINT * MaxIndex ++ ); ++ ++/* Determine the index range in the current index buffer. */ ++gceSTATUS ++gcoINDEX_GetIndexRange( ++ IN gcoINDEX Index, ++ IN gceINDEX_TYPE Type, ++ IN gctUINT32 Offset, ++ IN gctUINT32 Count, ++ OUT gctUINT32 * MinimumIndex, ++ OUT gctUINT32 * MaximumIndex ++ ); ++ ++/* Dynamic buffer management. */ ++gceSTATUS ++gcoINDEX_SetDynamic( ++ IN gcoINDEX Index, ++ IN gctSIZE_T Bytes, ++ IN gctUINT Buffers ++ ); ++ ++/******************************************************************************\ ++********************************** gco3D Object ********************************* ++\******************************************************************************/ ++ ++/* Blending targets. */ ++typedef enum _gceBLEND_UNIT ++{ ++ gcvBLEND_SOURCE, ++ gcvBLEND_TARGET, ++} ++gceBLEND_UNIT; ++ ++/* Construct a new gco3D object. */ ++gceSTATUS ++gco3D_Construct( ++ IN gcoHAL Hal, ++ OUT gco3D * Engine ++ ); ++ ++/* Destroy an gco3D object. */ ++gceSTATUS ++gco3D_Destroy( ++ IN gco3D Engine ++ ); ++ ++/* Set 3D API type. */ ++gceSTATUS ++gco3D_SetAPI( ++ IN gco3D Engine, ++ IN gceAPI ApiType ++ ); ++ ++/* Get 3D API type. */ ++gceSTATUS ++gco3D_GetAPI( ++ IN gco3D Engine, ++ OUT gceAPI * ApiType ++ ); ++ ++/* Set render target. */ ++gceSTATUS ++gco3D_SetTarget( ++ IN gco3D Engine, ++ IN gcoSURF Surface ++ ); ++ ++/* Unset render target. */ ++gceSTATUS ++gco3D_UnsetTarget( ++ IN gco3D Engine, ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gco3D_SetTargetEx( ++ IN gco3D Engine, ++ IN gctUINT32 TargetIndex, ++ IN gcoSURF Surface, ++ IN gctUINT32 LayerIndex ++ ); ++ ++gceSTATUS ++gco3D_UnsetTargetEx( ++ IN gco3D Engine, ++ IN gctUINT32 TargetIndex, ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gco3D_SetTargetOffsetEx( ++ IN gco3D Engine, ++ IN gctUINT32 TargetIndex, ++ IN gctSIZE_T Offset ++ ); ++ ++ ++gceSTATUS ++gco3D_SetPSOutputMapping( ++ IN gco3D Engine, ++ IN gctINT32 * psOutputMapping ++ ); ++ ++ ++/* Set depth buffer. */ ++gceSTATUS ++gco3D_SetDepth( ++ IN gco3D Engine, ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gco3D_SetDepthBufferOffset( ++ IN gco3D Engine, ++ IN gctSIZE_T Offset ++ ); ++ ++/* Unset depth buffer. */ ++gceSTATUS ++gco3D_UnsetDepth( ++ IN gco3D Engine, ++ IN gcoSURF Surface ++ ); ++ ++/* Set viewport. */ ++gceSTATUS ++gco3D_SetViewport( ++ IN gco3D Engine, ++ IN gctINT32 Left, ++ IN gctINT32 Top, ++ IN gctINT32 Right, ++ IN gctINT32 Bottom ++ ); ++ ++/* Set scissors. */ ++gceSTATUS ++gco3D_SetScissors( ++ IN gco3D Engine, ++ IN gctINT32 Left, ++ IN gctINT32 Top, ++ IN gctINT32 Right, ++ IN gctINT32 Bottom ++ ); ++ ++/* Set clear color. */ ++gceSTATUS ++gco3D_SetClearColor( ++ IN gco3D Engine, ++ IN gctUINT8 Red, ++ IN gctUINT8 Green, ++ IN gctUINT8 Blue, ++ IN gctUINT8 Alpha ++ ); ++ ++/* Set fixed point clear color. */ ++gceSTATUS ++gco3D_SetClearColorX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT Red, ++ IN gctFIXED_POINT Green, ++ IN gctFIXED_POINT Blue, ++ IN gctFIXED_POINT Alpha ++ ); ++ ++/* Set floating point clear color. */ ++gceSTATUS ++gco3D_SetClearColorF( ++ IN gco3D Engine, ++ IN gctFLOAT Red, ++ IN gctFLOAT Green, ++ IN gctFLOAT Blue, ++ IN gctFLOAT Alpha ++ ); ++ ++/* Set fixed point clear depth. */ ++gceSTATUS ++gco3D_SetClearDepthX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT Depth ++ ); ++ ++/* Set floating point clear depth. */ ++gceSTATUS ++gco3D_SetClearDepthF( ++ IN gco3D Engine, ++ IN gctFLOAT Depth ++ ); ++ ++/* Set clear stencil. */ ++gceSTATUS ++gco3D_SetClearStencil( ++ IN gco3D Engine, ++ IN gctUINT32 Stencil ++ ); ++ ++/* Set shading mode. */ ++gceSTATUS ++gco3D_SetShading( ++ IN gco3D Engine, ++ IN gceSHADING Shading ++ ); ++ ++/* Set blending mode. */ ++gceSTATUS ++gco3D_EnableBlending( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set blending function. */ ++gceSTATUS ++gco3D_SetBlendFunction( ++ IN gco3D Engine, ++ IN gceBLEND_UNIT Unit, ++ IN gceBLEND_FUNCTION FunctionRGB, ++ IN gceBLEND_FUNCTION FunctionAlpha ++ ); ++ ++/* Set blending mode. */ ++gceSTATUS ++gco3D_SetBlendMode( ++ IN gco3D Engine, ++ IN gceBLEND_MODE ModeRGB, ++ IN gceBLEND_MODE ModeAlpha ++ ); ++ ++/* Set blending color. */ ++gceSTATUS ++gco3D_SetBlendColor( ++ IN gco3D Engine, ++ IN gctUINT Red, ++ IN gctUINT Green, ++ IN gctUINT Blue, ++ IN gctUINT Alpha ++ ); ++ ++/* Set fixed point blending color. */ ++gceSTATUS ++gco3D_SetBlendColorX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT Red, ++ IN gctFIXED_POINT Green, ++ IN gctFIXED_POINT Blue, ++ IN gctFIXED_POINT Alpha ++ ); ++ ++/* Set floating point blending color. */ ++gceSTATUS ++gco3D_SetBlendColorF( ++ IN gco3D Engine, ++ IN gctFLOAT Red, ++ IN gctFLOAT Green, ++ IN gctFLOAT Blue, ++ IN gctFLOAT Alpha ++ ); ++ ++/* Set culling mode. */ ++gceSTATUS ++gco3D_SetCulling( ++ IN gco3D Engine, ++ IN gceCULL Mode ++ ); ++ ++/* Enable point size */ ++gceSTATUS ++gco3D_SetPointSizeEnable( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set point sprite */ ++gceSTATUS ++gco3D_SetPointSprite( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set fill mode. */ ++gceSTATUS ++gco3D_SetFill( ++ IN gco3D Engine, ++ IN gceFILL Mode ++ ); ++ ++/* Set depth compare mode. */ ++gceSTATUS ++gco3D_SetDepthCompare( ++ IN gco3D Engine, ++ IN gceCOMPARE Compare ++ ); ++ ++/* Enable depth writing. */ ++gceSTATUS ++gco3D_EnableDepthWrite( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set depth mode. */ ++gceSTATUS ++gco3D_SetDepthMode( ++ IN gco3D Engine, ++ IN gceDEPTH_MODE Mode ++ ); ++ ++/* Set depth range. */ ++gceSTATUS ++gco3D_SetDepthRangeX( ++ IN gco3D Engine, ++ IN gceDEPTH_MODE Mode, ++ IN gctFIXED_POINT Near, ++ IN gctFIXED_POINT Far ++ ); ++ ++/* Set depth range. */ ++gceSTATUS ++gco3D_SetDepthRangeF( ++ IN gco3D Engine, ++ IN gceDEPTH_MODE Mode, ++ IN gctFLOAT Near, ++ IN gctFLOAT Far ++ ); ++ ++/* Set last pixel enable */ ++gceSTATUS ++gco3D_SetLastPixelEnable( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set depth Bias and Scale */ ++gceSTATUS ++gco3D_SetDepthScaleBiasX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT DepthScale, ++ IN gctFIXED_POINT DepthBias ++ ); ++ ++gceSTATUS ++gco3D_SetDepthScaleBiasF( ++ IN gco3D Engine, ++ IN gctFLOAT DepthScale, ++ IN gctFLOAT DepthBias ++ ); ++ ++/* Set depth near and far clipping plane. */ ++gceSTATUS ++gco3D_SetDepthPlaneF( ++ IN gco3D Engine, ++ IN gctFLOAT Near, ++ IN gctFLOAT Far ++ ); ++ ++/* Enable or disable dithering. */ ++gceSTATUS ++gco3D_EnableDither( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set color write enable bits. */ ++gceSTATUS ++gco3D_SetColorWrite( ++ IN gco3D Engine, ++ IN gctUINT8 Enable ++ ); ++ ++/* Enable or disable early depth. */ ++gceSTATUS ++gco3D_SetEarlyDepth( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Deprecated: Enable or disable all early depth operations. */ ++gceSTATUS ++gco3D_SetAllEarlyDepthModes( ++ IN gco3D Engine, ++ IN gctBOOL Disable ++ ); ++ ++/* Enable or disable all early depth operations. */ ++gceSTATUS ++gco3D_SetAllEarlyDepthModesEx( ++ IN gco3D Engine, ++ IN gctBOOL Disable, ++ IN gctBOOL DisableModify, ++ IN gctBOOL DisablePassZ ++ ); ++ ++/* Switch dynamic early mode */ ++gceSTATUS ++gco3D_SwitchDynamicEarlyDepthMode( ++ IN gco3D Engine ++ ); ++ ++/* Set dynamic early mode */ ++gceSTATUS ++gco3D_DisableDynamicEarlyDepthMode( ++ IN gco3D Engine, ++ IN gctBOOL Disable ++ ); ++ ++/* Enable or disable depth-only mode. */ ++gceSTATUS ++gco3D_SetDepthOnly( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++typedef struct _gcsSTENCIL_INFO * gcsSTENCIL_INFO_PTR; ++typedef struct _gcsSTENCIL_INFO ++{ ++ gceSTENCIL_MODE mode; ++ ++ gctUINT8 maskFront; ++ gctUINT8 maskBack; ++ gctUINT8 writeMaskFront; ++ gctUINT8 writeMaskBack; ++ ++ gctUINT8 referenceFront; ++ ++ gceCOMPARE compareFront; ++ gceSTENCIL_OPERATION passFront; ++ gceSTENCIL_OPERATION failFront; ++ gceSTENCIL_OPERATION depthFailFront; ++ ++ gctUINT8 referenceBack; ++ gceCOMPARE compareBack; ++ gceSTENCIL_OPERATION passBack; ++ gceSTENCIL_OPERATION failBack; ++ gceSTENCIL_OPERATION depthFailBack; ++} ++gcsSTENCIL_INFO; ++ ++/* Set stencil mode. */ ++gceSTATUS ++gco3D_SetStencilMode( ++ IN gco3D Engine, ++ IN gceSTENCIL_MODE Mode ++ ); ++ ++/* Set stencil mask. */ ++gceSTATUS ++gco3D_SetStencilMask( ++ IN gco3D Engine, ++ IN gctUINT8 Mask ++ ); ++ ++/* Set stencil back mask. */ ++gceSTATUS ++gco3D_SetStencilMaskBack( ++ IN gco3D Engine, ++ IN gctUINT8 Mask ++ ); ++ ++/* Set stencil write mask. */ ++gceSTATUS ++gco3D_SetStencilWriteMask( ++ IN gco3D Engine, ++ IN gctUINT8 Mask ++ ); ++ ++/* Set stencil back write mask. */ ++gceSTATUS ++gco3D_SetStencilWriteMaskBack( ++ IN gco3D Engine, ++ IN gctUINT8 Mask ++ ); ++ ++/* Set stencil reference. */ ++gceSTATUS ++gco3D_SetStencilReference( ++ IN gco3D Engine, ++ IN gctUINT8 Reference, ++ IN gctBOOL Front ++ ); ++ ++/* Set stencil compare. */ ++gceSTATUS ++gco3D_SetStencilCompare( ++ IN gco3D Engine, ++ IN gceSTENCIL_WHERE Where, ++ IN gceCOMPARE Compare ++ ); ++ ++/* Set stencil operation on pass. */ ++gceSTATUS ++gco3D_SetStencilPass( ++ IN gco3D Engine, ++ IN gceSTENCIL_WHERE Where, ++ IN gceSTENCIL_OPERATION Operation ++ ); ++ ++/* Set stencil operation on fail. */ ++gceSTATUS ++gco3D_SetStencilFail( ++ IN gco3D Engine, ++ IN gceSTENCIL_WHERE Where, ++ IN gceSTENCIL_OPERATION Operation ++ ); ++ ++/* Set stencil operation on depth fail. */ ++gceSTATUS ++gco3D_SetStencilDepthFail( ++ IN gco3D Engine, ++ IN gceSTENCIL_WHERE Where, ++ IN gceSTENCIL_OPERATION Operation ++ ); ++ ++/* Set all stencil states in one blow. */ ++gceSTATUS ++gco3D_SetStencilAll( ++ IN gco3D Engine, ++ IN gcsSTENCIL_INFO_PTR Info ++ ); ++ ++typedef struct _gcsALPHA_INFO * gcsALPHA_INFO_PTR; ++typedef struct _gcsALPHA_INFO ++{ ++ /* Alpha test states. */ ++ gctBOOL test; ++ gceCOMPARE compare; ++ gctUINT8 reference; ++ gctFLOAT floatReference; ++ ++ /* Alpha blending states. */ ++ gctBOOL blend; ++ ++ gceBLEND_FUNCTION srcFuncColor; ++ gceBLEND_FUNCTION srcFuncAlpha; ++ gceBLEND_FUNCTION trgFuncColor; ++ gceBLEND_FUNCTION trgFuncAlpha; ++ ++ gceBLEND_MODE modeColor; ++ gceBLEND_MODE modeAlpha; ++ ++ gctUINT32 color; ++} ++gcsALPHA_INFO; ++ ++/* Enable or disable alpha test. */ ++gceSTATUS ++gco3D_SetAlphaTest( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set alpha test compare. */ ++gceSTATUS ++gco3D_SetAlphaCompare( ++ IN gco3D Engine, ++ IN gceCOMPARE Compare ++ ); ++ ++/* Set alpha test reference in unsigned integer. */ ++gceSTATUS ++gco3D_SetAlphaReference( ++ IN gco3D Engine, ++ IN gctUINT8 Reference, ++ IN gctFLOAT FloatReference ++ ); ++ ++/* Set alpha test reference in fixed point. */ ++gceSTATUS ++gco3D_SetAlphaReferenceX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT Reference ++ ); ++ ++/* Set alpha test reference in floating point. */ ++gceSTATUS ++gco3D_SetAlphaReferenceF( ++ IN gco3D Engine, ++ IN gctFLOAT Reference ++ ); ++ ++/* Enable/Disable anti-alias line. */ ++gceSTATUS ++gco3D_SetAntiAliasLine( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Set texture slot for anti-alias line. */ ++gceSTATUS ++gco3D_SetAALineTexSlot( ++ IN gco3D Engine, ++ IN gctUINT TexSlot ++ ); ++ ++/* Set anti-alias line width scale. */ ++gceSTATUS ++gco3D_SetAALineWidth( ++ IN gco3D Engine, ++ IN gctFLOAT Width ++ ); ++ ++/* Draw a number of primitives. */ ++gceSTATUS ++gco3D_DrawPrimitives( ++ IN gco3D Engine, ++ IN gcePRIMITIVE Type, ++ IN gctSIZE_T StartVertex, ++ IN gctSIZE_T PrimitiveCount ++ ); ++ ++gceSTATUS ++gco3D_DrawInstancedPrimitives( ++ IN gco3D Engine, ++ IN gcePRIMITIVE Type, ++ IN gctBOOL DrawIndex, ++ IN gctSIZE_T StartVertex, ++ IN gctSIZE_T StartIndex, ++ IN gctSIZE_T PrimitiveCount, ++ IN gctSIZE_T VertexCount, ++ IN gctSIZE_T InstanceCount ++ ); ++ ++gceSTATUS ++gco3D_DrawPrimitivesCount( ++ IN gco3D Engine, ++ IN gcePRIMITIVE Type, ++ IN gctINT* StartVertex, ++ IN gctSIZE_T* VertexCount, ++ IN gctSIZE_T PrimitiveCount ++ ); ++ ++ ++/* Draw a number of primitives using offsets. */ ++gceSTATUS ++gco3D_DrawPrimitivesOffset( ++ IN gco3D Engine, ++ IN gcePRIMITIVE Type, ++ IN gctINT32 StartOffset, ++ IN gctSIZE_T PrimitiveCount ++ ); ++ ++/* Draw a number of indexed primitives. */ ++gceSTATUS ++gco3D_DrawIndexedPrimitives( ++ IN gco3D Engine, ++ IN gcePRIMITIVE Type, ++ IN gctSIZE_T BaseVertex, ++ IN gctSIZE_T StartIndex, ++ IN gctSIZE_T PrimitiveCount ++ ); ++ ++/* Draw a number of indexed primitives using offsets. */ ++gceSTATUS ++gco3D_DrawIndexedPrimitivesOffset( ++ IN gco3D Engine, ++ IN gcePRIMITIVE Type, ++ IN gctINT32 BaseOffset, ++ IN gctINT32 StartOffset, ++ IN gctSIZE_T PrimitiveCount ++ ); ++ ++/* Draw a element from pattern */ ++gceSTATUS ++gco3D_DrawPattern( ++ IN gco3D Engine, ++ IN gcsFAST_FLUSH_PTR FastFlushInfo ++ ); ++ ++/* Enable or disable anti-aliasing. */ ++gceSTATUS ++gco3D_SetAntiAlias( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++/* Write data into the command buffer. */ ++gceSTATUS ++gco3D_WriteBuffer( ++ IN gco3D Engine, ++ IN gctCONST_POINTER Data, ++ IN gctSIZE_T Bytes, ++ IN gctBOOL Aligned ++ ); ++ ++/* Send sempahore and stall until sempahore is signalled. */ ++gceSTATUS ++gco3D_Semaphore( ++ IN gco3D Engine, ++ IN gceWHERE From, ++ IN gceWHERE To, ++ IN gceHOW How); ++ ++/* Explicitly flush shader L1 cache */ ++gceSTATUS ++gco3D_FlushSHL1Cache( ++ IN gco3D Engine ++ ); ++ ++/* Set the subpixels center. */ ++gceSTATUS ++gco3D_SetCentroids( ++ IN gco3D Engine, ++ IN gctUINT32 Index, ++ IN gctPOINTER Centroids ++ ); ++ ++gceSTATUS ++gco3D_SetLogicOp( ++ IN gco3D Engine, ++ IN gctUINT8 Rop ++ ); ++ ++gceSTATUS ++gco3D_SetOQ( ++ IN gco3D Engine, ++ INOUT gctPOINTER * Result, ++ IN gctBOOL Enable ++ ); ++ ++gceSTATUS ++gco3D_GetOQ( ++ IN gco3D Engine, ++ IN gctPOINTER Result, ++ OUT gctINT64 * Logical ++ ); ++ ++gceSTATUS ++gco3D_DeleteOQ( ++ IN gco3D Engine, ++ INOUT gctPOINTER Result ++ ); ++ ++gceSTATUS ++gco3D_SetColorOutCount( ++ IN gco3D Engine, ++ IN gctUINT32 ColorOutCount ++ ); ++ ++gceSTATUS ++gco3D_Set3DEngine( ++ IN gco3D Engine ++ ); ++ ++gceSTATUS ++gco3D_UnSet3DEngine( ++ IN gco3D Engine ++ ); ++ ++gceSTATUS ++gco3D_Get3DEngine( ++ OUT gco3D * Engine ++ ); ++ ++ ++/* OCL thread walker information. */ ++typedef struct _gcsTHREAD_WALKER_INFO * gcsTHREAD_WALKER_INFO_PTR; ++typedef struct _gcsTHREAD_WALKER_INFO ++{ ++ gctUINT32 dimensions; ++ gctUINT32 traverseOrder; ++ gctUINT32 enableSwathX; ++ gctUINT32 enableSwathY; ++ gctUINT32 enableSwathZ; ++ gctUINT32 swathSizeX; ++ gctUINT32 swathSizeY; ++ gctUINT32 swathSizeZ; ++ gctUINT32 valueOrder; ++ ++ gctUINT32 globalSizeX; ++ gctUINT32 globalOffsetX; ++ gctUINT32 globalSizeY; ++ gctUINT32 globalOffsetY; ++ gctUINT32 globalSizeZ; ++ gctUINT32 globalOffsetZ; ++ ++ gctUINT32 workGroupSizeX; ++ gctUINT32 workGroupCountX; ++ gctUINT32 workGroupSizeY; ++ gctUINT32 workGroupCountY; ++ gctUINT32 workGroupSizeZ; ++ gctUINT32 workGroupCountZ; ++ ++ gctUINT32 threadAllocation; ++} ++gcsTHREAD_WALKER_INFO; ++ ++/* Start OCL thread walker. */ ++gceSTATUS ++gco3D_InvokeThreadWalker( ++ IN gco3D Engine, ++ IN gcsTHREAD_WALKER_INFO_PTR Info ++ ); ++ ++gceSTATUS ++gco3D_GetClosestRenderFormat( ++ IN gco3D Engine, ++ IN gceSURF_FORMAT InFormat, ++ OUT gceSURF_FORMAT* OutFormat ++ ); ++ ++/* Set w clip and w plane limit value. */ ++gceSTATUS ++gco3D_SetWClipEnable( ++ IN gco3D Engine, ++ IN gctBOOL Enable ++ ); ++ ++gceSTATUS ++gco3D_GetWClipEnable( ++ IN gco3D Engine, ++ OUT gctBOOL * Enable ++ ); ++ ++gceSTATUS ++gco3D_SetWPlaneLimitF( ++ IN gco3D Engine, ++ IN gctFLOAT Value ++ ); ++ ++gceSTATUS ++gco3D_SetWPlaneLimitX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT Value ++ ); ++ ++gceSTATUS ++gco3D_SetWPlaneLimit( ++ IN gco3D Engine, ++ IN gctFLOAT Value ++ ); ++ ++gceSTATUS ++gco3D_PrimitiveRestart( ++ IN gco3D Engine, ++ IN gctBOOL PrimitiveRestart); ++ ++#if gcdSTREAM_OUT_BUFFER ++ ++gceSTATUS ++gco3D_QueryStreamOut( ++ IN gco3D Engine, ++ IN gctUINT32 OriginalIndexAddress, ++ IN gctUINT32 OriginalIndexOffset, ++ IN gctUINT32 OriginalIndexCount, ++ OUT gctBOOL_PTR Found ++ ); ++ ++gceSTATUS ++gco3D_StartStreamOut( ++ IN gco3D Engine, ++ IN gctINT StreamOutStatus, ++ IN gctUINT32 IndexAddress, ++ IN gctUINT32 IndexOffset, ++ IN gctUINT32 IndexCount ++ ); ++ ++gceSTATUS ++gco3D_StopStreamOut( ++ IN gco3D Engine ++ ); ++ ++gceSTATUS ++gco3D_ReplayStreamOut( ++ IN gco3D Engine, ++ IN gctUINT32 IndexAddress, ++ IN gctUINT32 IndexOffset, ++ IN gctUINT32 IndexCount ++ ); ++ ++gceSTATUS ++gco3D_EndStreamOut( ++ IN gco3D Engine ++ ); ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*-------------------------- gco3D Fragment Processor ------------------------*/ ++ ++/* Set the fragment processor configuration. */ ++gceSTATUS ++gco3D_SetFragmentConfiguration( ++ IN gco3D Engine, ++ IN gctBOOL ColorFromStream, ++ IN gctBOOL EnableFog, ++ IN gctBOOL EnableSmoothPoint, ++ IN gctUINT32 ClipPlanes ++ ); ++ ++/* Enable/disable texture stage operation. */ ++gceSTATUS ++gco3D_EnableTextureStage( ++ IN gco3D Engine, ++ IN gctINT Stage, ++ IN gctBOOL Enable ++ ); ++ ++/* Program the channel enable masks for the color texture function. */ ++gceSTATUS ++gco3D_SetTextureColorMask( ++ IN gco3D Engine, ++ IN gctINT Stage, ++ IN gctBOOL ColorEnabled, ++ IN gctBOOL AlphaEnabled ++ ); ++ ++/* Program the channel enable masks for the alpha texture function. */ ++gceSTATUS ++gco3D_SetTextureAlphaMask( ++ IN gco3D Engine, ++ IN gctINT Stage, ++ IN gctBOOL ColorEnabled, ++ IN gctBOOL AlphaEnabled ++ ); ++ ++/* Program the constant fragment color. */ ++gceSTATUS ++gco3D_SetFragmentColorX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT Red, ++ IN gctFIXED_POINT Green, ++ IN gctFIXED_POINT Blue, ++ IN gctFIXED_POINT Alpha ++ ); ++ ++gceSTATUS ++gco3D_SetFragmentColorF( ++ IN gco3D Engine, ++ IN gctFLOAT Red, ++ IN gctFLOAT Green, ++ IN gctFLOAT Blue, ++ IN gctFLOAT Alpha ++ ); ++ ++/* Program the constant fog color. */ ++gceSTATUS ++gco3D_SetFogColorX( ++ IN gco3D Engine, ++ IN gctFIXED_POINT Red, ++ IN gctFIXED_POINT Green, ++ IN gctFIXED_POINT Blue, ++ IN gctFIXED_POINT Alpha ++ ); ++ ++gceSTATUS ++gco3D_SetFogColorF( ++ IN gco3D Engine, ++ IN gctFLOAT Red, ++ IN gctFLOAT Green, ++ IN gctFLOAT Blue, ++ IN gctFLOAT Alpha ++ ); ++ ++/* Program the constant texture color. */ ++gceSTATUS ++gco3D_SetTetxureColorX( ++ IN gco3D Engine, ++ IN gctINT Stage, ++ IN gctFIXED_POINT Red, ++ IN gctFIXED_POINT Green, ++ IN gctFIXED_POINT Blue, ++ IN gctFIXED_POINT Alpha ++ ); ++ ++gceSTATUS ++gco3D_SetTetxureColorF( ++ IN gco3D Engine, ++ IN gctINT Stage, ++ IN gctFLOAT Red, ++ IN gctFLOAT Green, ++ IN gctFLOAT Blue, ++ IN gctFLOAT Alpha ++ ); ++ ++/* Configure color texture function. */ ++gceSTATUS ++gco3D_SetColorTextureFunction( ++ IN gco3D Engine, ++ IN gctINT Stage, ++ IN gceTEXTURE_FUNCTION Function, ++ IN gceTEXTURE_SOURCE Source0, ++ IN gceTEXTURE_CHANNEL Channel0, ++ IN gceTEXTURE_SOURCE Source1, ++ IN gceTEXTURE_CHANNEL Channel1, ++ IN gceTEXTURE_SOURCE Source2, ++ IN gceTEXTURE_CHANNEL Channel2, ++ IN gctINT Scale ++ ); ++ ++/* Configure alpha texture function. */ ++gceSTATUS ++gco3D_SetAlphaTextureFunction( ++ IN gco3D Engine, ++ IN gctINT Stage, ++ IN gceTEXTURE_FUNCTION Function, ++ IN gceTEXTURE_SOURCE Source0, ++ IN gceTEXTURE_CHANNEL Channel0, ++ IN gceTEXTURE_SOURCE Source1, ++ IN gceTEXTURE_CHANNEL Channel1, ++ IN gceTEXTURE_SOURCE Source2, ++ IN gceTEXTURE_CHANNEL Channel2, ++ IN gctINT Scale ++ ); ++ ++/******************************************************************************\ ++******************************* gcoTEXTURE Object ******************************* ++\******************************************************************************/ ++ ++/* Cube faces. */ ++typedef enum _gceTEXTURE_FACE ++{ ++ gcvFACE_NONE, ++ gcvFACE_POSITIVE_X, ++ gcvFACE_NEGATIVE_X, ++ gcvFACE_POSITIVE_Y, ++ gcvFACE_NEGATIVE_Y, ++ gcvFACE_POSITIVE_Z, ++ gcvFACE_NEGATIVE_Z, ++} ++gceTEXTURE_FACE; ++ ++typedef struct _gcsTEXTURE ++{ ++ /* Addressing modes. */ ++ gceTEXTURE_ADDRESSING s; ++ gceTEXTURE_ADDRESSING t; ++ gceTEXTURE_ADDRESSING r; ++ ++ gceTEXTURE_SWIZZLE swizzle[gcvTEXTURE_COMPONENT_NUM]; ++ ++ /* Border color. */ ++ gctUINT8 border[gcvTEXTURE_COMPONENT_NUM]; ++ ++ /* Filters. */ ++ gceTEXTURE_FILTER minFilter; ++ gceTEXTURE_FILTER magFilter; ++ gceTEXTURE_FILTER mipFilter; ++ gctUINT anisoFilter; ++ ++ /* Level of detail. */ ++ gctFLOAT lodBias; ++ gctFLOAT lodMin; ++ gctFLOAT lodMax; ++ ++ /* base/max level */ ++ gctINT32 baseLevel; ++ gctINT32 maxLevel; ++ ++ /* depth texture comparison */ ++ gceTEXTURE_COMPARE_MODE compareMode; ++ gceCOMPARE compareFunc; ++ ++} ++gcsTEXTURE, * gcsTEXTURE_PTR; ++ ++/* Construct a new gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_Construct( ++ IN gcoHAL Hal, ++ OUT gcoTEXTURE * Texture ++ ); ++ ++/* Construct a new gcoTEXTURE object with type information. */ ++gceSTATUS ++gcoTEXTURE_ConstructEx( ++ IN gcoHAL Hal, ++ IN gceTEXTURE_TYPE Type, ++ OUT gcoTEXTURE * Texture ++ ); ++ ++ ++/* Construct a new sized gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_ConstructSized( ++ IN gcoHAL Hal, ++ IN gceSURF_FORMAT Format, ++ IN gctUINT Width, ++ IN gctUINT Height, ++ IN gctUINT Depth, ++ IN gctUINT Faces, ++ IN gctUINT MipMapCount, ++ IN gcePOOL Pool, ++ OUT gcoTEXTURE * Texture ++ ); ++ ++/* Destroy an gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_Destroy( ++ IN gcoTEXTURE Texture ++ ); ++ ++/* Upload data to an gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_Upload( ++ IN gcoTEXTURE Texture, ++ IN gctINT MipMap, ++ IN gceTEXTURE_FACE Face, ++ IN gctSIZE_T Width, ++ IN gctSIZE_T Height, ++ IN gctUINT Slice, ++ IN gctCONST_POINTER Memory, ++ IN gctSIZE_T Stride, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_COLOR_SPACE SrcColorSpace ++ ); ++ ++/* Upload data to an gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_UploadSub( ++ IN gcoTEXTURE Texture, ++ IN gctINT MipMap, ++ IN gceTEXTURE_FACE Face, ++ IN gctSIZE_T X, ++ IN gctSIZE_T Y, ++ IN gctSIZE_T Width, ++ IN gctSIZE_T Height, ++ IN gctUINT Slice, ++ IN gctCONST_POINTER Memory, ++ IN gctSIZE_T Stride, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_COLOR_SPACE SrcColorSpace, ++ IN gctUINT32 PhysicalAddress ++ ); ++ ++ ++/* Upload YUV data to an gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_UploadYUV( ++ IN gcoTEXTURE Texture, ++ IN gceTEXTURE_FACE Face, ++ IN gctUINT Width, ++ IN gctUINT Height, ++ IN gctUINT Slice, ++ IN gctPOINTER Memory[3], ++ IN gctINT Stride[3], ++ IN gceSURF_FORMAT Format ++ ); ++ ++/* Upload compressed data to an gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_UploadCompressed( ++ IN gcoTEXTURE Texture, ++ IN gctINT MipMap, ++ IN gceTEXTURE_FACE Face, ++ IN gctSIZE_T Width, ++ IN gctSIZE_T Height, ++ IN gctUINT Slice, ++ IN gctCONST_POINTER Memory, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Upload compressed sub data to an gcoTEXTURE object. */ ++gceSTATUS ++gcoTEXTURE_UploadCompressedSub( ++ IN gcoTEXTURE Texture, ++ IN gctINT MipMap, ++ IN gceTEXTURE_FACE Face, ++ IN gctSIZE_T XOffset, ++ IN gctSIZE_T YOffset, ++ IN gctSIZE_T Width, ++ IN gctSIZE_T Height, ++ IN gctUINT Slice, ++ IN gctCONST_POINTER Memory, ++ IN gctSIZE_T Size ++ ); ++ ++/* Get gcoSURF object for a mipmap level. */ ++gceSTATUS ++gcoTEXTURE_GetMipMap( ++ IN gcoTEXTURE Texture, ++ IN gctUINT MipMap, ++ OUT gcoSURF * Surface ++ ); ++ ++/* Get gcoSURF object for a mipmap level and face offset. */ ++gceSTATUS ++gcoTEXTURE_GetMipMapFace( ++ IN gcoTEXTURE Texture, ++ IN gctUINT MipMap, ++ IN gceTEXTURE_FACE Face, ++ OUT gcoSURF * Surface, ++ OUT gctSIZE_T_PTR Offset ++ ); ++ ++gceSTATUS ++gcoTEXTURE_GetMipMapSlice( ++ IN gcoTEXTURE Texture, ++ IN gctUINT MipMap, ++ IN gctUINT Slice, ++ OUT gcoSURF * Surface, ++ OUT gctSIZE_T_PTR Offset ++ ); ++ ++gceSTATUS ++gcoTEXTURE_AddMipMap( ++ IN gcoTEXTURE Texture, ++ IN gctINT Level, ++ IN gctINT InternalFormat, ++ IN gceSURF_FORMAT Format, ++ IN gctSIZE_T Width, ++ IN gctSIZE_T Height, ++ IN gctSIZE_T Depth, ++ IN gctUINT Faces, ++ IN gcePOOL Pool, ++ OUT gcoSURF * Surface ++ ); ++ ++gceSTATUS ++gcoTEXTURE_AddMipMapWithFlag( ++ IN gcoTEXTURE Texture, ++ IN gctINT Level, ++ IN gctINT InternalFormat, ++ IN gceSURF_FORMAT Format, ++ IN gctSIZE_T Width, ++ IN gctSIZE_T Height, ++ IN gctSIZE_T Depth, ++ IN gctUINT Faces, ++ IN gcePOOL Pool, ++ IN gctBOOL Protected, ++ OUT gcoSURF * Surface ++ ); ++ ++gceSTATUS ++gcoTEXTURE_AddMipMapFromClient( ++ IN gcoTEXTURE Texture, ++ IN gctINT Level, ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoTEXTURE_AddMipMapFromSurface( ++ IN gcoTEXTURE Texture, ++ IN gctINT Level, ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoTEXTURE_SetEndianHint( ++ IN gcoTEXTURE Texture, ++ IN gceENDIAN_HINT EndianHint ++ ); ++ ++gceSTATUS ++gcoTEXTURE_Disable( ++ IN gcoHAL Hal, ++ IN gctINT Sampler ++ ); ++ ++gceSTATUS ++gcoTEXTURE_Flush( ++ IN gcoTEXTURE Texture ++ ); ++ ++gceSTATUS ++gcoTEXTURE_FlushVS( ++ IN gcoTEXTURE Texture ++ ); ++ ++gceSTATUS ++gcoTEXTURE_QueryCaps( ++ IN gcoHAL Hal, ++ OUT gctUINT * MaxWidth, ++ OUT gctUINT * MaxHeight, ++ OUT gctUINT * MaxDepth, ++ OUT gctBOOL * Cubic, ++ OUT gctBOOL * NonPowerOfTwo, ++ OUT gctUINT * VertexSamplers, ++ OUT gctUINT * PixelSamplers ++ ); ++ ++gceSTATUS ++gcoTEXTURE_GetClosestFormat( ++ IN gcoHAL Hal, ++ IN gceSURF_FORMAT InFormat, ++ OUT gceSURF_FORMAT* OutFormat ++ ); ++ ++gceSTATUS ++gcoTEXTURE_GetClosestFormatEx( ++ IN gcoHAL Hal, ++ IN gceSURF_FORMAT InFormat, ++ IN gceTEXTURE_TYPE TextureType, ++ OUT gceSURF_FORMAT* OutFormat ++ ); ++ ++gceSTATUS ++gcoTEXTURE_GetFormatInfo( ++ IN gcoTEXTURE Texture, ++ IN gctINT preferLevel, ++ OUT gcsSURF_FORMAT_INFO_PTR * TxFormatInfo ++ ); ++ ++gceSTATUS ++gcoTEXTURE_GetTextureFormatName( ++ IN gcsSURF_FORMAT_INFO_PTR TxFormatInfo, ++ OUT gctCONST_STRING * TxName ++ ); ++ ++gceSTATUS ++gcoTEXTURE_RenderIntoMipMap( ++ IN gcoTEXTURE Texture, ++ IN gctINT Level ++ ); ++ ++gceSTATUS ++gcoTEXTURE_RenderIntoMipMap2( ++ IN gcoTEXTURE Texture, ++ IN gctINT Level, ++ IN gctBOOL Sync ++ ); ++ ++gceSTATUS ++gcoTEXTURE_IsRenderable( ++ IN gcoTEXTURE Texture, ++ IN gctUINT Level ++ ); ++ ++gceSTATUS ++gcoTEXTURE_IsComplete( ++ IN gcoTEXTURE Texture, ++ IN gcsTEXTURE_PTR Info, ++ IN gctINT BaseLevel, ++ IN gctINT MaxLevel ++ ); ++ ++gceSTATUS ++gcoTEXTURE_BindTexture( ++ IN gcoTEXTURE Texture, ++ IN gctINT Target, ++ IN gctINT Sampler, ++ IN gcsTEXTURE_PTR Info ++ ); ++ ++gceSTATUS ++gcoTEXTURE_BindTextureEx( ++ IN gcoTEXTURE Texture, ++ IN gctINT Target, ++ IN gctINT Sampler, ++ IN gcsTEXTURE_PTR Info, ++ IN gctINT textureLayer ++ ); ++ ++gceSTATUS ++gcoTEXTURE_InitParams( ++ IN gcoHAL Hal, ++ IN gcsTEXTURE_PTR TexParams ++ ); ++ ++gceSTATUS ++gcoTEXTURE_SetDepthTextureFlag( ++ IN gcoTEXTURE Texture, ++ IN gctBOOL unsized ++ ); ++ ++ ++/******************************************************************************\ ++******************************* gcoSTREAM Object ****************************** ++\******************************************************************************/ ++ ++typedef enum _gceVERTEX_FORMAT ++{ ++ gcvVERTEX_BYTE, ++ gcvVERTEX_UNSIGNED_BYTE, ++ gcvVERTEX_SHORT, ++ gcvVERTEX_UNSIGNED_SHORT, ++ gcvVERTEX_INT, ++ gcvVERTEX_UNSIGNED_INT, ++ gcvVERTEX_FIXED, ++ gcvVERTEX_HALF, ++ gcvVERTEX_FLOAT, ++ gcvVERTEX_UNSIGNED_INT_10_10_10_2, ++ gcvVERTEX_INT_10_10_10_2, ++ gcvVERTEX_UNSIGNED_INT_2_10_10_10_REV, ++ gcvVERTEX_INT_2_10_10_10_REV, ++ /* integer format */ ++ gcvVERTEX_INT8, ++ gcvVERTEX_INT16, ++ gcvVERTEX_INT32, ++} ++gceVERTEX_FORMAT; ++ ++/* What the SW converting scheme to create temp attrib */ ++typedef enum _gceATTRIB_SCHEME ++{ ++ gcvATTRIB_SCHEME_KEEP = 0, ++ gcvATTRIB_SCHEME_2_10_10_10_REV_TO_FLOAT, ++ gcvATTRIB_SCHEME_BYTE_TO_INT, ++ gcvATTRIB_SCHEME_SHORT_TO_INT, ++ gcvATTRIB_SCHEME_UBYTE_TO_UINT, ++ gcvATTRIB_SCHEME_USHORT_TO_UINT, ++} gceATTRIB_SCHEME; ++ ++gceSTATUS ++gcoSTREAM_Construct( ++ IN gcoHAL Hal, ++ OUT gcoSTREAM * Stream ++ ); ++ ++gceSTATUS ++gcoSTREAM_Destroy( ++ IN gcoSTREAM Stream ++ ); ++ ++gceSTATUS ++gcoSTREAM_Upload( ++ IN gcoSTREAM Stream, ++ IN gctCONST_POINTER Buffer, ++ IN gctSIZE_T Offset, ++ IN gctSIZE_T Bytes, ++ IN gctBOOL Dynamic ++ ); ++ ++gceSTATUS ++gcoSTREAM_SetStride( ++ IN gcoSTREAM Stream, ++ IN gctUINT32 Stride ++ ); ++ ++gceSTATUS ++gcoSTREAM_Size( ++ IN gcoSTREAM Stream, ++ OUT gctSIZE_T *Size ++ ); ++ ++gceSTATUS ++gcoSTREAM_Node( ++ IN gcoSTREAM Stream, ++ OUT gcsSURF_NODE_PTR * Node ++ ); ++ ++gceSTATUS ++gcoSTREAM_Lock( ++ IN gcoSTREAM Stream, ++ OUT gctPOINTER * Logical, ++ OUT gctUINT32 * Physical ++ ); ++ ++gceSTATUS ++gcoSTREAM_Unlock( ++ IN gcoSTREAM Stream ++ ); ++ ++gceSTATUS ++gcoSTREAM_Reserve( ++ IN gcoSTREAM Stream, ++ IN gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gcoSTREAM_Flush( ++ IN gcoSTREAM Stream ++ ); ++ ++/* Dynamic buffer API. */ ++gceSTATUS ++gcoSTREAM_SetDynamic( ++ IN gcoSTREAM Stream, ++ IN gctSIZE_T Bytes, ++ IN gctUINT Buffers ++ ); ++ ++typedef struct _gcsSTREAM_INFO ++{ ++ gctUINT index; ++ gceVERTEX_FORMAT format; ++ gctBOOL normalized; ++ gctUINT components; ++ gctSIZE_T size; ++ gctCONST_POINTER data; ++ gctUINT stride; ++} ++gcsSTREAM_INFO, * gcsSTREAM_INFO_PTR; ++ ++gceSTATUS ++gcoSTREAM_UploadDynamic( ++ IN gcoSTREAM Stream, ++ IN gctUINT VertexCount, ++ IN gctUINT InfoCount, ++ IN gcsSTREAM_INFO_PTR Info, ++ IN gcoVERTEX Vertex ++ ); ++ ++gceSTATUS ++gcoSTREAM_CPUCacheOperation( ++ IN gcoSTREAM Stream, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++gceSTATUS ++gcoSTREAM_CPUCacheOperation_Range( ++ IN gcoSTREAM Stream, ++ IN gctSIZE_T Offset, ++ IN gctSIZE_T Length, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++/******************************************************************************\ ++******************************** gcoVERTEX Object ****************************** ++\******************************************************************************/ ++ ++typedef struct _gcsVERTEX_ATTRIBUTES ++{ ++ gceVERTEX_FORMAT format; ++ gctBOOL normalized; ++ gctUINT32 components; ++ gctSIZE_T size; ++ gctUINT32 stream; ++ gctUINT32 offset; ++ gctUINT32 stride; ++} ++gcsVERTEX_ATTRIBUTES; ++ ++gceSTATUS ++gcoVERTEX_Construct( ++ IN gcoHAL Hal, ++ OUT gcoVERTEX * Vertex ++ ); ++ ++gceSTATUS ++gcoVERTEX_Destroy( ++ IN gcoVERTEX Vertex ++ ); ++ ++gceSTATUS ++gcoVERTEX_Reset( ++ IN gcoVERTEX Vertex ++ ); ++ ++gceSTATUS ++gcoVERTEX_EnableAttribute( ++ IN gcoVERTEX Vertex, ++ IN gctUINT32 Index, ++ IN gceVERTEX_FORMAT Format, ++ IN gctBOOL Normalized, ++ IN gctUINT32 Components, ++ IN gcoSTREAM Stream, ++ IN gctUINT32 Offset, ++ IN gctUINT32 Stride ++ ); ++ ++gceSTATUS ++gcoVERTEX_DisableAttribute( ++ IN gcoVERTEX Vertex, ++ IN gctUINT32 Index ++ ); ++ ++gceSTATUS ++gcoVERTEX_Bind( ++ IN gcoVERTEX Vertex ++ ); ++ ++/******************************************************************************* ++***** gcoVERTEXARRAY Object ***************************************************/ ++ ++typedef struct _gcsATTRIBUTE ++{ ++ /* Enabled. */ ++ gctBOOL enable; ++ ++ /* Number of components. */ ++ gctINT size; ++ ++ /* Attribute format. */ ++ gceVERTEX_FORMAT format; ++ ++ /* Flag whether the attribute is normalized or not. */ ++ gctBOOL normalized; ++ ++ /* Stride of the component. */ ++ gctSIZE_T stride; ++ ++ /* Divisor of the attribute */ ++ gctUINT divisor; ++ ++ /* Pointer to the attribute data. */ ++ gctCONST_POINTER pointer; ++ ++ /* Stream object owning the attribute data. */ ++ gcoBUFOBJ stream; ++ ++ /* Generic values for attribute. */ ++ gctFLOAT genericValue[4]; ++ ++ /* Generic size for attribute. */ ++ gctINT genericSize; ++ ++ /* Vertex shader linkage. */ ++ gctUINT linkage; ++ ++#if gcdUSE_WCLIP_PATCH ++ /* Does it hold positions? */ ++ gctBOOL isPosition; ++#endif ++ ++ /* Index to vertex array */ ++ gctINT arrayIdx; ++ ++ gceATTRIB_SCHEME convertScheme; ++ ++ /* Pointer to the temporary buffer to be freed */ ++ gcoBUFOBJ tempStream; ++ ++ /* Pointer to the temporary memory to be freed */ ++ gctCONST_POINTER tempMemory; ++} ++gcsATTRIBUTE, ++* gcsATTRIBUTE_PTR; ++ ++ ++typedef struct _gcsVERTEXARRAY ++{ ++ /* Enabled. */ ++ gctBOOL enable; ++ ++ /* Number of components. */ ++ gctINT size; ++ ++ /* Attribute format. */ ++ gceVERTEX_FORMAT format; ++ ++ /* Flag whether the attribute is normalized or not. */ ++ gctBOOL normalized; ++ ++ /* Stride of the component. */ ++ gctUINT stride; ++ ++ /* Divisor of the attribute */ ++ gctUINT divisor; ++ ++ /* Pointer to the attribute data. */ ++ gctCONST_POINTER pointer; ++ ++ /* Stream object owning the attribute data. */ ++ gcoSTREAM stream; ++ ++ /* Generic values for attribute. */ ++ gctFLOAT genericValue[4]; ++ ++ /* Generic size for attribute. */ ++ gctINT genericSize; ++ ++ /* Vertex shader linkage. */ ++ gctUINT linkage; ++ ++ gctBOOL isPosition; ++} ++gcsVERTEXARRAY, ++* gcsVERTEXARRAY_PTR; ++ ++gceSTATUS ++gcoVERTEXARRAY_Construct( ++ IN gcoHAL Hal, ++ OUT gcoVERTEXARRAY * Vertex ++ ); ++ ++gceSTATUS ++gcoVERTEXARRAY_Destroy( ++ IN gcoVERTEXARRAY Vertex ++ ); ++ ++gceSTATUS ++gcoVERTEXARRAY_Bind_Ex( ++ IN gcoVERTEXARRAY Vertex, ++ IN gctUINT32 EnableBits, ++ IN gcsVERTEXARRAY_PTR VertexArray, ++ IN gctUINT First, ++ IN gctSIZE_T Count, ++ IN gctBOOL DrawArraysInstanced, ++ IN gctSIZE_T InstanceCount, ++ IN gceINDEX_TYPE IndexType, ++ IN gcoINDEX IndexObject, ++ IN gctPOINTER IndexMemory, ++ IN OUT gcePRIMITIVE * PrimitiveType, ++#if gcdUSE_WCLIP_PATCH ++ IN OUT gctUINT * PrimitiveCount, ++ IN OUT gctFLOAT * wLimitRms, ++ IN OUT gctBOOL * wLimitDirty ++#else ++ IN OUT gctUINT * PrimitiveCount ++#endif ++ ); ++ ++gceSTATUS ++gcoVERTEXARRAY_Bind_Ex2( ++ IN gcoVERTEXARRAY Vertex, ++ IN gctUINT32 EnableBits, ++ IN gcsATTRIBUTE_PTR VertexArray, ++ IN gctSIZE_T First, ++ IN gctSIZE_T Count, ++ IN gctBOOL DrawArraysInstanced, ++ IN gctSIZE_T InstanceCount, ++ IN gceINDEX_TYPE IndexType, ++ IN gcoBUFOBJ IndexObject, ++ IN gctPOINTER IndexMemory, ++ IN OUT gcePRIMITIVE * PrimitiveType, ++#if gcdUSE_WCLIP_PATCH ++ IN OUT gctSIZE_T * PrimitiveCount, ++ IN OUT gctFLOAT * wLimitRms, ++ IN OUT gctBOOL * wLimitDirty, ++#else ++ IN OUT gctUINT * PrimitiveCount, ++#endif ++ IN gctINT VertexInstanceIdLinkage ++ ); ++ ++gceSTATUS ++gcoVERTEXARRAY_Bind( ++ IN gcoVERTEXARRAY Vertex, ++ IN gctUINT32 EnableBits, ++ IN gcsVERTEXARRAY_PTR VertexArray, ++ IN gctUINT First, ++ IN gctSIZE_T Count, ++ IN gceINDEX_TYPE IndexType, ++ IN gcoINDEX IndexObject, ++ IN gctPOINTER IndexMemory, ++ IN OUT gcePRIMITIVE * PrimitiveType, ++#if gcdUSE_WCLIP_PATCH ++ IN OUT gctUINT * PrimitiveCount, ++ IN OUT gctFLOAT * wLimitRms, ++ IN OUT gctBOOL * wLimitDirty ++#else ++ IN OUT gctUINT * PrimitiveCount ++#endif ++ ); ++ ++/******************************************************************************* ++***** Composition *************************************************************/ ++ ++typedef enum _gceCOMPOSITION ++{ ++ gcvCOMPOSE_CLEAR = 1, ++ gcvCOMPOSE_BLUR, ++ gcvCOMPOSE_DIM, ++ gcvCOMPOSE_LAYER ++} ++gceCOMPOSITION; ++ ++typedef struct _gcsCOMPOSITION * gcsCOMPOSITION_PTR; ++typedef struct _gcsCOMPOSITION ++{ ++ /* Structure size. */ ++ gctUINT structSize; ++ ++ /* Composition operation. */ ++ gceCOMPOSITION operation; ++ ++ /* Layer to be composed. */ ++ gcoSURF layer; ++ ++ /* Source and target coordinates. */ ++ gcsRECT srcRect; ++ gcsRECT trgRect; ++ ++ /* Target rectangle */ ++ gcsPOINT v0; ++ gcsPOINT v1; ++ gcsPOINT v2; ++ ++ /* Blending parameters. */ ++ gctBOOL enableBlending; ++ gctBOOL premultiplied; ++ gctUINT8 alphaValue; ++ ++ /* Clear color. */ ++ gctFLOAT r; ++ gctFLOAT g; ++ gctFLOAT b; ++ gctFLOAT a; ++} ++gcsCOMPOSITION; ++ ++gceSTATUS ++gco3D_ProbeComposition( ++ IN gcoHARDWARE Hardware, ++ IN gctBOOL ResetIfEmpty ++ ); ++ ++gceSTATUS ++gco3D_CompositionBegin( ++ IN gcoHARDWARE Hardware ++ ); ++ ++gceSTATUS ++gco3D_ComposeLayer( ++ IN gcoHARDWARE Hardware, ++ IN gcsCOMPOSITION_PTR Layer ++ ); ++ ++gceSTATUS ++gco3D_CompositionSignals( ++ IN gcoHARDWARE Hardware, ++ IN gctHANDLE Process, ++ IN gctSIGNAL Signal1, ++ IN gctSIGNAL Signal2 ++ ); ++ ++gceSTATUS ++gco3D_CompositionEnd( ++ IN gcoHARDWARE Hardware, ++ IN gcoSURF Target, ++ IN gctBOOL Synchronous ++ ); ++ ++/* Frame Database */ ++gceSTATUS ++gcoHAL_AddFrameDB( ++ void ++ ); ++ ++gceSTATUS ++gcoHAL_DumpFrameDB( ++ gctCONST_STRING Filename OPTIONAL ++ ); ++ ++/****************************************************************************** ++**********************gcoBUFOBJ object***************************************** ++*******************************************************************************/ ++typedef enum _gceBUFOBJ_TYPE ++{ ++ gcvBUFOBJ_TYPE_ARRAY_BUFFER = 1, ++ gcvBUFOBJ_TYPE_ELEMENT_ARRAY_BUFFER = 2, ++ gcvBUFOBJ_TYPE_GENERIC_BUFFER = 100 ++ ++} gceBUFOBJ_TYPE; ++ ++typedef enum _gceBUFOBJ_USAGE ++{ ++ gcvBUFOBJ_USAGE_STREAM_DRAW = 1, ++ gcvBUFOBJ_USAGE_STREAM_READ, ++ gcvBUFOBJ_USAGE_STREAM_COPY, ++ gcvBUFOBJ_USAGE_STATIC_DRAW, ++ gcvBUFOBJ_USAGE_STATIC_READ, ++ gcvBUFOBJ_USAGE_STATIC_COPY, ++ gcvBUFOBJ_USAGE_DYNAMIC_DRAW, ++ gcvBUFOBJ_USAGE_DYNAMIC_READ, ++ gcvBUFOBJ_USAGE_DYNAMIC_COPY, ++ ++} gceBUFOBJ_USAGE; ++ ++/* Construct a new gcoBUFOBJ object. */ ++gceSTATUS ++gcoBUFOBJ_Construct( ++ IN gcoHAL Hal, ++ IN gceBUFOBJ_TYPE Type, ++ OUT gcoBUFOBJ * BufObj ++ ); ++ ++/* Destroy a gcoBUFOBJ object. */ ++gceSTATUS ++gcoBUFOBJ_Destroy( ++ IN gcoBUFOBJ BufObj ++ ); ++ ++/* Lock pbo in memory. */ ++gceSTATUS ++gcoBUFOBJ_Lock( ++ IN gcoBUFOBJ BufObj, ++ OUT gctUINT32 * Address, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Lock pbo in memory. */ ++gceSTATUS ++gcoBUFOBJ_FastLock( ++ IN gcoBUFOBJ BufObj, ++ OUT gctUINT32 * Address, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Unlock pbo that was previously locked with gcoBUFOBJ_Lock. */ ++gceSTATUS ++gcoBUFOBJ_Unlock( ++ IN gcoBUFOBJ BufObj ++ ); ++ ++/* Free existing pbo buffer. */ ++gceSTATUS ++gcoBUFOBJ_Free( ++ IN gcoBUFOBJ BufObj ++ ); ++ ++/* Upload data into an pbo buffer. */ ++gceSTATUS ++gcoBUFOBJ_Upload( ++ IN gcoBUFOBJ BufObj, ++ IN gctCONST_POINTER Buffer, ++ IN gctSIZE_T Offset, ++ IN gctSIZE_T Bytes, ++ IN gceBUFOBJ_USAGE Usage ++ ); ++ ++/* Bind an index object to the hardware. */ ++gceSTATUS ++gcoBUFOBJ_IndexBind ( ++ IN gcoBUFOBJ Index, ++ IN gceINDEX_TYPE Type, ++ IN gctUINT32 Offset, ++ IN gctSIZE_T Count ++ ); ++ ++/* Find min and max index for the index buffer */ ++gceSTATUS ++gcoBUFOBJ_IndexGetRange( ++ IN gcoBUFOBJ Index, ++ IN gceINDEX_TYPE Type, ++ IN gctUINT32 Offset, ++ IN gctUINT32 Count, ++ OUT gctUINT32 * MinimumIndex, ++ OUT gctUINT32 * MaximumIndex ++ ); ++ ++/* Sets a buffer object as dirty */ ++gceSTATUS ++gcoBUFOBJ_SetDirty( ++ IN gcoBUFOBJ BufObj ++ ); ++ ++/* Creates a new buffer if needed */ ++gceSTATUS ++gcoBUFOBJ_AlignIndexBufferWhenNeeded( ++ IN gcoBUFOBJ BufObj, ++ IN gctSIZE_T Offset, ++ OUT gcoBUFOBJ * AlignedBufObj ++ ); ++ ++/* Cache operations on whole range */ ++gceSTATUS ++gcoBUFOBJ_CPUCacheOperation( ++ IN gcoBUFOBJ BufObj, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++/* Cache operations on a specified range */ ++gceSTATUS ++gcoBUFOBJ_CPUCacheOperation_Range( ++ IN gcoBUFOBJ BufObj, ++ IN gctSIZE_T Offset, ++ IN gctSIZE_T Length, ++ IN gceCACHEOPERATION Operation ++ ); ++ ++/* Return size of the bufobj */ ++gceSTATUS ++gcoBUFOBJ_GetSize( ++ IN gcoBUFOBJ BufObj, ++ OUT gctSIZE_T_PTR Size ++ ); ++ ++/* Return memory node of the bufobj */ ++gceSTATUS ++gcoBUFOBJ_GetNode( ++ IN gcoBUFOBJ BufObj, ++ OUT gcsSURF_NODE_PTR * Node ++ ); ++ ++/* Handle GPU cache operations */ ++gceSTATUS ++gcoBUFOBJ_GPUCacheOperation( ++ gcoBUFOBJ BufObj ++ ); ++ ++/* Dump buffer. */ ++void ++gcoBUFOBJ_Dump( ++ IN gcoBUFOBJ BufObj ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* gcdENABLE_3D */ ++#endif /* __gc_hal_engine_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_engine_vg.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_engine_vg.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_engine_vg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_engine_vg.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,1215 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_engine_vg_h_ ++#define __gc_hal_engine_vg_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include "gc_hal_types.h" ++ ++/******************************************************************************\ ++******************************** VG Enumerations ******************************* ++\******************************************************************************/ ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Tiling mode for painting and imagig. ++** ++** This enumeration defines the tiling modes supported by the HAL. This is ++** in fact a one-to-one mapping of the OpenVG 1.1 tile modes. ++*/ ++typedef enum _gceTILE_MODE ++{ ++ gcvTILE_FILL, ++ gcvTILE_PAD, ++ gcvTILE_REPEAT, ++ gcvTILE_REFLECT ++} ++gceTILE_MODE; ++ ++/******************************************************************************/ ++/** @ingroup gcoVG ++** ++** @brief The different paint modes. ++** ++** This enumeration lists the available paint modes. ++*/ ++typedef enum _gcePAINT_TYPE ++{ ++ /** Solid color. */ ++ gcvPAINT_MODE_SOLID, ++ ++ /** Linear gradient. */ ++ gcvPAINT_MODE_LINEAR, ++ ++ /** Radial gradient. */ ++ gcvPAINT_MODE_RADIAL, ++ ++ /** Pattern. */ ++ gcvPAINT_MODE_PATTERN, ++ ++ /** Mode count. */ ++ gcvPAINT_MODE_COUNT ++} ++gcePAINT_TYPE; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Types of path data supported by HAL. ++** ++** This enumeration defines the types of path data supported by the HAL. ++** This is in fact a one-to-one mapping of the OpenVG 1.1 path types. ++*/ ++typedef enum _gcePATHTYPE ++{ ++ gcePATHTYPE_UNKNOWN = -1, ++ gcePATHTYPE_INT8, ++ gcePATHTYPE_INT16, ++ gcePATHTYPE_INT32, ++ gcePATHTYPE_FLOAT ++} ++gcePATHTYPE; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Supported path segment commands. ++** ++** This enumeration defines the path segment commands supported by the HAL. ++*/ ++typedef enum _gceVGCMD ++{ ++ gcvVGCMD_END, /* 0: GCCMD_TS_OPCODE_END */ ++ gcvVGCMD_CLOSE, /* 1: GCCMD_TS_OPCODE_CLOSE */ ++ gcvVGCMD_MOVE, /* 2: GCCMD_TS_OPCODE_MOVE */ ++ gcvVGCMD_MOVE_REL, /* 3: GCCMD_TS_OPCODE_MOVE_REL */ ++ gcvVGCMD_LINE, /* 4: GCCMD_TS_OPCODE_LINE */ ++ gcvVGCMD_LINE_REL, /* 5: GCCMD_TS_OPCODE_LINE_REL */ ++ gcvVGCMD_QUAD, /* 6: GCCMD_TS_OPCODE_QUADRATIC */ ++ gcvVGCMD_QUAD_REL, /* 7: GCCMD_TS_OPCODE_QUADRATIC_REL */ ++ gcvVGCMD_CUBIC, /* 8: GCCMD_TS_OPCODE_CUBIC */ ++ gcvVGCMD_CUBIC_REL, /* 9: GCCMD_TS_OPCODE_CUBIC_REL */ ++ gcvVGCMD_BREAK, /* 10: GCCMD_TS_OPCODE_BREAK */ ++ gcvVGCMD_HLINE, /* 11: ******* R E S E R V E D *******/ ++ gcvVGCMD_HLINE_REL, /* 12: ******* R E S E R V E D *******/ ++ gcvVGCMD_VLINE, /* 13: ******* R E S E R V E D *******/ ++ gcvVGCMD_VLINE_REL, /* 14: ******* R E S E R V E D *******/ ++ gcvVGCMD_SQUAD, /* 15: ******* R E S E R V E D *******/ ++ gcvVGCMD_SQUAD_REL, /* 16: ******* R E S E R V E D *******/ ++ gcvVGCMD_SCUBIC, /* 17: ******* R E S E R V E D *******/ ++ gcvVGCMD_SCUBIC_REL, /* 18: ******* R E S E R V E D *******/ ++ gcvVGCMD_SCCWARC, /* 19: ******* R E S E R V E D *******/ ++ gcvVGCMD_SCCWARC_REL, /* 20: ******* R E S E R V E D *******/ ++ gcvVGCMD_SCWARC, /* 21: ******* R E S E R V E D *******/ ++ gcvVGCMD_SCWARC_REL, /* 22: ******* R E S E R V E D *******/ ++ gcvVGCMD_LCCWARC, /* 23: ******* R E S E R V E D *******/ ++ gcvVGCMD_LCCWARC_REL, /* 24: ******* R E S E R V E D *******/ ++ gcvVGCMD_LCWARC, /* 25: ******* R E S E R V E D *******/ ++ gcvVGCMD_LCWARC_REL, /* 26: ******* R E S E R V E D *******/ ++ ++ /* The width of the command recognized by the hardware on bits. */ ++ gcvVGCMD_WIDTH = 5, ++ ++ /* Hardware command mask. */ ++ gcvVGCMD_MASK = (1 << gcvVGCMD_WIDTH) - 1, ++ ++ /* Command modifiers. */ ++ gcvVGCMD_H_MOD = 1 << gcvVGCMD_WIDTH, /* = 32 */ ++ gcvVGCMD_V_MOD = 2 << gcvVGCMD_WIDTH, /* = 64 */ ++ gcvVGCMD_S_MOD = 3 << gcvVGCMD_WIDTH, /* = 96 */ ++ gcvVGCMD_ARC_MOD = 4 << gcvVGCMD_WIDTH, /* = 128 */ ++ ++ /* Emulated LINE commands. */ ++ gcvVGCMD_HLINE_EMUL = gcvVGCMD_H_MOD | gcvVGCMD_LINE, /* = 36 */ ++ gcvVGCMD_HLINE_EMUL_REL = gcvVGCMD_H_MOD | gcvVGCMD_LINE_REL, /* = 37 */ ++ gcvVGCMD_VLINE_EMUL = gcvVGCMD_V_MOD | gcvVGCMD_LINE, /* = 68 */ ++ gcvVGCMD_VLINE_EMUL_REL = gcvVGCMD_V_MOD | gcvVGCMD_LINE_REL, /* = 69 */ ++ ++ /* Emulated SMOOTH commands. */ ++ gcvVGCMD_SQUAD_EMUL = gcvVGCMD_S_MOD | gcvVGCMD_QUAD, /* = 102 */ ++ gcvVGCMD_SQUAD_EMUL_REL = gcvVGCMD_S_MOD | gcvVGCMD_QUAD_REL, /* = 103 */ ++ gcvVGCMD_SCUBIC_EMUL = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC, /* = 104 */ ++ gcvVGCMD_SCUBIC_EMUL_REL = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC_REL, /* = 105 */ ++ ++ /* Emulation ARC commands. */ ++ gcvVGCMD_ARC_LINE = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE, /* = 132 */ ++ gcvVGCMD_ARC_LINE_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE_REL, /* = 133 */ ++ gcvVGCMD_ARC_QUAD = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD, /* = 134 */ ++ gcvVGCMD_ARC_QUAD_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD_REL /* = 135 */ ++} ++gceVGCMD; ++typedef enum _gceVGCMD * gceVGCMD_PTR; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Blending modes supported by the HAL. ++** ++** This enumeration defines the blending modes supported by the HAL. This is ++** in fact a one-to-one mapping of the OpenVG 1.1 blending modes. ++*/ ++typedef enum _gceVG_BLEND ++{ ++ gcvVG_BLEND_SRC, ++ gcvVG_BLEND_SRC_OVER, ++ gcvVG_BLEND_DST_OVER, ++ gcvVG_BLEND_SRC_IN, ++ gcvVG_BLEND_DST_IN, ++ gcvVG_BLEND_MULTIPLY, ++ gcvVG_BLEND_SCREEN, ++ gcvVG_BLEND_DARKEN, ++ gcvVG_BLEND_LIGHTEN, ++ gcvVG_BLEND_ADDITIVE, ++ gcvVG_BLEND_SUBTRACT, ++ gcvVG_BLEND_FILTER ++} ++gceVG_BLEND; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Image modes supported by the HAL. ++** ++** This enumeration defines the image modes supported by the HAL. This is ++** in fact a one-to-one mapping of the OpenVG 1.1 image modes with the addition ++** of NO IMAGE. ++*/ ++typedef enum _gceVG_IMAGE ++{ ++ gcvVG_IMAGE_NONE, ++ gcvVG_IMAGE_NORMAL, ++ gcvVG_IMAGE_MULTIPLY, ++ gcvVG_IMAGE_STENCIL, ++ gcvVG_IMAGE_FILTER ++} ++gceVG_IMAGE; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Filter mode patterns and imaging. ++** ++** This enumeration defines the filter modes supported by the HAL. ++*/ ++typedef enum _gceIMAGE_FILTER ++{ ++ gcvFILTER_POINT, ++ gcvFILTER_LINEAR, ++ gcvFILTER_BI_LINEAR ++} ++gceIMAGE_FILTER; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Primitive modes supported by the HAL. ++** ++** This enumeration defines the primitive modes supported by the HAL. ++*/ ++typedef enum _gceVG_PRIMITIVE ++{ ++ gcvVG_SCANLINE, ++ gcvVG_RECTANGLE, ++ gcvVG_TESSELLATED, ++ gcvVG_TESSELLATED_TILED ++} ++gceVG_PRIMITIVE; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Rendering quality modes supported by the HAL. ++** ++** This enumeration defines the rendering quality modes supported by the HAL. ++*/ ++typedef enum _gceRENDER_QUALITY ++{ ++ gcvVG_NONANTIALIASED, ++ gcvVG_2X2_MSAA, ++ gcvVG_2X4_MSAA, ++ gcvVG_4X4_MSAA ++} ++gceRENDER_QUALITY; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Fill rules supported by the HAL. ++** ++** This enumeration defines the fill rules supported by the HAL. ++*/ ++typedef enum _gceFILL_RULE ++{ ++ gcvVG_EVEN_ODD, ++ gcvVG_NON_ZERO ++} ++gceFILL_RULE; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Cap styles supported by the HAL. ++** ++** This enumeration defines the cap styles supported by the HAL. ++*/ ++typedef enum _gceCAP_STYLE ++{ ++ gcvCAP_BUTT, ++ gcvCAP_ROUND, ++ gcvCAP_SQUARE ++} ++gceCAP_STYLE; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Join styles supported by the HAL. ++** ++** This enumeration defines the join styles supported by the HAL. ++*/ ++typedef enum _gceJOIN_STYLE ++{ ++ gcvJOIN_MITER, ++ gcvJOIN_ROUND, ++ gcvJOIN_BEVEL ++} ++gceJOIN_STYLE; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Channel mask values. ++** ++** This enumeration defines the values for channel mask used in image ++** filtering. ++*/ ++ ++/* Base values for channel mask definitions. */ ++#define gcvCHANNEL_X (0) ++#define gcvCHANNEL_R (1 << 0) ++#define gcvCHANNEL_G (1 << 1) ++#define gcvCHANNEL_B (1 << 2) ++#define gcvCHANNEL_A (1 << 3) ++ ++typedef enum _gceCHANNEL ++{ ++ gcvCHANNEL_XXXX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X), ++ gcvCHANNEL_XXXA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A), ++ gcvCHANNEL_XXBX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X), ++ gcvCHANNEL_XXBA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A), ++ ++ gcvCHANNEL_XGXX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X), ++ gcvCHANNEL_XGXA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A), ++ gcvCHANNEL_XGBX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X), ++ gcvCHANNEL_XGBA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A), ++ ++ gcvCHANNEL_RXXX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X), ++ gcvCHANNEL_RXXA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A), ++ gcvCHANNEL_RXBX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X), ++ gcvCHANNEL_RXBA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A), ++ ++ gcvCHANNEL_RGXX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X), ++ gcvCHANNEL_RGXA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A), ++ gcvCHANNEL_RGBX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X), ++ gcvCHANNEL_RGBA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A), ++} ++gceCHANNEL; ++ ++/******************************************************************************\ ++******************************** VG Structures ******************************* ++\******************************************************************************/ ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Definition of the color ramp used by the gradient paints. ++** ++** The gcsCOLOR_RAMP structure defines the layout of one single color inside ++** a color ramp which is used by gradient paints. ++*/ ++typedef struct _gcsCOLOR_RAMP ++{ ++ /** Value for the color stop. */ ++ gctFLOAT stop; ++ ++ /** Red color channel value for the color stop. */ ++ gctFLOAT red; ++ ++ /** Green color channel value for the color stop. */ ++ gctFLOAT green; ++ ++ /** Blue color channel value for the color stop. */ ++ gctFLOAT blue; ++ ++ /** Alpha color channel value for the color stop. */ ++ gctFLOAT alpha; ++} ++gcsCOLOR_RAMP, * gcsCOLOR_RAMP_PTR; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Definition of the color ramp used by the gradient paints in fixed form. ++** ++** The gcsCOLOR_RAMP structure defines the layout of one single color inside ++** a color ramp which is used by gradient paints. ++*/ ++typedef struct _gcsFIXED_COLOR_RAMP ++{ ++ /** Value for the color stop. */ ++ gctFIXED_POINT stop; ++ ++ /** Red color channel value for the color stop. */ ++ gctFIXED_POINT red; ++ ++ /** Green color channel value for the color stop. */ ++ gctFIXED_POINT green; ++ ++ /** Blue color channel value for the color stop. */ ++ gctFIXED_POINT blue; ++ ++ /** Alpha color channel value for the color stop. */ ++ gctFIXED_POINT alpha; ++} ++gcsFIXED_COLOR_RAMP, * gcsFIXED_COLOR_RAMP_PTR; ++ ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Rectangle structure used by the gcoVG object. ++** ++** This structure defines the layout of a rectangle. Make sure width and ++** height are larger than 0. ++*/ ++typedef struct _gcsVG_RECT * gcsVG_RECT_PTR; ++typedef struct _gcsVG_RECT ++{ ++ /** Left location of the rectangle. */ ++ gctINT x; ++ ++ /** Top location of the rectangle. */ ++ gctINT y; ++ ++ /** Width of the rectangle. */ ++ gctINT width; ++ ++ /** Height of the rectangle. */ ++ gctINT height; ++} ++gcsVG_RECT; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Path command buffer attribute structure. ++** ++** The gcsPATH_BUFFER_INFO structure contains the specifics about ++** the layout of the path data command buffer. ++*/ ++typedef struct _gcsPATH_BUFFER_INFO * gcsPATH_BUFFER_INFO_PTR; ++typedef struct _gcsPATH_BUFFER_INFO ++{ ++ gctUINT reservedForHead; ++ gctUINT reservedForTail; ++} ++gcsPATH_BUFFER_INFO; ++ ++/** ++** @ingroup gcoVG ++** ++** @brief Definition of the path data container structure. ++** ++** The gcsPATH structure defines the layout of the path data container. ++*/ ++typedef struct _gcsPATH_DATA * gcsPATH_DATA_PTR; ++typedef struct _gcsPATH_DATA ++{ ++ /* Data container in command buffer format. */ ++ gcsCMDBUFFER data; ++ ++ /* Path data type. */ ++ gcePATHTYPE dataType; ++} ++gcsPATH_DATA; ++ ++ ++/******************************************************************************\ ++********************************* gcoHAL Object ******************************** ++\******************************************************************************/ ++ ++/* Query path data storage attributes. */ ++gceSTATUS ++gcoHAL_QueryPathStorage( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ OUT gcsPATH_BUFFER_INFO_PTR Information ++ ); ++ ++/* Associate a completion signal with the command buffer. */ ++gceSTATUS ++gcoHAL_AssociateCompletion( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcsPATH_DATA_PTR PathData ++ ); ++ ++/* Release the current command buffer completion signal. */ ++gceSTATUS ++gcoHAL_DeassociateCompletion( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcsPATH_DATA_PTR PathData ++ ); ++ ++/* Verify whether the command buffer is still in use. */ ++gceSTATUS ++gcoHAL_CheckCompletion( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcsPATH_DATA_PTR PathData ++ ); ++ ++/* Wait until the command buffer is no longer in use. */ ++gceSTATUS ++gcoHAL_WaitCompletion( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcsPATH_DATA_PTR PathData ++ ); ++ ++/* Flush the pixel cache. */ ++gceSTATUS ++gcoHAL_Flush( ++ IN gcoHAL Hal ++#if GC355_PROFILER ++ , ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth ++#endif ++ ); ++ ++/* Split a harwdare address into pool and offset. */ ++gceSTATUS ++gcoHAL_SplitAddress( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctUINT32 Address, ++ OUT gcePOOL * Pool, ++ OUT gctUINT32 * Offset ++ ); ++ ++/* Combine pool and offset into a harwdare address. */ ++gceSTATUS ++gcoHAL_CombineAddress( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcePOOL Pool, ++ IN gctUINT32 Offset, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Schedule to free linear video memory allocated. */ ++gceSTATUS ++gcoHAL_ScheduleVideoMemory( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctUINT32 Node ++ ); ++ ++/* Free linear video memory allocated with gcoHAL_AllocateLinearVideoMemory. */ ++gceSTATUS ++gcoHAL_FreeVideoMemory( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctUINT32 Node ++ ); ++ ++/* Query command buffer attributes. */ ++gceSTATUS ++gcoHAL_QueryCommandBuffer( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ OUT gcsCOMMAND_BUFFER_INFO_PTR Information ++ ); ++/* Allocate and lock linear video memory. */ ++gceSTATUS ++gcoHAL_AllocateLinearVideoMemory( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctUINT Size, ++ IN gctUINT Alignment, ++ IN gcePOOL Pool, ++ OUT gctUINT32 * Node, ++ OUT gctUINT32 * Address, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Align the specified size accordingly to the hardware requirements. */ ++gceSTATUS ++gcoHAL_GetAlignedSurfaceSize( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceSURF_TYPE Type, ++ IN OUT gctUINT32_PTR Width, ++ IN OUT gctUINT32_PTR Height ++ ); ++ ++gceSTATUS ++gcoHAL_ReserveTask( ++ IN gcoHAL Hal, ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceBLOCK Block, ++ IN gctUINT TaskCount, ++ IN gctUINT32 Bytes, ++ OUT gctPOINTER * Memory ++ ); ++/******************************************************************************\ ++********************************** gcoVG Object ******************************** ++\******************************************************************************/ ++ ++/** @defgroup gcoVG gcoVG ++** ++** The gcoVG object abstracts the VG hardware pipe. ++*/ ++#if GC355_PROFILER ++void ++gcoVG_ProfilerEnableDisable( ++ IN gcoVG Vg, ++ IN gctUINT enableGetAPITimes, ++ IN gctFILE apiTimeFile ++ ); ++ ++void ++gcoVG_ProfilerTreeDepth( ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth ++ ); ++ ++void ++gcoVG_ProfilerSetStates( ++ IN gcoVG Vg, ++ IN gctUINT treeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth ++ ); ++#endif ++ ++gctBOOL ++gcoVG_IsMaskSupported( ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceSURF_FORMAT Format ++ ); ++ ++gctBOOL ++gcoVG_IsTargetSupported( ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceSURF_FORMAT Format ++ ); ++ ++gctBOOL ++gcoVG_IsImageSupported( ++#if GC355_PROFILER ++ IN gcoVG Vg, ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceSURF_FORMAT Format ++ ); ++ ++gctUINT8 gcoVG_PackColorComponent( ++#if GC355_PROFILER ++ gcoVG Vg, ++ gctUINT TreeDepth, ++ gctUINT saveLayerTreeDepth, ++ gctUINT varTreeDepth, ++#endif ++ gctFLOAT Value ++ ); ++ ++gceSTATUS ++gcoVG_Construct( ++ IN gcoHAL Hal, ++ OUT gcoVG * Vg ++ ); ++ ++gceSTATUS ++gcoVG_Destroy( ++ IN gcoVG Vg ++#if GC355_PROFILER ++ , ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth ++#endif ++ ); ++ ++gceSTATUS ++gcoVG_SetTarget( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Target ++ ); ++ ++gceSTATUS ++gcoVG_UnsetTarget( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoVG_SetUserToSurface( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctFLOAT UserToSurface[9] ++ ); ++ ++gceSTATUS ++gcoVG_SetSurfaceToImage( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctFLOAT SurfaceToImage[9] ++ ); ++ ++gceSTATUS ++gcoVG_EnableMask( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctBOOL Enable ++ ); ++ ++gceSTATUS ++gcoVG_SetMask( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Mask ++ ); ++ ++gceSTATUS ++gcoVG_UnsetMask( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Surface ++ ); ++ ++gceSTATUS ++gcoVG_FlushMask( ++ IN gcoVG Vg ++#if GC355_PROFILER ++ , ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth ++#endif ++ ); ++ ++gceSTATUS ++gcoVG_EnableScissor( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctBOOL Enable ++ ); ++ ++gceSTATUS ++gcoVG_SetScissor( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctSIZE_T RectangleCount, ++ IN gcsVG_RECT_PTR Rectangles ++ ); ++ ++gceSTATUS ++gcoVG_EnableColorTransform( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctBOOL Enable ++ ); ++ ++gceSTATUS ++gcoVG_SetColorTransform( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctFLOAT ColorTransform[8] ++ ); ++ ++gceSTATUS ++gcoVG_SetTileFillColor( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctFLOAT Red, ++ IN gctFLOAT Green, ++ IN gctFLOAT Blue, ++ IN gctFLOAT Alpha ++ ); ++ ++gceSTATUS ++gcoVG_SetSolidPaint( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctUINT8 Red, ++ IN gctUINT8 Green, ++ IN gctUINT8 Blue, ++ IN gctUINT8 Alpha ++ ); ++ ++gceSTATUS ++gcoVG_SetLinearPaint( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctFLOAT Constant, ++ IN gctFLOAT StepX, ++ IN gctFLOAT StepY ++ ); ++ ++gceSTATUS ++gcoVG_SetRadialPaint( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctFLOAT LinConstant, ++ IN gctFLOAT LinStepX, ++ IN gctFLOAT LinStepY, ++ IN gctFLOAT RadConstant, ++ IN gctFLOAT RadStepX, ++ IN gctFLOAT RadStepY, ++ IN gctFLOAT RadStepXX, ++ IN gctFLOAT RadStepYY, ++ IN gctFLOAT RadStepXY ++ ); ++ ++gceSTATUS ++gcoVG_SetPatternPaint( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctFLOAT UConstant, ++ IN gctFLOAT UStepX, ++ IN gctFLOAT UStepY, ++ IN gctFLOAT VConstant, ++ IN gctFLOAT VStepX, ++ IN gctFLOAT VStepY, ++ IN gctBOOL Linear ++ ); ++ ++gceSTATUS ++gcoVG_SetColorRamp( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF ColorRamp, ++ IN gceTILE_MODE ColorRampSpreadMode ++ ); ++ ++gceSTATUS ++gcoVG_SetPattern( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctINT32 width, ++ IN gctINT32 height, ++ IN gcoSURF Pattern, ++ IN gceTILE_MODE TileMode, ++ IN gceIMAGE_FILTER Filter ++ ); ++ ++gceSTATUS ++gcoVG_SetImageMode( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceVG_IMAGE Mode ++ ); ++ ++gceSTATUS ++gcoVG_SetBlendMode( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceVG_BLEND Mode ++ ); ++ ++gceSTATUS ++gcoVG_SetRenderingQuality( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceRENDER_QUALITY Quality ++ ); ++ ++gceSTATUS ++gcoVG_SetFillRule( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gceFILL_RULE FillRule ++ ); ++ ++gceSTATUS ++gcoVG_FinalizePath( ++ IN gcoVG Vg, ++ IN gcsPATH_DATA_PTR PathData ++ ); ++ ++gceSTATUS ++gcoVG_Clear( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctINT X, ++ IN gctINT Y, ++ IN gctINT Width, ++ IN gctINT Height ++ ); ++ ++gceSTATUS ++gcoVG_DrawPath( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcsPATH_DATA_PTR PathData, ++ IN gctFLOAT Scale, ++ IN gctFLOAT Bias, ++#if gcdMOVG ++ IN gctUINT32 Width, ++ IN gctUINT32 Height, ++ IN gctFLOAT *Bounds, ++#endif ++ IN gctBOOL SoftwareTesselation ++ ); ++ ++gceSTATUS ++gcoVG_DrawImage( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Source, ++ IN gcsPOINT_PTR SourceOrigin, ++ IN gcsPOINT_PTR TargetOrigin, ++ IN gcsSIZE_PTR SourceSize, ++ IN gctINT SourceX, ++ IN gctINT SourceY, ++ IN gctINT TargetX, ++ IN gctINT TargetY, ++ IN gctINT Width, ++ IN gctINT Height, ++ IN gctBOOL Mask, ++ IN gctBOOL isDrawImage ++ ); ++ ++gceSTATUS ++gcoVG_TesselateImage( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Image, ++ IN gcsVG_RECT_PTR Rectangle, ++ IN gceIMAGE_FILTER Filter, ++ IN gctBOOL Mask, ++#if gcdMOVG ++ IN gctBOOL SoftwareTesselation, ++ IN gceVG_BLEND BlendMode ++#else ++ IN gctBOOL SoftwareTesselation ++#endif ++ ); ++ ++gceSTATUS ++gcoVG_Blit( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Source, ++ IN gcoSURF Target, ++ IN gcsVG_RECT_PTR SrcRect, ++ IN gcsVG_RECT_PTR TrgRect, ++ IN gceIMAGE_FILTER Filter, ++ IN gceVG_BLEND Mode ++ ); ++ ++gceSTATUS ++gcoVG_ColorMatrix( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Source, ++ IN gcoSURF Target, ++ IN const gctFLOAT * Matrix, ++ IN gceCHANNEL ColorChannels, ++ IN gctBOOL FilterLinear, ++ IN gctBOOL FilterPremultiplied, ++ IN gcsPOINT_PTR SourceOrigin, ++ IN gcsPOINT_PTR TargetOrigin, ++ IN gctINT Width, ++ IN gctINT Height ++ ); ++ ++gceSTATUS ++gcoVG_SeparableConvolve( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Source, ++ IN gcoSURF Target, ++ IN gctINT KernelWidth, ++ IN gctINT KernelHeight, ++ IN gctINT ShiftX, ++ IN gctINT ShiftY, ++ IN const gctINT16 * KernelX, ++ IN const gctINT16 * KernelY, ++ IN gctFLOAT Scale, ++ IN gctFLOAT Bias, ++ IN gceTILE_MODE TilingMode, ++ IN gctFLOAT_PTR FillColor, ++ IN gceCHANNEL ColorChannels, ++ IN gctBOOL FilterLinear, ++ IN gctBOOL FilterPremultiplied, ++ IN gcsPOINT_PTR SourceOrigin, ++ IN gcsPOINT_PTR TargetOrigin, ++ IN gcsSIZE_PTR SourceSize, ++ IN gctINT Width, ++ IN gctINT Height ++ ); ++ ++gceSTATUS ++gcoVG_GaussianBlur( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gcoSURF Source, ++ IN gcoSURF Target, ++ IN gctFLOAT StdDeviationX, ++ IN gctFLOAT StdDeviationY, ++ IN gceTILE_MODE TilingMode, ++ IN gctFLOAT_PTR FillColor, ++ IN gceCHANNEL ColorChannels, ++ IN gctBOOL FilterLinear, ++ IN gctBOOL FilterPremultiplied, ++ IN gcsPOINT_PTR SourceOrigin, ++ IN gcsPOINT_PTR TargetOrigin, ++ IN gcsSIZE_PTR SourceSize, ++ IN gctINT Width, ++ IN gctINT Height ++ ); ++ ++gceSTATUS ++gcoVG_EnableDither( ++ IN gcoVG Vg, ++#if GC355_PROFILER ++ IN gctUINT TreeDepth, ++ IN gctUINT saveLayerTreeDepth, ++ IN gctUINT varTreeDepth, ++#endif ++ IN gctBOOL Enable ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_vg_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_enum.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_enum.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_enum.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_enum.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,1605 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_enum_h_ ++#define __gc_hal_enum_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Chip models. */ ++typedef enum _gceCHIPMODEL ++{ ++ gcv200 = 0x0200, ++ gcv300 = 0x0300, ++ gcv320 = 0x0320, ++ gcv328 = 0x0328, ++ gcv350 = 0x0350, ++ gcv355 = 0x0355, ++ gcv400 = 0x0400, ++ gcv410 = 0x0410, ++ gcv420 = 0x0420, ++ gcv428 = 0x0428, ++ gcv450 = 0x0450, ++ gcv500 = 0x0500, ++ gcv520 = 0x0520, ++ gcv530 = 0x0530, ++ gcv600 = 0x0600, ++ gcv700 = 0x0700, ++ gcv800 = 0x0800, ++ gcv860 = 0x0860, ++ gcv880 = 0x0880, ++ gcv1000 = 0x1000, ++ gcv1500 = 0x1500, ++ gcv2000 = 0x2000, ++ gcv2100 = 0x2100, ++ gcv2200 = 0x2200, ++ gcv2500 = 0x2500, ++ gcv3000 = 0x3000, ++ gcv4000 = 0x4000, ++ gcv5000 = 0x5000, ++ gcv5200 = 0x5200, ++ gcv6400 = 0x6400, ++} ++gceCHIPMODEL; ++ ++/* Chip features. */ ++typedef enum _gceFEATURE ++{ ++ gcvFEATURE_PIPE_2D = 0, ++ gcvFEATURE_PIPE_3D, ++ gcvFEATURE_PIPE_VG, ++ gcvFEATURE_DC, ++ gcvFEATURE_HIGH_DYNAMIC_RANGE, ++ gcvFEATURE_MODULE_CG, ++ gcvFEATURE_MIN_AREA, ++ gcvFEATURE_BUFFER_INTERLEAVING, ++ gcvFEATURE_BYTE_WRITE_2D, ++ gcvFEATURE_ENDIANNESS_CONFIG, ++ gcvFEATURE_DUAL_RETURN_BUS, ++ gcvFEATURE_DEBUG_MODE, ++ gcvFEATURE_YUY2_RENDER_TARGET, ++ gcvFEATURE_FRAGMENT_PROCESSOR, ++ gcvFEATURE_2DPE20, ++ gcvFEATURE_FAST_CLEAR, ++ gcvFEATURE_YUV420_TILER, ++ gcvFEATURE_YUY2_AVERAGING, ++ gcvFEATURE_FLIP_Y, ++ gcvFEATURE_EARLY_Z, ++ gcvFEATURE_COMPRESSION, ++ gcvFEATURE_MSAA, ++ gcvFEATURE_SPECIAL_ANTI_ALIASING, ++ gcvFEATURE_SPECIAL_MSAA_LOD, ++ gcvFEATURE_422_TEXTURE_COMPRESSION, ++ gcvFEATURE_DXT_TEXTURE_COMPRESSION, ++ gcvFEATURE_ETC1_TEXTURE_COMPRESSION, ++ gcvFEATURE_CORRECT_TEXTURE_CONVERTER, ++ gcvFEATURE_TEXTURE_8K, ++ gcvFEATURE_SCALER, ++ gcvFEATURE_YUV420_SCALER, ++ gcvFEATURE_SHADER_HAS_W, ++ gcvFEATURE_SHADER_HAS_SIGN, ++ gcvFEATURE_SHADER_HAS_FLOOR, ++ gcvFEATURE_SHADER_HAS_CEIL, ++ gcvFEATURE_SHADER_HAS_SQRT, ++ gcvFEATURE_SHADER_HAS_TRIG, ++ gcvFEATURE_VAA, ++ gcvFEATURE_HZ, ++ gcvFEATURE_CORRECT_STENCIL, ++ gcvFEATURE_VG20, ++ gcvFEATURE_VG_FILTER, ++ gcvFEATURE_VG21, ++ gcvFEATURE_VG_DOUBLE_BUFFER, ++ gcvFEATURE_MC20, ++ gcvFEATURE_SUPER_TILED, ++ gcvFEATURE_FAST_CLEAR_FLUSH, ++ gcvFEATURE_2D_FILTERBLIT_PLUS_ALPHABLEND, ++ gcvFEATURE_2D_DITHER, ++ gcvFEATURE_2D_A8_TARGET, ++ gcvFEATURE_2D_A8_NO_ALPHA, ++ gcvFEATURE_2D_FILTERBLIT_FULLROTATION, ++ gcvFEATURE_2D_BITBLIT_FULLROTATION, ++ gcvFEATURE_WIDE_LINE, ++ gcvFEATURE_FC_FLUSH_STALL, ++ gcvFEATURE_FULL_DIRECTFB, ++ gcvFEATURE_HALF_FLOAT_PIPE, ++ gcvFEATURE_LINE_LOOP, ++ gcvFEATURE_2D_YUV_BLIT, ++ gcvFEATURE_2D_TILING, ++ gcvFEATURE_NON_POWER_OF_TWO, ++ gcvFEATURE_3D_TEXTURE, ++ gcvFEATURE_TEXTURE_ARRAY, ++ gcvFEATURE_TILE_FILLER, ++ gcvFEATURE_LOGIC_OP, ++ gcvFEATURE_COMPOSITION, ++ gcvFEATURE_MIXED_STREAMS, ++ gcvFEATURE_2D_MULTI_SOURCE_BLT, ++ gcvFEATURE_END_EVENT, ++ gcvFEATURE_VERTEX_10_10_10_2, ++ gcvFEATURE_TEXTURE_10_10_10_2, ++ gcvFEATURE_TEXTURE_ANISOTROPIC_FILTERING, ++ gcvFEATURE_TEXTURE_FLOAT_HALF_FLOAT, ++ gcvFEATURE_2D_ROTATION_STALL_FIX, ++ gcvFEATURE_2D_MULTI_SOURCE_BLT_EX, ++ gcvFEATURE_BUG_FIXES10, ++ gcvFEATURE_2D_MINOR_TILING, ++ /* Supertiled compressed textures are supported. */ ++ gcvFEATURE_TEX_COMPRRESSION_SUPERTILED, ++ gcvFEATURE_FAST_MSAA, ++ gcvFEATURE_BUG_FIXED_INDEXED_TRIANGLE_STRIP, ++ gcvFEATURE_TEXTURE_TILE_STATUS_READ, ++ gcvFEATURE_DEPTH_BIAS_FIX, ++ gcvFEATURE_RECT_PRIMITIVE, ++ gcvFEATURE_BUG_FIXES11, ++ gcvFEATURE_SUPERTILED_TEXTURE, ++ gcvFEATURE_2D_NO_COLORBRUSH_INDEX8, ++ gcvFEATURE_RS_YUV_TARGET, ++ gcvFEATURE_2D_FC_SOURCE, ++ gcvFEATURE_2D_CC_NOAA_SOURCE, ++ gcvFEATURE_PE_DITHER_FIX, ++ gcvFEATURE_2D_YUV_SEPARATE_STRIDE, ++ gcvFEATURE_FRUSTUM_CLIP_FIX, ++ gcvFEATURE_TEXTURE_SWIZZLE, ++ gcvFEATURE_PRIMITIVE_RESTART, ++ gcvFEATURE_TEXTURE_LINEAR, ++ gcvFEATURE_TEXTURE_YUV_ASSEMBLER, ++ gcvFEATURE_LINEAR_RENDER_TARGET, ++ gcvFEATURE_SHADER_HAS_ATOMIC, ++ gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE, ++ gcvFEATURE_SHADER_ENHANCEMENTS2, ++ gcvFEATURE_BUG_FIXES7, ++ gcvFEATURE_SHADER_HAS_RTNE, ++ gcvFEATURE_SHADER_HAS_EXTRA_INSTRUCTIONS2, ++ gcvFEATURE_SHADER_ENHANCEMENTS3, ++ gcvFEATURE_DYNAMIC_FREQUENCY_SCALING, ++ gcvFEATURE_SINGLE_BUFFER, ++ gcvFEATURE_OCCLUSION_QUERY, ++ gcvFEATURE_2D_GAMMA, ++ gcvFEATURE_2D_COLOR_SPACE_CONVERSION, ++ gcvFEATURE_2D_SUPER_TILE_VERSION, ++ gcvFEATURE_HALTI0, ++ gcvFEATURE_HALTI1, ++ gcvFEATURE_HALTI2, ++ gcvFEATURE_2D_MIRROR_EXTENSION, ++ gcvFEATURE_TEXTURE_ASTC, ++ gcvFEATURE_2D_SUPER_TILE_V1, ++ gcvFEATURE_2D_SUPER_TILE_V2, ++ gcvFEATURE_2D_SUPER_TILE_V3, ++ gcvFEATURE_2D_MULTI_SOURCE_BLT_EX2, ++ gcvFEATURE_NEW_RA, ++ gcvFEATURE_BUG_FIXED_IMPLICIT_PRIMITIVE_RESTART, ++ gcvFEATURE_PE_MULTI_RT_BLEND_ENABLE_CONTROL, ++ gcvFEATURE_SMALL_MSAA, /* An upgraded version of Fast MSAA */ ++ gcvFEATURE_VERTEX_INST_ID_AS_ATTRIBUTE, ++ gcvFEATURE_DUAL_16, ++ gcvFEATURE_BRANCH_ON_IMMEDIATE_REG, ++ gcvFEATURE_2D_COMPRESSION, ++ gcvFEATURE_TPC_COMPRESSION, ++ gcvFEATURE_2D_OPF_YUV_OUTPUT, ++ gcvFEATURE_2D_FILTERBLIT_A8_ALPHA, ++ gcvFEATURE_2D_MULTI_SRC_BLT_TO_UNIFIED_DST_RECT, ++ gcvFEATURE_V2_COMPRESSION_Z16_FIX, ++ ++ gcvFEATURE_VERTEX_INST_ID_AS_INTEGER, ++ gcvFEATURE_2D_YUV_MODE, ++ gcvFEATURE_ACE, ++ gcvFEATURE_COLOR_COMPRESSION, ++ ++ gcvFEATURE_32BPP_COMPONENT_TEXTURE_CHANNEL_SWIZZLE, ++ gcvFEATURE_64BPP_HW_CLEAR_SUPPORT, ++ gcvFEATURE_TX_LERP_PRECISION_FIX, ++ gcvFEATURE_COMPRESSION_V2, ++ gcvFEATURE_MMU, ++ gcvFEATURE_COMPRESSION_V3, ++ gcvFEATURE_TX_DECOMPRESSOR, ++ gcvFEATURE_MRT_TILE_STATUS_BUFFER, ++ gcvFEATURE_COMPRESSION_V1, ++ gcvFEATURE_V1_COMPRESSION_Z16_DECOMPRESS_FIX, ++ gcvFEATURE_RTT, ++ gcvFEATURE_GENERICS, ++ gcvFEATURE_2D_ONE_PASS_FILTER, ++ gcvFEATURE_2D_ONE_PASS_FILTER_TAP, ++ gcvFEATURE_2D_POST_FLIP, ++ gcvFEATURE_2D_PIXEL_ALIGNMENT, ++ gcvFEATURE_CORRECT_AUTO_DISABLE_COUNT, ++ gcvFEATURE_CORRECT_AUTO_DISABLE_COUNT_WIDTH, ++ ++ gcvFEATURE_HALTI3, ++ gcvFEATURE_EEZ, ++ gcvFEATURE_INTEGER_PIPE_FIX, ++ gcvFEATURE_PSOUTPUT_MAPPING, ++ gcvFEATURE_8K_RT_FIX, ++ gcvFEATURE_TX_TILE_STATUS_MAPPING, ++ gcvFEATURE_SRGB_RT_SUPPORT, ++ gcvFEATURE_UNIFORM_APERTURE, ++ gcvFEATURE_TEXTURE_16K, ++ gcvFEATURE_PA_FARZCLIPPING_FIX, ++ gcvFEATURE_PE_DITHER_COLORMASK_FIX, ++ gcvFEATURE_ZSCALE_FIX, ++ ++ gcvFEATURE_MULTI_PIXELPIPES, ++ gcvFEATURE_PIPE_CL, ++ ++ gcvFEATURE_BUG_FIXES18, ++ ++ gcvFEATURE_UNIFIED_SAMPLERS, ++ gcvFEATURE_CL_PS_WALKER, ++ gcvFEATURE_NEW_HZ, ++ ++ gcvFEATURE_TX_FRAC_PRECISION_6BIT, ++ gcvFEATURE_SH_INSTRUCTION_PREFETCH, ++ gcvFEATURE_PROBE, ++ ++ gcvFEATURE_BUG_FIXES8, ++ gcvFEATURE_2D_ALL_QUAD, ++ ++ gcvFEATURE_SINGLE_PIPE_HALTI1, ++ ++ gcvFEATURE_BLOCK_SIZE_16x16, ++ ++ gcvFEATURE_NO_USER_CSC, ++ gcvFEATURE_ANDROID_ONLY, ++ gcvFEATURE_HAS_PRODUCTID, ++ ++ gcvFEATURE_V2_MSAA_COMP_FIX, ++ ++ gcvFEATURE_S8_ONLY_RENDERING, ++ ++ gcvFEATURE_SEPARATE_SRC_DST, ++ ++ gcvFEATURE_FE_START_VERTEX_SUPPORT, ++ gcvFEATURE_RS_DEPTHSTENCIL_NATIVE_SUPPORT, ++ ++ /* Insert features above this comment only. */ ++ gcvFEATURE_COUNT /* Not a feature. */ ++} ++gceFEATURE; ++ ++/* Chip SWWA. */ ++typedef enum _gceSWWA ++{ ++ gcvSWWA_601 = 0, ++ gcvSWWA_706, ++ gcvSWWA_1163, ++ gcvSWWA_1165, ++ /* Insert SWWA above this comment only. */ ++ gcvSWWA_COUNT /* Not a SWWA. */ ++} ++gceSWWA; ++ ++ ++/* Option Set*/ ++typedef enum _gceOPITON ++{ ++ /* HW setting we take PREFER */ ++ gcvOPTION_PREFER_MULTIPIPE_RS = 0, ++ gcvOPTION_PREFER_ZCONVERT_BYPASS =1, ++ ++ ++ gcvOPTION_HW_NULL = 50, ++ gcvOPTION_PRINT_OPTION = 51, ++ ++ gcvOPTION_FBO_PREFER_MEM = 80, ++ ++ /* Insert option above this comment only */ ++ gcvOPTION_COUNT /* Not a OPTION*/ ++} ++gceOPTION; ++ ++typedef enum _gceFRAMEINFO ++{ ++ gcvFRAMEINFO_FRAME_NUM = 0, ++ gcvFRAMEINFO_DRAW_NUM = 1, ++ gcvFRAMEINFO_DRAW_DUAL16_NUM = 2, ++ gcvFRAMEINFO_DRAW_FL32_NUM = 3, ++ ++ ++ gcvFRAMEINFO_COUNT, ++} ++gceFRAMEINFO; ++ ++typedef enum _gceFRAMEINFO_OP ++{ ++ gcvFRAMEINFO_OP_INC = 0, ++ gcvFRAMEINFO_OP_DEC = 1, ++ gcvFRAMEINFO_OP_ZERO = 2, ++ gcvFRAMEINFO_OP_GET = 3, ++ ++ ++ gcvFRAMEINFO_OP_COUNT, ++} ++gceFRAMEINFO_OP; ++ ++ ++/* Chip Power Status. */ ++typedef enum _gceCHIPPOWERSTATE ++{ ++ gcvPOWER_ON = 0, ++ gcvPOWER_OFF, ++ gcvPOWER_IDLE, ++ gcvPOWER_SUSPEND, ++ gcvPOWER_SUSPEND_ATPOWERON, ++ gcvPOWER_OFF_ATPOWERON, ++ gcvPOWER_IDLE_BROADCAST, ++ gcvPOWER_SUSPEND_BROADCAST, ++ gcvPOWER_OFF_BROADCAST, ++ gcvPOWER_OFF_RECOVERY, ++ gcvPOWER_OFF_TIMEOUT, ++ gcvPOWER_ON_AUTO ++} ++gceCHIPPOWERSTATE; ++ ++/* CPU cache operations */ ++typedef enum _gceCACHEOPERATION ++{ ++ gcvCACHE_CLEAN = 0x01, ++ gcvCACHE_INVALIDATE = 0x02, ++ gcvCACHE_FLUSH = gcvCACHE_CLEAN | gcvCACHE_INVALIDATE, ++ gcvCACHE_MEMORY_BARRIER = 0x04 ++} ++gceCACHEOPERATION; ++ ++/* Surface types. */ ++typedef enum _gceSURF_TYPE ++{ ++ gcvSURF_TYPE_UNKNOWN = 0, ++ gcvSURF_INDEX, ++ gcvSURF_VERTEX, ++ gcvSURF_TEXTURE, ++ gcvSURF_RENDER_TARGET, ++ gcvSURF_DEPTH, ++ gcvSURF_BITMAP, ++ gcvSURF_TILE_STATUS, ++ gcvSURF_IMAGE, ++ gcvSURF_MASK, ++ gcvSURF_SCISSOR, ++ gcvSURF_HIERARCHICAL_DEPTH, ++ gcvSURF_NUM_TYPES, /* Make sure this is the last one! */ ++ ++ /* Combinations. */ ++ gcvSURF_NO_TILE_STATUS = 0x100, ++ gcvSURF_NO_VIDMEM = 0x200, /* Used to allocate surfaces with no underlying vidmem node. ++ In Android, vidmem node is allocated by another process. */ ++ gcvSURF_CACHEABLE = 0x400, /* Used to allocate a cacheable surface */ ++ ++ gcvSURF_FLIP = 0x800, /* The Resolve Target the will been flip resolve from RT */ ++ ++ gcvSURF_TILE_STATUS_DIRTY = 0x1000, /* Init tile status to all dirty */ ++ ++ gcvSURF_LINEAR = 0x2000, ++ ++ gcvSURF_CREATE_AS_TEXTURE = 0x4000, /* create it as a texture */ ++ ++ gcvSURF_PROTECTED_CONTENT = 0x8000, /* create it as content protected */ ++ ++ /* Create it as no compression, valid on when it has tile status. */ ++ gcvSURF_NO_COMPRESSION = 0x40000, ++ ++ gcvSURF_CONTIGUOUS = 0x20000, /*create it as contiguous */ ++ ++ gcvSURF_TEXTURE_LINEAR = gcvSURF_TEXTURE ++ | gcvSURF_LINEAR, ++ ++ gcvSURF_RENDER_TARGET_LINEAR = gcvSURF_RENDER_TARGET ++ | gcvSURF_LINEAR, ++ ++ gcvSURF_RENDER_TARGET_NO_TILE_STATUS = gcvSURF_RENDER_TARGET ++ | gcvSURF_NO_TILE_STATUS, ++ ++ gcvSURF_RENDER_TARGET_TS_DIRTY = gcvSURF_RENDER_TARGET ++ | gcvSURF_TILE_STATUS_DIRTY, ++ ++ gcvSURF_DEPTH_NO_TILE_STATUS = gcvSURF_DEPTH ++ | gcvSURF_NO_TILE_STATUS, ++ ++ gcvSURF_DEPTH_TS_DIRTY = gcvSURF_DEPTH ++ | gcvSURF_TILE_STATUS_DIRTY, ++ ++ /* Supported surface types with no vidmem node. */ ++ gcvSURF_BITMAP_NO_VIDMEM = gcvSURF_BITMAP ++ | gcvSURF_NO_VIDMEM, ++ ++ gcvSURF_TEXTURE_NO_VIDMEM = gcvSURF_TEXTURE ++ | gcvSURF_NO_VIDMEM, ++ ++ /* Cacheable surface types with no vidmem node. */ ++ gcvSURF_CACHEABLE_BITMAP_NO_VIDMEM = gcvSURF_BITMAP_NO_VIDMEM ++ | gcvSURF_CACHEABLE, ++ ++ gcvSURF_CACHEABLE_BITMAP = gcvSURF_BITMAP ++ | gcvSURF_CACHEABLE, ++ ++ gcvSURF_FLIP_BITMAP = gcvSURF_BITMAP ++ | gcvSURF_FLIP, ++} ++gceSURF_TYPE; ++ ++typedef enum _gceSURF_USAGE ++{ ++ gcvSURF_USAGE_UNKNOWN, ++ gcvSURF_USAGE_RESOLVE_AFTER_CPU, ++ gcvSURF_USAGE_RESOLVE_AFTER_3D ++} ++gceSURF_USAGE; ++ ++typedef enum _gceSURF_COLOR_SPACE ++{ ++ gcvSURF_COLOR_SPACE_UNKNOWN, ++ gcvSURF_COLOR_SPACE_LINEAR, ++ gcvSURF_COLOR_SPACE_NONLINEAR, ++} ++gceSURF_COLOR_SPACE; ++ ++typedef enum _gceSURF_COLOR_TYPE ++{ ++ gcvSURF_COLOR_UNKNOWN = 0, ++ gcvSURF_COLOR_LINEAR = 0x01, ++ gcvSURF_COLOR_ALPHA_PRE = 0x02, ++} ++gceSURF_COLOR_TYPE; ++ ++/* Rotation. */ ++typedef enum _gceSURF_ROTATION ++{ ++ gcvSURF_0_DEGREE = 0, ++ gcvSURF_90_DEGREE, ++ gcvSURF_180_DEGREE, ++ gcvSURF_270_DEGREE, ++ gcvSURF_FLIP_X, ++ gcvSURF_FLIP_Y, ++ ++ gcvSURF_POST_FLIP_X = 0x40000000, ++ gcvSURF_POST_FLIP_Y = 0x80000000, ++} ++gceSURF_ROTATION; ++ ++/* Surface flag */ ++typedef enum _gceSURF_FLAG ++{ ++ /* None flag */ ++ gcvSURF_FLAG_NONE = 0x0, ++ /* content is preserved after swap */ ++ gcvSURF_FLAG_CONTENT_PRESERVED = 0x1, ++ /* content is updated after swap*/ ++ gcvSURF_FLAG_CONTENT_UPDATED = 0x2, ++ /* content is y inverted */ ++ gcvSURF_FLAG_CONTENT_YINVERTED = 0x4, ++ /* content is protected */ ++ gcvSURF_FLAG_CONTENT_PROTECTED = 0x8, ++ /* surface is contiguous. */ ++ gcvSURF_FLAG_CONTIGUOUS = (1 << 4), ++} ++gceSURF_FLAG; ++ ++typedef enum _gceMIPMAP_IMAGE_FORMAT ++{ ++ gcvUNKNOWN_MIPMAP_IMAGE_FORMAT = -2 ++} ++gceMIPMAP_IMAGE_FORMAT; ++ ++/* Surface formats. */ ++typedef enum _gceSURF_FORMAT ++{ ++ /* Unknown format. */ ++ gcvSURF_UNKNOWN = 0, ++ ++ /* Palettized formats. */ ++ gcvSURF_INDEX1 = 100, ++ gcvSURF_INDEX4, ++ gcvSURF_INDEX8, ++ ++ /* RGB formats. */ ++ gcvSURF_A2R2G2B2 = 200, ++ gcvSURF_R3G3B2, ++ gcvSURF_A8R3G3B2, ++ gcvSURF_X4R4G4B4, ++ gcvSURF_A4R4G4B4, ++ gcvSURF_R4G4B4A4, ++ gcvSURF_X1R5G5B5, ++ gcvSURF_A1R5G5B5, ++ gcvSURF_R5G5B5A1, ++ gcvSURF_R5G6B5, ++ gcvSURF_R8G8B8, ++ gcvSURF_X8R8G8B8, ++ gcvSURF_A8R8G8B8, ++ gcvSURF_R8G8B8A8, ++ gcvSURF_G8R8G8B8, ++ gcvSURF_R8G8B8G8, ++ gcvSURF_X2R10G10B10, ++ gcvSURF_A2R10G10B10, ++ gcvSURF_X12R12G12B12, ++ gcvSURF_A12R12G12B12, ++ gcvSURF_X16R16G16B16, ++ gcvSURF_A16R16G16B16, ++ gcvSURF_A32R32G32B32, ++ gcvSURF_R8G8B8X8, ++ gcvSURF_R5G5B5X1, ++ gcvSURF_R4G4B4X4, ++ gcvSURF_X16R16G16B16_2_A8R8G8B8, ++ gcvSURF_A16R16G16B16_2_A8R8G8B8, ++ gcvSURF_A32R32G32B32_2_G32R32F, ++ gcvSURF_A32R32G32B32_4_A8R8G8B8, ++ ++ /* BGR formats. */ ++ gcvSURF_A4B4G4R4 = 300, ++ gcvSURF_A1B5G5R5, ++ gcvSURF_B5G6R5, ++ gcvSURF_B8G8R8, ++ gcvSURF_B16G16R16, ++ gcvSURF_X8B8G8R8, ++ gcvSURF_A8B8G8R8, ++ gcvSURF_A2B10G10R10, ++ gcvSURF_X16B16G16R16, ++ gcvSURF_A16B16G16R16, ++ gcvSURF_B32G32R32, ++ gcvSURF_X32B32G32R32, ++ gcvSURF_A32B32G32R32, ++ gcvSURF_B4G4R4A4, ++ gcvSURF_B5G5R5A1, ++ gcvSURF_B8G8R8X8, ++ gcvSURF_B8G8R8A8, ++ gcvSURF_X4B4G4R4, ++ gcvSURF_X1B5G5R5, ++ gcvSURF_B4G4R4X4, ++ gcvSURF_B5G5R5X1, ++ gcvSURF_X2B10G10R10, ++ gcvSURF_B8G8R8_SNORM, ++ gcvSURF_X8B8G8R8_SNORM, ++ gcvSURF_A8B8G8R8_SNORM, ++ gcvSURF_A8B12G12R12_2_A8R8G8B8, ++ ++ /* Compressed formats. */ ++ gcvSURF_DXT1 = 400, ++ gcvSURF_DXT2, ++ gcvSURF_DXT3, ++ gcvSURF_DXT4, ++ gcvSURF_DXT5, ++ gcvSURF_CXV8U8, ++ gcvSURF_ETC1, ++ gcvSURF_R11_EAC, ++ gcvSURF_SIGNED_R11_EAC, ++ gcvSURF_RG11_EAC, ++ gcvSURF_SIGNED_RG11_EAC, ++ gcvSURF_RGB8_ETC2, ++ gcvSURF_SRGB8_ETC2, ++ gcvSURF_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, ++ gcvSURF_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, ++ gcvSURF_RGBA8_ETC2_EAC, ++ gcvSURF_SRGB8_ALPHA8_ETC2_EAC, ++ ++ /* YUV formats. */ ++ gcvSURF_YUY2 = 500, ++ gcvSURF_UYVY, ++ gcvSURF_YV12, ++ gcvSURF_I420, ++ gcvSURF_NV12, ++ gcvSURF_NV21, ++ gcvSURF_NV16, ++ gcvSURF_NV61, ++ gcvSURF_YVYU, ++ gcvSURF_VYUY, ++ ++ /* Depth formats. */ ++ gcvSURF_D16 = 600, ++ gcvSURF_D24S8, ++ gcvSURF_D32, ++ gcvSURF_D24X8, ++ gcvSURF_D32F, ++ gcvSURF_S8D32F, ++ gcvSURF_S8D32F_1_G32R32F, ++ gcvSURF_S8D32F_2_A8R8G8B8, ++ gcvSURF_D24S8_1_A8R8G8B8, ++ gcvSURF_S8, ++ ++ /* Alpha formats. */ ++ gcvSURF_A4 = 700, ++ gcvSURF_A8, ++ gcvSURF_A12, ++ gcvSURF_A16, ++ gcvSURF_A32, ++ gcvSURF_A1, ++ ++ /* Luminance formats. */ ++ gcvSURF_L4 = 800, ++ gcvSURF_L8, ++ gcvSURF_L12, ++ gcvSURF_L16, ++ gcvSURF_L32, ++ gcvSURF_L1, ++ ++ /* Alpha/Luminance formats. */ ++ gcvSURF_A4L4 = 900, ++ gcvSURF_A2L6, ++ gcvSURF_A8L8, ++ gcvSURF_A4L12, ++ gcvSURF_A12L12, ++ gcvSURF_A16L16, ++ ++ /* Bump formats. */ ++ gcvSURF_L6V5U5 = 1000, ++ gcvSURF_V8U8, ++ gcvSURF_X8L8V8U8, ++ gcvSURF_Q8W8V8U8, ++ gcvSURF_A2W10V10U10, ++ gcvSURF_V16U16, ++ gcvSURF_Q16W16V16U16, ++ ++ /* R/RG/RA formats. */ ++ gcvSURF_R8 = 1100, ++ gcvSURF_X8R8, ++ gcvSURF_G8R8, ++ gcvSURF_X8G8R8, ++ gcvSURF_A8R8, ++ gcvSURF_R16, ++ gcvSURF_X16R16, ++ gcvSURF_G16R16, ++ gcvSURF_X16G16R16, ++ gcvSURF_A16R16, ++ gcvSURF_R32, ++ gcvSURF_X32R32, ++ gcvSURF_G32R32, ++ gcvSURF_X32G32R32, ++ gcvSURF_A32R32, ++ gcvSURF_RG16, ++ gcvSURF_R8_SNORM, ++ gcvSURF_G8R8_SNORM, ++ ++ gcvSURF_R8_1_X8R8G8B8, ++ gcvSURF_G8R8_1_X8R8G8B8, ++ ++ /* Floating point formats. */ ++ gcvSURF_R16F = 1200, ++ gcvSURF_X16R16F, ++ gcvSURF_G16R16F, ++ gcvSURF_X16G16R16F, ++ gcvSURF_B16G16R16F, ++ gcvSURF_X16B16G16R16F, ++ gcvSURF_A16B16G16R16F, ++ gcvSURF_R32F, ++ gcvSURF_X32R32F, ++ gcvSURF_G32R32F, ++ gcvSURF_X32G32R32F, ++ gcvSURF_B32G32R32F, ++ gcvSURF_X32B32G32R32F, ++ gcvSURF_A32B32G32R32F, ++ gcvSURF_A16F, ++ gcvSURF_L16F, ++ gcvSURF_A16L16F, ++ gcvSURF_A16R16F, ++ gcvSURF_A32F, ++ gcvSURF_L32F, ++ gcvSURF_A32L32F, ++ gcvSURF_A32R32F, ++ gcvSURF_E5B9G9R9, ++ gcvSURF_B10G11R11F, ++ ++ gcvSURF_X16B16G16R16F_2_A8R8G8B8, ++ gcvSURF_A16B16G16R16F_2_A8R8G8B8, ++ gcvSURF_G32R32F_2_A8R8G8B8, ++ gcvSURF_X32B32G32R32F_2_G32R32F, ++ gcvSURF_A32B32G32R32F_2_G32R32F, ++ gcvSURF_X32B32G32R32F_4_A8R8G8B8, ++ gcvSURF_A32B32G32R32F_4_A8R8G8B8, ++ ++ gcvSURF_R16F_1_A4R4G4B4, ++ gcvSURF_G16R16F_1_A8R8G8B8, ++ gcvSURF_B16G16R16F_2_A8R8G8B8, ++ ++ gcvSURF_R32F_1_A8R8G8B8, ++ gcvSURF_B32G32R32F_3_A8R8G8B8, ++ ++ gcvSURF_B10G11R11F_1_A8R8G8B8, ++ ++ ++ /* sRGB format. */ ++ gcvSURF_SBGR8 = 1400, ++ gcvSURF_A8_SBGR8, ++ gcvSURF_X8_SBGR8, ++ ++ /* Integer formats. */ ++ gcvSURF_R8I = 1500, ++ gcvSURF_R8UI, ++ gcvSURF_R16I, ++ gcvSURF_R16UI, ++ gcvSURF_R32I, ++ gcvSURF_R32UI, ++ gcvSURF_X8R8I, ++ gcvSURF_G8R8I, ++ gcvSURF_X8R8UI, ++ gcvSURF_G8R8UI, ++ gcvSURF_X16R16I, ++ gcvSURF_G16R16I, ++ gcvSURF_X16R16UI, ++ gcvSURF_G16R16UI, ++ gcvSURF_X32R32I, ++ gcvSURF_G32R32I, ++ gcvSURF_X32R32UI, ++ gcvSURF_G32R32UI, ++ gcvSURF_X8G8R8I, ++ gcvSURF_B8G8R8I, ++ gcvSURF_X8G8R8UI, ++ gcvSURF_B8G8R8UI, ++ gcvSURF_X16G16R16I, ++ gcvSURF_B16G16R16I, ++ gcvSURF_X16G16R16UI, ++ gcvSURF_B16G16R16UI, ++ gcvSURF_X32G32R32I, ++ gcvSURF_B32G32R32I, ++ gcvSURF_X32G32R32UI, ++ gcvSURF_B32G32R32UI, ++ gcvSURF_X8B8G8R8I, ++ gcvSURF_A8B8G8R8I, ++ gcvSURF_X8B8G8R8UI, ++ gcvSURF_A8B8G8R8UI, ++ gcvSURF_X16B16G16R16I, ++ gcvSURF_A16B16G16R16I, ++ gcvSURF_X16B16G16R16UI, ++ gcvSURF_A16B16G16R16UI, ++ gcvSURF_X32B32G32R32I, ++ gcvSURF_A32B32G32R32I, ++ gcvSURF_X32B32G32R32UI, ++ gcvSURF_A32B32G32R32UI, ++ gcvSURF_A2B10G10R10UI, ++ gcvSURF_G32R32I_2_A8R8G8B8, ++ gcvSURF_G32R32UI_2_A8R8G8B8, ++ gcvSURF_X16B16G16R16I_2_A8R8G8B8, ++ gcvSURF_A16B16G16R16I_2_A8R8G8B8, ++ gcvSURF_X16B16G16R16UI_2_A8R8G8B8, ++ gcvSURF_A16B16G16R16UI_2_A8R8G8B8, ++ gcvSURF_X32B32G32R32I_2_G32R32I, ++ gcvSURF_A32B32G32R32I_2_G32R32I, ++ gcvSURF_X32B32G32R32I_3_A8R8G8B8, ++ gcvSURF_A32B32G32R32I_4_A8R8G8B8, ++ gcvSURF_X32B32G32R32UI_2_G32R32UI, ++ gcvSURF_A32B32G32R32UI_2_G32R32UI, ++ gcvSURF_X32B32G32R32UI_3_A8R8G8B8, ++ gcvSURF_A32B32G32R32UI_4_A8R8G8B8, ++ gcvSURF_A2B10G10R10UI_1_A8R8G8B8, ++ gcvSURF_A8B8G8R8I_1_A8R8G8B8, ++ gcvSURF_A8B8G8R8UI_1_A8R8G8B8, ++ gcvSURF_R8I_1_A4R4G4B4, ++ gcvSURF_R8UI_1_A4R4G4B4, ++ gcvSURF_R16I_1_A4R4G4B4, ++ gcvSURF_R16UI_1_A4R4G4B4, ++ gcvSURF_R32I_1_A8R8G8B8, ++ gcvSURF_R32UI_1_A8R8G8B8, ++ gcvSURF_X8R8I_1_A4R4G4B4, ++ gcvSURF_X8R8UI_1_A4R4G4B4, ++ gcvSURF_G8R8I_1_A4R4G4B4, ++ gcvSURF_G8R8UI_1_A4R4G4B4, ++ gcvSURF_X16R16I_1_A4R4G4B4, ++ gcvSURF_X16R16UI_1_A4R4G4B4, ++ gcvSURF_G16R16I_1_A8R8G8B8, ++ gcvSURF_G16R16UI_1_A8R8G8B8, ++ gcvSURF_X32R32I_1_A8R8G8B8, ++ gcvSURF_X32R32UI_1_A8R8G8B8, ++ gcvSURF_X8G8R8I_1_A4R4G4B4, ++ gcvSURF_X8G8R8UI_1_A4R4G4B4, ++ gcvSURF_B8G8R8I_1_A8R8G8B8, ++ gcvSURF_B8G8R8UI_1_A8R8G8B8, ++ gcvSURF_B16G16R16I_2_A8R8G8B8, ++ gcvSURF_B16G16R16UI_2_A8R8G8B8, ++ gcvSURF_B32G32R32I_3_A8R8G8B8, ++ gcvSURF_B32G32R32UI_3_A8R8G8B8, ++ ++ /* ASTC formats. */ ++ gcvSURF_ASTC4x4 = 1600, ++ gcvSURF_ASTC5x4, ++ gcvSURF_ASTC5x5, ++ gcvSURF_ASTC6x5, ++ gcvSURF_ASTC6x6, ++ gcvSURF_ASTC8x5, ++ gcvSURF_ASTC8x6, ++ gcvSURF_ASTC8x8, ++ gcvSURF_ASTC10x5, ++ gcvSURF_ASTC10x6, ++ gcvSURF_ASTC10x8, ++ gcvSURF_ASTC10x10, ++ gcvSURF_ASTC12x10, ++ gcvSURF_ASTC12x12, ++ gcvSURF_ASTC4x4_SRGB, ++ gcvSURF_ASTC5x4_SRGB, ++ gcvSURF_ASTC5x5_SRGB, ++ gcvSURF_ASTC6x5_SRGB, ++ gcvSURF_ASTC6x6_SRGB, ++ gcvSURF_ASTC8x5_SRGB, ++ gcvSURF_ASTC8x6_SRGB, ++ gcvSURF_ASTC8x8_SRGB, ++ gcvSURF_ASTC10x5_SRGB, ++ gcvSURF_ASTC10x6_SRGB, ++ gcvSURF_ASTC10x8_SRGB, ++ gcvSURF_ASTC10x10_SRGB, ++ gcvSURF_ASTC12x10_SRGB, ++ gcvSURF_ASTC12x12_SRGB, ++ ++ gcvSURF_FORMAT_COUNT ++} ++gceSURF_FORMAT; ++ ++/* Format modifiers. */ ++typedef enum _gceSURF_FORMAT_MODE ++{ ++ gcvSURF_FORMAT_OCL = 0x80000000 ++} ++gceSURF_FORMAT_MODE; ++ ++/* Pixel swizzle modes. */ ++typedef enum _gceSURF_SWIZZLE ++{ ++ gcvSURF_NOSWIZZLE = 0, ++ gcvSURF_ARGB, ++ gcvSURF_ABGR, ++ gcvSURF_RGBA, ++ gcvSURF_BGRA ++} ++gceSURF_SWIZZLE; ++ ++/* Transparency modes. */ ++typedef enum _gceSURF_TRANSPARENCY ++{ ++ /* Valid only for PE 1.0 */ ++ gcvSURF_OPAQUE = 0, ++ gcvSURF_SOURCE_MATCH, ++ gcvSURF_SOURCE_MASK, ++ gcvSURF_PATTERN_MASK, ++} ++gceSURF_TRANSPARENCY; ++ ++/* Surface Alignment. */ ++typedef enum _gceSURF_ALIGNMENT ++{ ++ gcvSURF_FOUR = 0, ++ gcvSURF_SIXTEEN, ++ gcvSURF_SUPER_TILED, ++ gcvSURF_SPLIT_TILED, ++ gcvSURF_SPLIT_SUPER_TILED ++} ++gceSURF_ALIGNMENT; ++ ++/* Surface Addressing. */ ++typedef enum _gceSURF_ADDRESSING ++{ ++ gcvSURF_NO_STRIDE_TILED = 0, ++ gcvSURF_NO_STRIDE_LINEAR, ++ gcvSURF_STRIDE_TILED, ++ gcvSURF_STRIDE_LINEAR ++} ++gceSURF_ADDRESSING; ++ ++/* Transparency modes. */ ++typedef enum _gce2D_TRANSPARENCY ++{ ++ /* Valid only for PE 2.0 */ ++ gcv2D_OPAQUE = 0, ++ gcv2D_KEYED, ++ gcv2D_MASKED ++} ++gce2D_TRANSPARENCY; ++ ++/* Mono packing modes. */ ++typedef enum _gceSURF_MONOPACK ++{ ++ gcvSURF_PACKED8 = 0, ++ gcvSURF_PACKED16, ++ gcvSURF_PACKED32, ++ gcvSURF_UNPACKED, ++} ++gceSURF_MONOPACK; ++ ++/* Blending modes. */ ++typedef enum _gceSURF_BLEND_MODE ++{ ++ /* Porter-Duff blending modes. */ ++ /* Fsrc Fdst */ ++ gcvBLEND_CLEAR = 0, /* 0 0 */ ++ gcvBLEND_SRC, /* 1 0 */ ++ gcvBLEND_DST, /* 0 1 */ ++ gcvBLEND_SRC_OVER_DST, /* 1 1 - Asrc */ ++ gcvBLEND_DST_OVER_SRC, /* 1 - Adst 1 */ ++ gcvBLEND_SRC_IN_DST, /* Adst 0 */ ++ gcvBLEND_DST_IN_SRC, /* 0 Asrc */ ++ gcvBLEND_SRC_OUT_DST, /* 1 - Adst 0 */ ++ gcvBLEND_DST_OUT_SRC, /* 0 1 - Asrc */ ++ gcvBLEND_SRC_ATOP_DST, /* Adst 1 - Asrc */ ++ gcvBLEND_DST_ATOP_SRC, /* 1 - Adst Asrc */ ++ gcvBLEND_SRC_XOR_DST, /* 1 - Adst 1 - Asrc */ ++ ++ /* Special blending modes. */ ++ gcvBLEND_SET, /* DST = 1 */ ++ gcvBLEND_SUB /* DST = DST * (1 - SRC) */ ++} ++gceSURF_BLEND_MODE; ++ ++/* Per-pixel alpha modes. */ ++typedef enum _gceSURF_PIXEL_ALPHA_MODE ++{ ++ gcvSURF_PIXEL_ALPHA_STRAIGHT = 0, ++ gcvSURF_PIXEL_ALPHA_INVERSED ++} ++gceSURF_PIXEL_ALPHA_MODE; ++ ++/* Global alpha modes. */ ++typedef enum _gceSURF_GLOBAL_ALPHA_MODE ++{ ++ gcvSURF_GLOBAL_ALPHA_OFF = 0, ++ gcvSURF_GLOBAL_ALPHA_ON, ++ gcvSURF_GLOBAL_ALPHA_SCALE ++} ++gceSURF_GLOBAL_ALPHA_MODE; ++ ++/* Color component modes for alpha blending. */ ++typedef enum _gceSURF_PIXEL_COLOR_MODE ++{ ++ gcvSURF_COLOR_STRAIGHT = 0, ++ gcvSURF_COLOR_MULTIPLY ++} ++gceSURF_PIXEL_COLOR_MODE; ++ ++/* Color component modes for alpha blending. */ ++typedef enum _gce2D_PIXEL_COLOR_MULTIPLY_MODE ++{ ++ gcv2D_COLOR_MULTIPLY_DISABLE = 0, ++ gcv2D_COLOR_MULTIPLY_ENABLE ++} ++gce2D_PIXEL_COLOR_MULTIPLY_MODE; ++ ++/* Color component modes for alpha blending. */ ++typedef enum _gce2D_GLOBAL_COLOR_MULTIPLY_MODE ++{ ++ gcv2D_GLOBAL_COLOR_MULTIPLY_DISABLE = 0, ++ gcv2D_GLOBAL_COLOR_MULTIPLY_ALPHA, ++ gcv2D_GLOBAL_COLOR_MULTIPLY_COLOR ++} ++gce2D_GLOBAL_COLOR_MULTIPLY_MODE; ++ ++/* Alpha blending factor modes. */ ++typedef enum _gceSURF_BLEND_FACTOR_MODE ++{ ++ gcvSURF_BLEND_ZERO = 0, ++ gcvSURF_BLEND_ONE, ++ gcvSURF_BLEND_STRAIGHT, ++ gcvSURF_BLEND_INVERSED, ++ gcvSURF_BLEND_COLOR, ++ gcvSURF_BLEND_COLOR_INVERSED, ++ gcvSURF_BLEND_SRC_ALPHA_SATURATED, ++ gcvSURF_BLEND_STRAIGHT_NO_CROSS, ++ gcvSURF_BLEND_INVERSED_NO_CROSS, ++ gcvSURF_BLEND_COLOR_NO_CROSS, ++ gcvSURF_BLEND_COLOR_INVERSED_NO_CROSS, ++ gcvSURF_BLEND_SRC_ALPHA_SATURATED_CROSS ++} ++gceSURF_BLEND_FACTOR_MODE; ++ ++/* Alpha blending porter duff rules. */ ++typedef enum _gce2D_PORTER_DUFF_RULE ++{ ++ gcvPD_CLEAR = 0, ++ gcvPD_SRC, ++ gcvPD_SRC_OVER, ++ gcvPD_DST_OVER, ++ gcvPD_SRC_IN, ++ gcvPD_DST_IN, ++ gcvPD_SRC_OUT, ++ gcvPD_DST_OUT, ++ gcvPD_SRC_ATOP, ++ gcvPD_DST_ATOP, ++ gcvPD_ADD, ++ gcvPD_XOR, ++ gcvPD_DST ++} ++gce2D_PORTER_DUFF_RULE; ++ ++/* Alpha blending factor modes. */ ++typedef enum _gce2D_YUV_COLOR_MODE ++{ ++ gcv2D_YUV_601= 0, ++ gcv2D_YUV_709, ++ gcv2D_YUV_USER_DEFINED, ++ gcv2D_YUV_USER_DEFINED_CLAMP, ++ ++ /* Default setting is for src. gcv2D_YUV_DST ++ can be ORed to set dst. ++ */ ++ gcv2D_YUV_DST = 0x80000000, ++} ++gce2D_YUV_COLOR_MODE; ++ ++typedef enum _gce2D_COMMAND ++{ ++ gcv2D_CLEAR = 0, ++ gcv2D_LINE, ++ gcv2D_BLT, ++ gcv2D_STRETCH, ++ gcv2D_HOR_FILTER, ++ gcv2D_VER_FILTER, ++ gcv2D_MULTI_SOURCE_BLT, ++ gcv2D_FILTER_BLT, ++} ++gce2D_COMMAND; ++ ++typedef enum _gce2D_TILE_STATUS_CONFIG ++{ ++ gcv2D_TSC_DISABLE = 0, ++ gcv2D_TSC_ENABLE = 0x00000001, ++ gcv2D_TSC_COMPRESSED = 0x00000002, ++ gcv2D_TSC_DOWN_SAMPLER = 0x00000004, ++ gcv2D_TSC_2D_COMPRESSED = 0x00000008, ++ gcv2D_TSC_TPC_COMPRESSED = 0x00000010, ++} ++gce2D_TILE_STATUS_CONFIG; ++ ++typedef enum _gce2D_QUERY ++{ ++ gcv2D_QUERY_RGB_ADDRESS_MIN_ALIGN = 0, ++ gcv2D_QUERY_RGB_STRIDE_MIN_ALIGN, ++ gcv2D_QUERY_YUV_ADDRESS_MIN_ALIGN, ++ gcv2D_QUERY_YUV_STRIDE_MIN_ALIGN, ++} ++gce2D_QUERY; ++ ++typedef enum _gce2D_SUPER_TILE_VERSION ++{ ++ gcv2D_SUPER_TILE_VERSION_V1 = 1, ++ gcv2D_SUPER_TILE_VERSION_V2 = 2, ++ gcv2D_SUPER_TILE_VERSION_V3 = 3, ++} ++gce2D_SUPER_TILE_VERSION; ++ ++typedef enum _gce2D_STATE ++{ ++ gcv2D_STATE_SPECIAL_FILTER_MIRROR_MODE = 1, ++ gcv2D_STATE_SUPER_TILE_VERSION, ++ gcv2D_STATE_EN_GAMMA, ++ gcv2D_STATE_DE_GAMMA, ++ gcv2D_STATE_MULTI_SRC_BLIT_UNIFIED_DST_RECT, ++ gcv2D_STATE_PROFILE_ENABLE, ++ gcv2D_STATE_XRGB_ENABLE, ++ ++ gcv2D_STATE_ARRAY_EN_GAMMA = 0x10001, ++ gcv2D_STATE_ARRAY_DE_GAMMA, ++ gcv2D_STATE_ARRAY_CSC_YUV_TO_RGB, ++ gcv2D_STATE_ARRAY_CSC_RGB_TO_YUV, ++} ++gce2D_STATE; ++ ++typedef enum _gce2D_STATE_PROFILE ++{ ++ gcv2D_STATE_PROFILE_NONE = 0x0, ++ gcv2D_STATE_PROFILE_COMMAND = 0x1, ++ gcv2D_STATE_PROFILE_SURFACE = 0x2, ++ gcv2D_STATE_PROFILE_ALL = 0xFFFF, ++} ++gce2D_STATE_PROFILE; ++ ++/* Texture object types */ ++typedef enum _gceTEXTURE_TYPE ++{ ++ gcvTEXTURE_UNKNOWN = 0, ++ gcvTEXTURE_1D, ++ gcvTEXTURE_2D, ++ gcvTEXTURE_3D, ++ gcvTEXTURE_CUBEMAP, ++ gcvTEXTURE_1D_ARRAY, ++ gcvTEXTURE_2D_ARRAY, ++ gcvTEXTURE_EXTERNAL ++} ++gceTEXTURE_TYPE; ++ ++#if gcdENABLE_3D ++/* Texture functions. */ ++typedef enum _gceTEXTURE_FUNCTION ++{ ++ gcvTEXTURE_DUMMY = 0, ++ gcvTEXTURE_REPLACE = 0, ++ gcvTEXTURE_MODULATE, ++ gcvTEXTURE_ADD, ++ gcvTEXTURE_ADD_SIGNED, ++ gcvTEXTURE_INTERPOLATE, ++ gcvTEXTURE_SUBTRACT, ++ gcvTEXTURE_DOT3 ++} ++gceTEXTURE_FUNCTION; ++ ++/* Texture sources. */ ++typedef enum _gceTEXTURE_SOURCE ++{ ++ gcvCOLOR_FROM_TEXTURE = 0, ++ gcvCOLOR_FROM_CONSTANT_COLOR, ++ gcvCOLOR_FROM_PRIMARY_COLOR, ++ gcvCOLOR_FROM_PREVIOUS_COLOR ++} ++gceTEXTURE_SOURCE; ++ ++/* Texture source channels. */ ++typedef enum _gceTEXTURE_CHANNEL ++{ ++ gcvFROM_COLOR = 0, ++ gcvFROM_ONE_MINUS_COLOR, ++ gcvFROM_ALPHA, ++ gcvFROM_ONE_MINUS_ALPHA ++} ++gceTEXTURE_CHANNEL; ++#endif /* gcdENABLE_3D */ ++ ++/* Filter types. */ ++typedef enum _gceFILTER_TYPE ++{ ++ gcvFILTER_SYNC = 0, ++ gcvFILTER_BLUR, ++ gcvFILTER_USER ++} ++gceFILTER_TYPE; ++ ++/* Filter pass types. */ ++typedef enum _gceFILTER_PASS_TYPE ++{ ++ gcvFILTER_HOR_PASS = 0, ++ gcvFILTER_VER_PASS ++} ++gceFILTER_PASS_TYPE; ++ ++/* Endian hints. */ ++typedef enum _gceENDIAN_HINT ++{ ++ gcvENDIAN_NO_SWAP = 0, ++ gcvENDIAN_SWAP_WORD, ++ gcvENDIAN_SWAP_DWORD ++} ++gceENDIAN_HINT; ++ ++/* Tiling modes. */ ++typedef enum _gceTILING ++{ ++ gcvINVALIDTILED = 0x0, /* Invalid tiling */ ++ /* Tiling basic modes enum'ed in power of 2. */ ++ gcvLINEAR = 0x1, /* No tiling. */ ++ gcvTILED = 0x2, /* 4x4 tiling. */ ++ gcvSUPERTILED = 0x4, /* 64x64 tiling. */ ++ gcvMINORTILED = 0x8, /* 2x2 tiling. */ ++ ++ /* Tiling special layouts. */ ++ gcvTILING_SPLIT_BUFFER = 0x100, ++ ++ /* Tiling combination layouts. */ ++ gcvMULTI_TILED = gcvTILED ++ | gcvTILING_SPLIT_BUFFER, ++ ++ gcvMULTI_SUPERTILED = gcvSUPERTILED ++ | gcvTILING_SPLIT_BUFFER, ++} ++gceTILING; ++ ++/* 2D pattern type. */ ++typedef enum _gce2D_PATTERN ++{ ++ gcv2D_PATTERN_SOLID = 0, ++ gcv2D_PATTERN_MONO, ++ gcv2D_PATTERN_COLOR, ++ gcv2D_PATTERN_INVALID ++} ++gce2D_PATTERN; ++ ++/* 2D source type. */ ++typedef enum _gce2D_SOURCE ++{ ++ gcv2D_SOURCE_MASKED = 0, ++ gcv2D_SOURCE_MONO, ++ gcv2D_SOURCE_COLOR, ++ gcv2D_SOURCE_INVALID ++} ++gce2D_SOURCE; ++ ++/* Pipes. */ ++typedef enum _gcePIPE_SELECT ++{ ++ gcvPIPE_INVALID = ~0, ++ gcvPIPE_3D = 0, ++ gcvPIPE_2D ++} ++gcePIPE_SELECT; ++ ++/* Hardware type. */ ++typedef enum _gceHARDWARE_TYPE ++{ ++ gcvHARDWARE_INVALID = 0x00, ++ gcvHARDWARE_3D = 0x01, ++ gcvHARDWARE_2D = 0x02, ++ gcvHARDWARE_VG = 0x04, ++ gcvHARDWARE_3D2D = gcvHARDWARE_3D | gcvHARDWARE_2D ++} ++gceHARDWARE_TYPE; ++ ++#define gcdCHIP_COUNT 3 ++ ++typedef enum _gceMMU_MODE ++{ ++ gcvMMU_MODE_1K, ++ gcvMMU_MODE_4K, ++} gceMMU_MODE; ++ ++/* User signal command codes. */ ++typedef enum _gceUSER_SIGNAL_COMMAND_CODES ++{ ++ gcvUSER_SIGNAL_CREATE, ++ gcvUSER_SIGNAL_DESTROY, ++ gcvUSER_SIGNAL_SIGNAL, ++ gcvUSER_SIGNAL_WAIT, ++ gcvUSER_SIGNAL_MAP, ++ gcvUSER_SIGNAL_UNMAP, ++} ++gceUSER_SIGNAL_COMMAND_CODES; ++ ++/* Sync point command codes. */ ++typedef enum _gceSYNC_POINT_COMMAND_CODES ++{ ++ gcvSYNC_POINT_CREATE, ++ gcvSYNC_POINT_DESTROY, ++ gcvSYNC_POINT_SIGNAL, ++} ++gceSYNC_POINT_COMMAND_CODES; ++ ++/* Shared buffer command codes. */ ++typedef enum _gceSHBUF_COMMAND_CODES ++{ ++ gcvSHBUF_CREATE, ++ gcvSHBUF_DESTROY, ++ gcvSHBUF_MAP, ++ gcvSHBUF_WRITE, ++ gcvSHBUF_READ, ++} ++gceSHBUF_COMMAND_CODES; ++ ++/* Event locations. */ ++typedef enum _gceKERNEL_WHERE ++{ ++ gcvKERNEL_COMMAND, ++ gcvKERNEL_VERTEX, ++ gcvKERNEL_TRIANGLE, ++ gcvKERNEL_TEXTURE, ++ gcvKERNEL_PIXEL, ++} ++gceKERNEL_WHERE; ++ ++#if gcdENABLE_VG ++/* Hardware blocks. */ ++typedef enum _gceBLOCK ++{ ++ gcvBLOCK_COMMAND, ++ gcvBLOCK_TESSELLATOR, ++ gcvBLOCK_TESSELLATOR2, ++ gcvBLOCK_TESSELLATOR3, ++ gcvBLOCK_RASTER, ++ gcvBLOCK_VG, ++ gcvBLOCK_VG2, ++ gcvBLOCK_VG3, ++ gcvBLOCK_PIXEL, ++ ++ /* Number of defined blocks. */ ++ gcvBLOCK_COUNT ++} ++gceBLOCK; ++#endif ++ ++/* gcdDUMP message type. */ ++typedef enum _gceDEBUG_MESSAGE_TYPE ++{ ++ gcvMESSAGE_TEXT, ++ gcvMESSAGE_DUMP ++} ++gceDEBUG_MESSAGE_TYPE; ++ ++/* Shading format. */ ++typedef enum _gceSHADING ++{ ++ gcvSHADING_SMOOTH, ++ gcvSHADING_FLAT_D3D, ++ gcvSHADING_FLAT_OPENGL, ++} ++gceSHADING; ++ ++/* Culling modes. */ ++typedef enum _gceCULL ++{ ++ gcvCULL_NONE, ++ gcvCULL_CCW, ++ gcvCULL_CW, ++} ++gceCULL; ++ ++/* Fill modes. */ ++typedef enum _gceFILL ++{ ++ gcvFILL_POINT, ++ gcvFILL_WIRE_FRAME, ++ gcvFILL_SOLID, ++} ++gceFILL; ++ ++/* Compare modes. */ ++typedef enum _gceCOMPARE ++{ ++ gcvCOMPARE_INVALID = 0, ++ gcvCOMPARE_NEVER, ++ gcvCOMPARE_NOT_EQUAL, ++ gcvCOMPARE_LESS, ++ gcvCOMPARE_LESS_OR_EQUAL, ++ gcvCOMPARE_EQUAL, ++ gcvCOMPARE_GREATER, ++ gcvCOMPARE_GREATER_OR_EQUAL, ++ gcvCOMPARE_ALWAYS, ++} ++gceCOMPARE; ++ ++/* Stencil modes. */ ++typedef enum _gceSTENCIL_MODE ++{ ++ gcvSTENCIL_NONE, ++ gcvSTENCIL_SINGLE_SIDED, ++ gcvSTENCIL_DOUBLE_SIDED, ++} ++gceSTENCIL_MODE; ++ ++/* Stencil operations. */ ++typedef enum _gceSTENCIL_OPERATION ++{ ++ gcvSTENCIL_KEEP, ++ gcvSTENCIL_REPLACE, ++ gcvSTENCIL_ZERO, ++ gcvSTENCIL_INVERT, ++ gcvSTENCIL_INCREMENT, ++ gcvSTENCIL_DECREMENT, ++ gcvSTENCIL_INCREMENT_SATURATE, ++ gcvSTENCIL_DECREMENT_SATURATE, ++ gcvSTENCIL_OPERATION_INVALID = -1 ++} ++gceSTENCIL_OPERATION; ++ ++/* Stencil selection. */ ++typedef enum _gceSTENCIL_WHERE ++{ ++ gcvSTENCIL_FRONT, ++ gcvSTENCIL_BACK, ++} ++gceSTENCIL_WHERE; ++ ++/* Texture addressing selection. */ ++typedef enum _gceTEXTURE_WHICH ++{ ++ gcvTEXTURE_S, ++ gcvTEXTURE_T, ++ gcvTEXTURE_R, ++} ++gceTEXTURE_WHICH; ++ ++/* Texture addressing modes. */ ++typedef enum _gceTEXTURE_ADDRESSING ++{ ++ gcvTEXTURE_INVALID = 0, ++ gcvTEXTURE_CLAMP, ++ gcvTEXTURE_WRAP, ++ gcvTEXTURE_MIRROR, ++ gcvTEXTURE_BORDER, ++ gcvTEXTURE_MIRROR_ONCE, ++} ++gceTEXTURE_ADDRESSING; ++ ++/* Texture filters. */ ++typedef enum _gceTEXTURE_FILTER ++{ ++ gcvTEXTURE_NONE, ++ gcvTEXTURE_POINT, ++ gcvTEXTURE_LINEAR, ++ gcvTEXTURE_ANISOTROPIC, ++} ++gceTEXTURE_FILTER; ++ ++typedef enum _gceTEXTURE_COMPONENT ++{ ++ gcvTEXTURE_COMPONENT_R, ++ gcvTEXTURE_COMPONENT_G, ++ gcvTEXTURE_COMPONENT_B, ++ gcvTEXTURE_COMPONENT_A, ++ ++ gcvTEXTURE_COMPONENT_NUM, ++} gceTEXTURE_COMPONENT; ++ ++/* Texture swizzle modes. */ ++typedef enum _gceTEXTURE_SWIZZLE ++{ ++ gcvTEXTURE_SWIZZLE_R = 0, ++ gcvTEXTURE_SWIZZLE_G, ++ gcvTEXTURE_SWIZZLE_B, ++ gcvTEXTURE_SWIZZLE_A, ++ gcvTEXTURE_SWIZZLE_0, ++ gcvTEXTURE_SWIZZLE_1, ++ ++ gcvTEXTURE_SWIZZLE_INVALID, ++} gceTEXTURE_SWIZZLE; ++ ++typedef enum _gceTEXTURE_COMPARE_MODE ++{ ++ gcvTEXTURE_COMPARE_MODE_INVALID = 0, ++ gcvTEXTURE_COMPARE_MODE_NONE, ++ gcvTEXTURE_COMPARE_MODE_REF, ++} gceTEXTURE_COMPARE_MODE; ++ ++/* Pixel output swizzle modes. */ ++typedef enum _gcePIXEL_SWIZZLE ++{ ++ gcvPIXEL_SWIZZLE_R = gcvTEXTURE_SWIZZLE_R, ++ gcvPIXEL_SWIZZLE_G = gcvTEXTURE_SWIZZLE_G, ++ gcvPIXEL_SWIZZLE_B = gcvTEXTURE_SWIZZLE_B, ++ gcvPIXEL_SWIZZLE_A = gcvTEXTURE_SWIZZLE_A, ++ ++ gcvPIXEL_SWIZZLE_INVALID, ++} gcePIXEL_SWIZZLE; ++ ++/* Primitive types. */ ++typedef enum _gcePRIMITIVE ++{ ++ gcvPRIMITIVE_POINT_LIST, ++ gcvPRIMITIVE_LINE_LIST, ++ gcvPRIMITIVE_LINE_STRIP, ++ gcvPRIMITIVE_LINE_LOOP, ++ gcvPRIMITIVE_TRIANGLE_LIST, ++ gcvPRIMITIVE_TRIANGLE_STRIP, ++ gcvPRIMITIVE_TRIANGLE_FAN, ++ gcvPRIMITIVE_RECTANGLE, ++} ++gcePRIMITIVE; ++ ++/* Index types. */ ++typedef enum _gceINDEX_TYPE ++{ ++ gcvINDEX_8, ++ gcvINDEX_16, ++ gcvINDEX_32, ++} ++gceINDEX_TYPE; ++ ++/* Multi GPU rendering modes. */ ++typedef enum _gceMULTI_GPU_RENDERING_MODE ++{ ++ gcvMULTI_GPU_RENDERING_MODE_OFF, ++ gcvMULTI_GPU_RENDERING_MODE_SPLIT_WIDTH, ++ gcvMULTI_GPU_RENDERING_MODE_SPLIT_HEIGHT, ++ gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_64x64, ++ gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_128x64, ++ gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_128x128 ++} ++gceMULTI_GPU_RENDERING_MODE; ++ ++typedef enum _gceCORE_3D_MASK ++{ ++ gcvCORE_3D_0_MASK = (1 << 0), ++ gcvCORE_3D_1_MASK = (1 << 1), ++ ++ gcvCORE_3D_ALL_MASK = (0xFFFF) ++} ++gceCORE_3D_MASK; ++ ++typedef enum _gceCORE_3D_ID ++{ ++ gcvCORE_3D_0_ID = 0, ++ gcvCORE_3D_1_ID = 1, ++ ++ gcvCORE_3D_ID_INVALID = ~0UL ++} ++gceCORE_3D_ID; ++ ++typedef enum _gceMULTI_GPU_MODE ++{ ++ gcvMULTI_GPU_MODE_COMBINED = 0, ++ gcvMULTI_GPU_MODE_INDEPENDENT = 1 ++} ++gceMULTI_GPU_MODE; ++ ++typedef enum _gceMACHINECODE ++{ ++ gcvMACHINECODE_ANTUTU0 = 0x0, ++ ++ gcvMACHINECODE_GLB27_RELEASE_0, ++ ++ gcvMACHINECODE_GLB25_RELEASE_0, ++ gcvMACHINECODE_GLB25_RELEASE_1, ++ gcvMACHINECODE_GLB25_RELEASE_2, ++ ++ /* keep it as the last enum */ ++ gcvMACHINECODE_COUNT ++} ++gceMACHINECODE; ++ ++typedef enum _gceUNIFORMCVT ++{ ++ gcvUNIFORMCVT_NONE = 0, ++ gcvUNIFORMCVT_TO_BOOL, ++ gcvUNIFORMCVT_TO_FLOAT, ++} gceUNIFORMCVT; ++ ++typedef enum _gceHAL_ARG_VERSION ++{ ++ gcvHAL_ARG_VERSION_V1 = 0x0, ++} ++gceHAL_ARG_VERSION; ++ ++ ++/* ++* Bit of a requirment is 1 means requirement is a must, 0 means requirement can ++* be ignored. ++*/ ++#define gcvALLOC_FLAG_CONTIGUOUS_BIT 0 ++#define gcvALLOC_FLAG_CACHEABLE_BIT 1 ++#define gcvALLOC_FLAG_SECURITY_BIT 2 ++#define gcvALLOC_FLAG_NON_CONTIGUOUS_BIT 3 ++#define gcvALLOC_FLAG_MEMLIMIT_BIT 4 ++ ++/* No special needs. */ ++#define gcvALLOC_FLAG_NONE (0) ++/* Physical contiguous. */ ++#define gcvALLOC_FLAG_CONTIGUOUS (1 << gcvALLOC_FLAG_CONTIGUOUS_BIT) ++/* Can be remapped as cacheable. */ ++#define gcvALLOC_FLAG_CACHEABLE (1 << gcvALLOC_FLAG_CACHEABLE_BIT) ++/* Secure buffer. */ ++#define gcvALLOC_FLAG_SECURITY (1 << gcvALLOC_FLAG_SECURITY_BIT) ++/* Physical non contiguous. */ ++#define gcvALLOC_FLAG_NON_CONTIGUOUS (1 << gcvALLOC_FLAG_NON_CONTIGUOUS_BIT) ++#define gcvALLOC_FLAG_MEMLIMIT (1 << gcvALLOC_FLAG_MEMLIMIT_BIT) ++ ++/* GL_VIV internal usage */ ++#ifndef GL_MAP_BUFFER_OBJ_VIV ++#define GL_MAP_BUFFER_OBJ_VIV 0x10000 ++#endif ++ ++/* Command buffer usage. */ ++#define gcvCOMMAND_2D (1 << 0) ++#define gcvCOMMAND_3D (1 << 1) ++ ++/******************************************************************************\ ++****************************** Object Declarations ***************************** ++\******************************************************************************/ ++ ++typedef struct _gckCONTEXT * gckCONTEXT; ++typedef struct _gcoCMDBUF * gcoCMDBUF; ++ ++typedef struct _gcsSTATE_DELTA * gcsSTATE_DELTA_PTR; ++typedef struct _gcsQUEUE * gcsQUEUE_PTR; ++typedef struct _gcoQUEUE * gcoQUEUE; ++typedef struct _gcsHAL_INTERFACE * gcsHAL_INTERFACE_PTR; ++typedef struct _gcs2D_PROFILE * gcs2D_PROFILE_PTR; ++ ++#if gcdENABLE_VG ++typedef struct _gcoVGHARDWARE * gcoVGHARDWARE; ++typedef struct _gcoVGBUFFER * gcoVGBUFFER; ++typedef struct _gckVGHARDWARE * gckVGHARDWARE; ++typedef struct _gcsVGCONTEXT * gcsVGCONTEXT_PTR; ++typedef struct _gcsVGCONTEXT_MAP * gcsVGCONTEXT_MAP_PTR; ++typedef struct _gcsVGCMDQUEUE * gcsVGCMDQUEUE_PTR; ++typedef struct _gcsTASK_MASTER_TABLE * gcsTASK_MASTER_TABLE_PTR; ++typedef struct _gckVGKERNEL * gckVGKERNEL; ++typedef void * gctTHREAD; ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_enum_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,2677 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_h_ ++#define __gc_hal_h_ ++ ++#include "gc_hal_rename.h" ++#include "gc_hal_types.h" ++#include "gc_hal_enum.h" ++#include "gc_hal_base.h" ++#include "gc_hal_profiler.h" ++#include "gc_hal_driver.h" ++#if gcdENABLE_3D ++#include "gc_hal_statistics.h" ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++******************************* Alignment Macros ******************************* ++\******************************************************************************/ ++ ++/* Alignment with a non-power of two value. */ ++#define gcmALIGN_NP2(n, align) \ ++( \ ++ ((n) + (align) - 1) - (((n) + (align) - 1) % (align)) \ ++) ++ ++/* Alignment with a power of two value. */ ++#define gcmALIGN(n, align) \ ++( \ ++ ((n) + ((align) - 1)) & ~((align) - 1) \ ++) ++ ++#define gcmALIGN_BASE(n, align) \ ++( \ ++ ((n) & ~((align) - 1)) \ ++) ++ ++/******************************************************************************\ ++***************************** Element Count Macro ***************************** ++\******************************************************************************/ ++ ++#define gcmSIZEOF(a) \ ++( \ ++ (gctSIZE_T) (sizeof(a)) \ ++) ++ ++#define gcmCOUNTOF(a) \ ++( \ ++ sizeof(a) / sizeof(a[0]) \ ++) ++ ++/******************************************************************************\ ++********************************* Cast Macro ********************************** ++\******************************************************************************/ ++#define gcmNAME_TO_PTR(na) \ ++ gckKERNEL_QueryPointerFromName(kernel, gcmALL_TO_UINT32(na)) ++ ++#define gcmPTR_TO_NAME(ptr) \ ++ gckKERNEL_AllocateNameFromPointer(kernel, ptr) ++ ++#define gcmRELEASE_NAME(na) \ ++ gckKERNEL_DeleteName(kernel, gcmALL_TO_UINT32(na)) ++ ++#define gcmALL_TO_UINT32(t) \ ++( \ ++ (gctUINT32) (gctUINTPTR_T) (t)\ ++) ++ ++#define gcmPTR_TO_UINT64(p) \ ++( \ ++ (gctUINT64) (gctUINTPTR_T) (p)\ ++) ++ ++#define gcmUINT64_TO_PTR(u) \ ++( \ ++ (gctPOINTER) (gctUINTPTR_T) (u)\ ++) ++ ++#define gcmUINT64_TO_TYPE(u, t) \ ++( \ ++ (t) (gctUINTPTR_T) (u)\ ++) ++ ++/******************************************************************************\ ++******************************** Useful Macro ********************************* ++\******************************************************************************/ ++ ++#define gcvINVALID_ADDRESS ~0U ++ ++#define gcmGET_PRE_ROTATION(rotate) \ ++ ((rotate) & (~(gcvSURF_POST_FLIP_X | gcvSURF_POST_FLIP_Y))) ++ ++#define gcmGET_POST_ROTATION(rotate) \ ++ ((rotate) & (gcvSURF_POST_FLIP_X | gcvSURF_POST_FLIP_Y)) ++ ++/******************************************************************************\ ++******************************** gcsOBJECT Object ******************************* ++\******************************************************************************/ ++ ++/* Type of objects. */ ++typedef enum _gceOBJECT_TYPE ++{ ++ gcvOBJ_UNKNOWN = 0, ++ gcvOBJ_2D = gcmCC('2','D',' ',' '), ++ gcvOBJ_3D = gcmCC('3','D',' ',' '), ++ gcvOBJ_ATTRIBUTE = gcmCC('A','T','T','R'), ++ gcvOBJ_BRUSHCACHE = gcmCC('B','R','U','$'), ++ gcvOBJ_BRUSHNODE = gcmCC('B','R','U','n'), ++ gcvOBJ_BRUSH = gcmCC('B','R','U','o'), ++ gcvOBJ_BUFFER = gcmCC('B','U','F','R'), ++ gcvOBJ_COMMAND = gcmCC('C','M','D',' '), ++ gcvOBJ_COMMANDBUFFER = gcmCC('C','M','D','B'), ++ gcvOBJ_CONTEXT = gcmCC('C','T','X','T'), ++ gcvOBJ_DEVICE = gcmCC('D','E','V',' '), ++ gcvOBJ_DUMP = gcmCC('D','U','M','P'), ++ gcvOBJ_EVENT = gcmCC('E','V','N','T'), ++ gcvOBJ_FUNCTION = gcmCC('F','U','N','C'), ++ gcvOBJ_HAL = gcmCC('H','A','L',' '), ++ gcvOBJ_HARDWARE = gcmCC('H','A','R','D'), ++ gcvOBJ_HEAP = gcmCC('H','E','A','P'), ++ gcvOBJ_INDEX = gcmCC('I','N','D','X'), ++ gcvOBJ_INTERRUPT = gcmCC('I','N','T','R'), ++ gcvOBJ_KERNEL = gcmCC('K','E','R','N'), ++ gcvOBJ_KERNEL_FUNCTION = gcmCC('K','F','C','N'), ++ gcvOBJ_MEMORYBUFFER = gcmCC('M','E','M','B'), ++ gcvOBJ_MMU = gcmCC('M','M','U',' '), ++ gcvOBJ_OS = gcmCC('O','S',' ',' '), ++ gcvOBJ_OUTPUT = gcmCC('O','U','T','P'), ++ gcvOBJ_PAINT = gcmCC('P','N','T',' '), ++ gcvOBJ_PATH = gcmCC('P','A','T','H'), ++ gcvOBJ_QUEUE = gcmCC('Q','U','E',' '), ++ gcvOBJ_SAMPLER = gcmCC('S','A','M','P'), ++ gcvOBJ_SHADER = gcmCC('S','H','D','R'), ++ gcvOBJ_STREAM = gcmCC('S','T','R','M'), ++ gcvOBJ_SURF = gcmCC('S','U','R','F'), ++ gcvOBJ_TEXTURE = gcmCC('T','X','T','R'), ++ gcvOBJ_UNIFORM = gcmCC('U','N','I','F'), ++ gcvOBJ_VARIABLE = gcmCC('V','A','R','I'), ++ gcvOBJ_VERTEX = gcmCC('V','R','T','X'), ++ gcvOBJ_VIDMEM = gcmCC('V','M','E','M'), ++ gcvOBJ_VG = gcmCC('V','G',' ',' '), ++ gcvOBJ_BUFOBJ = gcmCC('B','U','F','O'), ++ gcvOBJ_UNIFORM_BLOCK = gcmCC('U','B','L','K'), ++ gcvOBJ_CL = gcmCC('C','L',' ',' '), ++} ++gceOBJECT_TYPE; ++ ++/* gcsOBJECT object defintinon. */ ++typedef struct _gcsOBJECT ++{ ++ /* Type of an object. */ ++ gceOBJECT_TYPE type; ++} ++gcsOBJECT; ++ ++typedef struct _gckHARDWARE * gckHARDWARE; ++ ++/* CORE flags. */ ++typedef enum _gceCORE ++{ ++ gcvCORE_MAJOR = 0x0, ++ gcvCORE_2D = 0x1, ++ gcvCORE_VG = 0x2, ++} ++gceCORE; ++ ++#define gcdMAX_GPU_COUNT 3 ++ ++#define gcdMAX_SURF_LAYER 4 ++ ++#define gcdMAX_DRAW_BUFFERS 4 ++ ++/******************************************************************************* ++** ++** gcmVERIFY_OBJECT ++** ++** Assert if an object is invalid or is not of the specified type. If the ++** object is invalid or not of the specified type, gcvSTATUS_INVALID_OBJECT ++** will be returned from the current function. In retail mode this macro ++** does nothing. ++** ++** ARGUMENTS: ++** ++** obj Object to test. ++** t Expected type of the object. ++*/ ++#if gcmIS_DEBUG(gcdDEBUG_TRACE) ++#define _gcmVERIFY_OBJECT(prefix, obj, t) \ ++ if ((obj) == gcvNULL) \ ++ { \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "VERIFY_OBJECT failed: NULL"); \ ++ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ ++ gcmCC_PRINT(t)); \ ++ prefix##ASSERT((obj) != gcvNULL); \ ++ prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ ++ return gcvSTATUS_INVALID_OBJECT; \ ++ } \ ++ else if (((gcsOBJECT*) (obj))->type != t) \ ++ { \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "VERIFY_OBJECT failed: %c%c%c%c", \ ++ gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \ ++ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ ++ gcmCC_PRINT(t)); \ ++ prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \ ++ prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ ++ return gcvSTATUS_INVALID_OBJECT; \ ++ } ++ ++# define gcmVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcm, obj, t) ++# define gcmkVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcmk, obj, t) ++#else ++# define gcmVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) ++# define gcmkVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) ++#endif ++ ++/******************************************************************************/ ++/*VERIFY_OBJECT if special return expected*/ ++/******************************************************************************/ ++#ifndef EGL_API_ANDROID ++# define _gcmVERIFY_OBJECT_RETURN(prefix, obj, t, retVal) \ ++ do \ ++ { \ ++ if ((obj) == gcvNULL) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "VERIFY_OBJECT_RETURN failed: NULL"); \ ++ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ ++ gcmCC_PRINT(t)); \ ++ prefix##ASSERT((obj) != gcvNULL); \ ++ prefix##FOOTER_ARG("retVal=%d", retVal); \ ++ return retVal; \ ++ } \ ++ else if (((gcsOBJECT*) (obj))->type != t) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "VERIFY_OBJECT_RETURN failed: %c%c%c%c", \ ++ gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \ ++ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ ++ gcmCC_PRINT(t)); \ ++ prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \ ++ prefix##FOOTER_ARG("retVal=%d", retVal); \ ++ return retVal; \ ++ } \ ++ } \ ++ while (gcvFALSE) ++# define gcmVERIFY_OBJECT_RETURN(obj, t, retVal) \ ++ _gcmVERIFY_OBJECT_RETURN(gcm, obj, t, retVal) ++# define gcmkVERIFY_OBJECT_RETURN(obj, t, retVal) \ ++ _gcmVERIFY_OBJECT_RETURN(gcmk, obj, t, retVal) ++#else ++# define gcmVERIFY_OBJECT_RETURN(obj, t) do {} while (gcvFALSE) ++# define gcmVERIFY_OBJECT_RETURN(obj, t) do {} while (gcvFALSE) ++#endif ++ ++/******************************************************************************\ ++********************************** gckOS Object ********************************* ++\******************************************************************************/ ++ ++/* Construct a new gckOS object. */ ++gceSTATUS ++gckOS_Construct( ++ IN gctPOINTER Context, ++ OUT gckOS * Os ++ ); ++ ++/* Destroy an gckOS object. */ ++gceSTATUS ++gckOS_Destroy( ++ IN gckOS Os ++ ); ++ ++/* Query the video memory. */ ++gceSTATUS ++gckOS_QueryVideoMemory( ++ IN gckOS Os, ++ OUT gctPHYS_ADDR * InternalAddress, ++ OUT gctSIZE_T * InternalSize, ++ OUT gctPHYS_ADDR * ExternalAddress, ++ OUT gctSIZE_T * ExternalSize, ++ OUT gctPHYS_ADDR * ContiguousAddress, ++ OUT gctSIZE_T * ContiguousSize ++ ); ++ ++/* Allocate memory from the heap. */ ++gceSTATUS ++gckOS_Allocate( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Free allocated memory. */ ++gceSTATUS ++gckOS_Free( ++ IN gckOS Os, ++ IN gctPOINTER Memory ++ ); ++ ++/* Wrapper for allocation memory.. */ ++gceSTATUS ++gckOS_AllocateMemory( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Memory ++ ); ++ ++/* Wrapper for freeing memory. */ ++gceSTATUS ++gckOS_FreeMemory( ++ IN gckOS Os, ++ IN gctPOINTER Memory ++ ); ++ ++/* Allocate paged memory. */ ++gceSTATUS ++gckOS_AllocatePagedMemory( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ OUT gctPHYS_ADDR * Physical ++ ); ++ ++/* Allocate paged memory. */ ++gceSTATUS ++gckOS_AllocatePagedMemoryEx( ++ IN gckOS Os, ++ IN gctUINT32 Flag, ++ IN gctSIZE_T Bytes, ++ OUT gctUINT32 * Gid, ++ OUT gctPHYS_ADDR * Physical ++ ); ++ ++/* Lock pages. */ ++gceSTATUS ++gckOS_LockPages( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctBOOL Cacheable, ++ OUT gctPOINTER * Logical, ++ OUT gctSIZE_T * PageCount ++ ); ++ ++/* Map pages. */ ++gceSTATUS ++gckOS_MapPages( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T PageCount, ++ IN gctPOINTER PageTable ++ ); ++ ++/* Map pages. */ ++gceSTATUS ++gckOS_MapPagesEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T PageCount, ++ IN gctUINT32 Address, ++ IN gctPOINTER PageTable ++ ); ++ ++gceSTATUS ++gckOS_UnmapPages( ++ IN gckOS Os, ++ IN gctSIZE_T PageCount, ++ IN gctUINT32 Address ++ ); ++ ++/* Unlock pages. */ ++gceSTATUS ++gckOS_UnlockPages( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ); ++ ++/* Free paged memory. */ ++gceSTATUS ++gckOS_FreePagedMemory( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Allocate non-paged memory. */ ++gceSTATUS ++gckOS_AllocateNonPagedMemory( ++ IN gckOS Os, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Free non-paged memory. */ ++gceSTATUS ++gckOS_FreeNonPagedMemory( ++ IN gckOS Os, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical ++ ); ++ ++/* Allocate contiguous memory. */ ++gceSTATUS ++gckOS_AllocateContiguous( ++ IN gckOS Os, ++ IN gctBOOL InUserSpace, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctPHYS_ADDR * Physical, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Free contiguous memory. */ ++gceSTATUS ++gckOS_FreeContiguous( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Get the number fo bytes per page. */ ++gceSTATUS ++gckOS_GetPageSize( ++ IN gckOS Os, ++ OUT gctSIZE_T * PageSize ++ ); ++ ++/* Get the physical address of a corresponding logical address. */ ++gceSTATUS ++gckOS_GetPhysicalAddress( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Get the physical address of a corresponding user logical address. */ ++gceSTATUS ++gckOS_UserLogicalToPhysical( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Get the physical address of a corresponding logical address. */ ++gceSTATUS ++gckOS_GetPhysicalAddressProcess( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ IN gctUINT32 ProcessID, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Map physical memory. */ ++gceSTATUS ++gckOS_MapPhysical( ++ IN gckOS Os, ++ IN gctUINT32 Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Unmap previously mapped physical memory. */ ++gceSTATUS ++gckOS_UnmapPhysical( ++ IN gckOS Os, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Get real physical address from descriptor. */ ++gceSTATUS ++gckOS_PhysicalToPhysicalAddress( ++ IN gckOS Os, ++ IN gctPOINTER Physical, ++ OUT gctUINT32 * PhysicalAddress ++ ); ++ ++/* Read data from a hardware register. */ ++gceSTATUS ++gckOS_ReadRegister( ++ IN gckOS Os, ++ IN gctUINT32 Address, ++ OUT gctUINT32 * Data ++ ); ++ ++/* Read data from a hardware register. */ ++gceSTATUS ++gckOS_ReadRegisterEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT32 Address, ++ OUT gctUINT32 * Data ++ ); ++ ++/* Write data to a hardware register. */ ++gceSTATUS ++gckOS_WriteRegister( ++ IN gckOS Os, ++ IN gctUINT32 Address, ++ IN gctUINT32 Data ++ ); ++ ++/* Write data to a hardware register. */ ++gceSTATUS ++gckOS_WriteRegisterEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT32 Address, ++ IN gctUINT32 Data ++ ); ++ ++/* Write data to a 32-bit memory location. */ ++gceSTATUS ++gckOS_WriteMemory( ++ IN gckOS Os, ++ IN gctPOINTER Address, ++ IN gctUINT32 Data ++ ); ++ ++/* Map physical memory into the process space. */ ++gceSTATUS ++gckOS_MapMemory( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Unmap physical memory from the specified process space. */ ++gceSTATUS ++gckOS_UnmapMemoryEx( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical, ++ IN gctUINT32 PID ++ ); ++ ++/* Unmap physical memory from the process space. */ ++gceSTATUS ++gckOS_UnmapMemory( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ); ++ ++/* Unmap user logical memory out of physical memory. ++ * This function is only supported in Linux currently. ++ */ ++gceSTATUS ++gckOS_UnmapUserLogical( ++ IN gckOS Os, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ); ++ ++/* Create a new mutex. */ ++gceSTATUS ++gckOS_CreateMutex( ++ IN gckOS Os, ++ OUT gctPOINTER * Mutex ++ ); ++ ++/* Delete a mutex. */ ++gceSTATUS ++gckOS_DeleteMutex( ++ IN gckOS Os, ++ IN gctPOINTER Mutex ++ ); ++ ++/* Acquire a mutex. */ ++gceSTATUS ++gckOS_AcquireMutex( ++ IN gckOS Os, ++ IN gctPOINTER Mutex, ++ IN gctUINT32 Timeout ++ ); ++ ++/* Release a mutex. */ ++gceSTATUS ++gckOS_ReleaseMutex( ++ IN gckOS Os, ++ IN gctPOINTER Mutex ++ ); ++ ++/* Atomically exchange a pair of 32-bit values. */ ++gceSTATUS ++gckOS_AtomicExchange( ++ IN gckOS Os, ++ IN OUT gctUINT32_PTR Target, ++ IN gctUINT32 NewValue, ++ OUT gctUINT32_PTR OldValue ++ ); ++ ++/* Atomically exchange a pair of pointers. */ ++gceSTATUS ++gckOS_AtomicExchangePtr( ++ IN gckOS Os, ++ IN OUT gctPOINTER * Target, ++ IN gctPOINTER NewValue, ++ OUT gctPOINTER * OldValue ++ ); ++ ++gceSTATUS ++gckOS_AtomSetMask( ++ IN gctPOINTER Atom, ++ IN gctUINT32 Mask ++ ); ++ ++gceSTATUS ++gckOS_AtomClearMask( ++ IN gctPOINTER Atom, ++ IN gctUINT32 Mask ++ ); ++ ++gceSTATUS ++gckOS_DumpCallStack( ++ IN gckOS Os ++ ); ++ ++gceSTATUS ++gckOS_GetProcessNameByPid( ++ IN gctINT Pid, ++ IN gctSIZE_T Length, ++ OUT gctUINT8_PTR String ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_AtomConstruct ++** ++** Create an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** OUTPUT: ++** ++** gctPOINTER * Atom ++** Pointer to a variable receiving the constructed atom. ++*/ ++gceSTATUS ++gckOS_AtomConstruct( ++ IN gckOS Os, ++ OUT gctPOINTER * Atom ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_AtomDestroy ++** ++** Destroy an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom to destroy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomDestroy( ++ IN gckOS Os, ++ OUT gctPOINTER Atom ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_AtomGet ++** ++** Get the 32-bit value protected by an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** OUTPUT: ++** ++** gctINT32_PTR Value ++** Pointer to a variable the receives the value of the atom. ++*/ ++gceSTATUS ++gckOS_AtomGet( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ OUT gctINT32_PTR Value ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_AtomSet ++** ++** Set the 32-bit value protected by an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** gctINT32 Value ++** The value of the atom. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_AtomSet( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ IN gctINT32 Value ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_AtomIncrement ++** ++** Atomically increment the 32-bit integer value inside an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** OUTPUT: ++** ++** gctINT32_PTR Value ++** Pointer to a variable the receives the original value of the atom. ++*/ ++gceSTATUS ++gckOS_AtomIncrement( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ OUT gctINT32_PTR Value ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_AtomDecrement ++** ++** Atomically decrement the 32-bit integer value inside an atom. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gctPOINTER Atom ++** Pointer to the atom. ++** ++** OUTPUT: ++** ++** gctINT32_PTR Value ++** Pointer to a variable the receives the original value of the atom. ++*/ ++gceSTATUS ++gckOS_AtomDecrement( ++ IN gckOS Os, ++ IN gctPOINTER Atom, ++ OUT gctINT32_PTR Value ++ ); ++ ++/* Delay a number of microseconds. */ ++gceSTATUS ++gckOS_Delay( ++ IN gckOS Os, ++ IN gctUINT32 Delay ++ ); ++ ++/* Get time in milliseconds. */ ++gceSTATUS ++gckOS_GetTicks( ++ OUT gctUINT32_PTR Time ++ ); ++ ++/* Compare time value. */ ++gceSTATUS ++gckOS_TicksAfter( ++ IN gctUINT32 Time1, ++ IN gctUINT32 Time2, ++ OUT gctBOOL_PTR IsAfter ++ ); ++ ++/* Get time in microseconds. */ ++gceSTATUS ++gckOS_GetTime( ++ OUT gctUINT64_PTR Time ++ ); ++ ++/* Memory barrier. */ ++gceSTATUS ++gckOS_MemoryBarrier( ++ IN gckOS Os, ++ IN gctPOINTER Address ++ ); ++ ++/* Map user pointer. */ ++gceSTATUS ++gckOS_MapUserPointer( ++ IN gckOS Os, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * KernelPointer ++ ); ++ ++/* Unmap user pointer. */ ++gceSTATUS ++gckOS_UnmapUserPointer( ++ IN gckOS Os, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size, ++ IN gctPOINTER KernelPointer ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_QueryNeedCopy ++** ++** Query whether the memory can be accessed or mapped directly or it has to be ++** copied. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctUINT32 ProcessID ++** Process ID of the current process. ++** ++** OUTPUT: ++** ++** gctBOOL_PTR NeedCopy ++** Pointer to a boolean receiving gcvTRUE if the memory needs a copy or ++** gcvFALSE if the memory can be accessed or mapped dircetly. ++*/ ++gceSTATUS ++gckOS_QueryNeedCopy( ++ IN gckOS Os, ++ IN gctUINT32 ProcessID, ++ OUT gctBOOL_PTR NeedCopy ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_CopyFromUserData ++** ++** Copy data from user to kernel memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER KernelPointer ++** Pointer to kernel memory. ++** ++** gctPOINTER Pointer ++** Pointer to user memory. ++** ++** gctSIZE_T Size ++** Number of bytes to copy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_CopyFromUserData( ++ IN gckOS Os, ++ IN gctPOINTER KernelPointer, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_CopyToUserData ++** ++** Copy data from kernel to user memory. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to an gckOS object. ++** ++** gctPOINTER KernelPointer ++** Pointer to kernel memory. ++** ++** gctPOINTER Pointer ++** Pointer to user memory. ++** ++** gctSIZE_T Size ++** Number of bytes to copy. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_CopyToUserData( ++ IN gckOS Os, ++ IN gctPOINTER KernelPointer, ++ IN gctPOINTER Pointer, ++ IN gctSIZE_T Size ++ ); ++ ++gceSTATUS ++gckOS_SuspendInterrupt( ++ IN gckOS Os ++ ); ++ ++gceSTATUS ++gckOS_SuspendInterruptEx( ++ IN gckOS Os, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS ++gckOS_ResumeInterrupt( ++ IN gckOS Os ++ ); ++ ++gceSTATUS ++gckOS_ResumeInterruptEx( ++ IN gckOS Os, ++ IN gceCORE Core ++ ); ++ ++/* Get the base address for the physical memory. */ ++gceSTATUS ++gckOS_GetBaseAddress( ++ IN gckOS Os, ++ OUT gctUINT32_PTR BaseAddress ++ ); ++ ++/* Perform a memory copy. */ ++gceSTATUS ++gckOS_MemCopy( ++ IN gctPOINTER Destination, ++ IN gctCONST_POINTER Source, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Zero memory. */ ++gceSTATUS ++gckOS_ZeroMemory( ++ IN gctPOINTER Memory, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Device I/O control to the kernel HAL layer. */ ++gceSTATUS ++gckOS_DeviceControl( ++ IN gckOS Os, ++ IN gctBOOL FromUser, ++ IN gctUINT32 IoControlCode, ++ IN gctPOINTER InputBuffer, ++ IN gctSIZE_T InputBufferSize, ++ OUT gctPOINTER OutputBuffer, ++ IN gctSIZE_T OutputBufferSize ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_GetProcessID ++** ++** Get current process ID. ++** ++** INPUT: ++** ++** Nothing. ++** ++** OUTPUT: ++** ++** gctUINT32_PTR ProcessID ++** Pointer to the variable that receives the process ID. ++*/ ++gceSTATUS ++gckOS_GetProcessID( ++ OUT gctUINT32_PTR ProcessID ++ ); ++ ++gceSTATUS ++gckOS_GetCurrentProcessID( ++ OUT gctUINT32_PTR ProcessID ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_GetThreadID ++** ++** Get current thread ID. ++** ++** INPUT: ++** ++** Nothing. ++** ++** OUTPUT: ++** ++** gctUINT32_PTR ThreadID ++** Pointer to the variable that receives the thread ID. ++*/ ++gceSTATUS ++gckOS_GetThreadID( ++ OUT gctUINT32_PTR ThreadID ++ ); ++ ++/******************************************************************************\ ++********************************** Signal Object ********************************* ++\******************************************************************************/ ++ ++/* Create a signal. */ ++gceSTATUS ++gckOS_CreateSignal( ++ IN gckOS Os, ++ IN gctBOOL ManualReset, ++ OUT gctSIGNAL * Signal ++ ); ++ ++/* Destroy a signal. */ ++gceSTATUS ++gckOS_DestroySignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal ++ ); ++ ++/* Signal a signal. */ ++gceSTATUS ++gckOS_Signal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctBOOL State ++ ); ++ ++/* Wait for a signal. */ ++gceSTATUS ++gckOS_WaitSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctUINT32 Wait ++ ); ++ ++/* Map a user signal to the kernel space. */ ++gceSTATUS ++gckOS_MapSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctHANDLE Process, ++ OUT gctSIGNAL * MappedSignal ++ ); ++ ++/* Unmap a user signal */ ++gceSTATUS ++gckOS_UnmapSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal ++ ); ++ ++/* Map user memory. */ ++gceSTATUS ++gckOS_MapUserMemory( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPOINTER Memory, ++ IN gctUINT32 Physical, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * Info, ++ OUT gctUINT32_PTR Address ++ ); ++ ++/* Unmap user memory. */ ++gceSTATUS ++gckOS_UnmapUserMemory( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPOINTER Memory, ++ IN gctSIZE_T Size, ++ IN gctPOINTER Info, ++ IN gctUINT32 Address ++ ); ++ ++/******************************************************************************\ ++************************** Android Native Fence Sync *************************** ++\******************************************************************************/ ++gceSTATUS ++gckOS_CreateSyncTimeline( ++ IN gckOS Os, ++ OUT gctHANDLE * Timeline ++ ); ++ ++gceSTATUS ++gckOS_DestroySyncTimeline( ++ IN gckOS Os, ++ IN gctHANDLE Timeline ++ ); ++ ++gceSTATUS ++gckOS_CreateSyncPoint( ++ IN gckOS Os, ++ OUT gctSYNC_POINT * SyncPoint ++ ); ++ ++gceSTATUS ++gckOS_ReferenceSyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint ++ ); ++ ++gceSTATUS ++gckOS_DestroySyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint ++ ); ++ ++gceSTATUS ++gckOS_SignalSyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint ++ ); ++ ++gceSTATUS ++gckOS_QuerySyncPoint( ++ IN gckOS Os, ++ IN gctSYNC_POINT SyncPoint, ++ OUT gctBOOL_PTR State ++ ); ++ ++gceSTATUS ++gckOS_CreateNativeFence( ++ IN gckOS Os, ++ IN gctHANDLE Timeline, ++ IN gctSYNC_POINT SyncPoint, ++ OUT gctINT * FenceFD ++ ); ++ ++/* Create signal to be used in the user space. */ ++gceSTATUS ++gckOS_CreateUserSignal( ++ IN gckOS Os, ++ IN gctBOOL ManualReset, ++ OUT gctINT * SignalID ++ ); ++ ++/* Destroy signal used in the user space. */ ++gceSTATUS ++gckOS_DestroyUserSignal( ++ IN gckOS Os, ++ IN gctINT SignalID ++ ); ++ ++/* Wait for signal used in the user space. */ ++gceSTATUS ++gckOS_WaitUserSignal( ++ IN gckOS Os, ++ IN gctINT SignalID, ++ IN gctUINT32 Wait ++ ); ++ ++/* Signal a signal used in the user space. */ ++gceSTATUS ++gckOS_SignalUserSignal( ++ IN gckOS Os, ++ IN gctINT SignalID, ++ IN gctBOOL State ++ ); ++ ++/* Set a signal owned by a process. */ ++gceSTATUS ++gckOS_UserSignal( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ IN gctHANDLE Process ++ ); ++ ++/******************************************************************************\ ++** Cache Support ++*/ ++ ++gceSTATUS ++gckOS_CacheClean( ++ gckOS Os, ++ gctUINT32 ProcessID, ++ gctPHYS_ADDR Handle, ++ gctUINT32 Physical, ++ gctPOINTER Logical, ++ gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gckOS_CacheFlush( ++ gckOS Os, ++ gctUINT32 ProcessID, ++ gctPHYS_ADDR Handle, ++ gctUINT32 Physical, ++ gctPOINTER Logical, ++ gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gckOS_CacheInvalidate( ++ gckOS Os, ++ gctUINT32 ProcessID, ++ gctPHYS_ADDR Handle, ++ gctUINT32 Physical, ++ gctPOINTER Logical, ++ gctSIZE_T Bytes ++ ); ++ ++gceSTATUS ++gckOS_CPUPhysicalToGPUPhysical( ++ IN gckOS Os, ++ IN gctUINT32 CPUPhysical, ++ IN gctUINT32_PTR GPUPhysical ++ ); ++ ++gceSTATUS ++gckOS_GPUPhysicalToCPUPhysical( ++ IN gckOS Os, ++ IN gctUINT32 GPUPhysical, ++ IN gctUINT32_PTR CPUPhysical ++ ); ++ ++gceSTATUS ++gckOS_QueryOption( ++ IN gckOS Os, ++ IN gctCONST_STRING Option, ++ OUT gctUINT32 * Value ++ ); ++ ++/******************************************************************************\ ++** Debug Support ++*/ ++ ++void ++gckOS_SetDebugLevel( ++ IN gctUINT32 Level ++ ); ++ ++void ++gckOS_SetDebugZone( ++ IN gctUINT32 Zone ++ ); ++ ++void ++gckOS_SetDebugLevelZone( ++ IN gctUINT32 Level, ++ IN gctUINT32 Zone ++ ); ++ ++void ++gckOS_SetDebugZones( ++ IN gctUINT32 Zones, ++ IN gctBOOL Enable ++ ); ++ ++void ++gckOS_SetDebugFile( ++ IN gctCONST_STRING FileName ++ ); ++ ++/******************************************************************************* ++** Broadcast interface. ++*/ ++ ++typedef enum _gceBROADCAST ++{ ++ /* GPU might be idle. */ ++ gcvBROADCAST_GPU_IDLE, ++ ++ /* A commit is going to happen. */ ++ gcvBROADCAST_GPU_COMMIT, ++ ++ /* GPU seems to be stuck. */ ++ gcvBROADCAST_GPU_STUCK, ++ ++ /* First process gets attached. */ ++ gcvBROADCAST_FIRST_PROCESS, ++ ++ /* Last process gets detached. */ ++ gcvBROADCAST_LAST_PROCESS, ++ ++ /* AXI bus error. */ ++ gcvBROADCAST_AXI_BUS_ERROR, ++ ++ /* Out of memory. */ ++ gcvBROADCAST_OUT_OF_MEMORY, ++} ++gceBROADCAST; ++ ++gceSTATUS ++gckOS_Broadcast( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gceBROADCAST Reason ++ ); ++ ++gceSTATUS ++gckOS_BroadcastHurry( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gctUINT Urgency ++ ); ++ ++gceSTATUS ++gckOS_BroadcastCalibrateSpeed( ++ IN gckOS Os, ++ IN gckHARDWARE Hardware, ++ IN gctUINT Idle, ++ IN gctUINT Time ++ ); ++ ++/******************************************************************************* ++** ++** gckOS_SetGPUPower ++** ++** Set the power of the GPU on or off. ++** ++** INPUT: ++** ++** gckOS Os ++** Pointer to a gckOS object. ++** ++** gceCORE Core ++** GPU whose power is set. ++** ++** gctBOOL Clock ++** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. ++** ++** gctBOOL Power ++** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckOS_SetGPUPower( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctBOOL Clock, ++ IN gctBOOL Power ++ ); ++ ++gceSTATUS ++gckOS_ResetGPU( ++ IN gckOS Os, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS ++gckOS_PrepareGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS ++gckOS_FinishGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core ++ ); ++ ++gceSTATUS ++gckOS_QueryGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core, ++ OUT gctUINT32 * Frequency, ++ OUT gctUINT8 * Scale ++ ); ++ ++gceSTATUS ++gckOS_SetGPUFrequency( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT8 Scale ++ ); ++ ++/******************************************************************************* ++** Semaphores. ++*/ ++ ++/* Create a new semaphore. */ ++gceSTATUS ++gckOS_CreateSemaphore( ++ IN gckOS Os, ++ OUT gctPOINTER * Semaphore ++ ); ++ ++#if gcdENABLE_VG ++gceSTATUS ++gckOS_CreateSemaphoreVG( ++ IN gckOS Os, ++ OUT gctPOINTER * Semaphore ++ ); ++#endif ++ ++/* Delete a semahore. */ ++gceSTATUS ++gckOS_DestroySemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ); ++ ++/* Acquire a semahore. */ ++gceSTATUS ++gckOS_AcquireSemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ); ++ ++/* Try to acquire a semahore. */ ++gceSTATUS ++gckOS_TryAcquireSemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ); ++ ++/* Release a semahore. */ ++gceSTATUS ++gckOS_ReleaseSemaphore( ++ IN gckOS Os, ++ IN gctPOINTER Semaphore ++ ); ++ ++/******************************************************************************* ++** Timer API. ++*/ ++ ++typedef void (*gctTIMERFUNCTION)(gctPOINTER); ++ ++/* Create a timer. */ ++gceSTATUS ++gckOS_CreateTimer( ++ IN gckOS Os, ++ IN gctTIMERFUNCTION Function, ++ IN gctPOINTER Data, ++ OUT gctPOINTER * Timer ++ ); ++ ++/* Destory a timer. */ ++gceSTATUS ++gckOS_DestroyTimer( ++ IN gckOS Os, ++ IN gctPOINTER Timer ++ ); ++ ++/* Start a timer. */ ++gceSTATUS ++gckOS_StartTimer( ++ IN gckOS Os, ++ IN gctPOINTER Timer, ++ IN gctUINT32 Delay ++ ); ++ ++/* Stop a timer. */ ++gceSTATUS ++gckOS_StopTimer( ++ IN gckOS Os, ++ IN gctPOINTER Timer ++ ); ++ ++/******************************************************************************\ ++********************************* gckHEAP Object ******************************** ++\******************************************************************************/ ++ ++typedef struct _gckHEAP * gckHEAP; ++ ++/* Construct a new gckHEAP object. */ ++gceSTATUS ++gckHEAP_Construct( ++ IN gckOS Os, ++ IN gctSIZE_T AllocationSize, ++ OUT gckHEAP * Heap ++ ); ++ ++/* Destroy an gckHEAP object. */ ++gceSTATUS ++gckHEAP_Destroy( ++ IN gckHEAP Heap ++ ); ++ ++/* Allocate memory. */ ++gceSTATUS ++gckHEAP_Allocate( ++ IN gckHEAP Heap, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Node ++ ); ++ ++/* Free memory. */ ++gceSTATUS ++gckHEAP_Free( ++ IN gckHEAP Heap, ++ IN gctPOINTER Node ++ ); ++ ++/* Profile the heap. */ ++gceSTATUS ++gckHEAP_ProfileStart( ++ IN gckHEAP Heap ++ ); ++ ++gceSTATUS ++gckHEAP_ProfileEnd( ++ IN gckHEAP Heap, ++ IN gctCONST_STRING Title ++ ); ++ ++ ++/******************************************************************************\ ++******************************** gckVIDMEM Object ****************************** ++\******************************************************************************/ ++ ++typedef struct _gckVIDMEM * gckVIDMEM; ++typedef struct _gckKERNEL * gckKERNEL; ++typedef struct _gckDB * gckDB; ++typedef struct _gckDVFS * gckDVFS; ++ ++/* Construct a new gckVIDMEM object. */ ++gceSTATUS ++gckVIDMEM_Construct( ++ IN gckOS Os, ++ IN gctUINT32 BaseAddress, ++ IN gctSIZE_T Bytes, ++ IN gctSIZE_T Threshold, ++ IN gctSIZE_T Banking, ++ OUT gckVIDMEM * Memory ++ ); ++ ++/* Destroy an gckVDIMEM object. */ ++gceSTATUS ++gckVIDMEM_Destroy( ++ IN gckVIDMEM Memory ++ ); ++ ++/* Allocate linear memory. */ ++gceSTATUS ++gckVIDMEM_AllocateLinear( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM Memory, ++ IN gctSIZE_T Bytes, ++ IN gctUINT32 Alignment, ++ IN gceSURF_TYPE Type, ++ IN gctBOOL Specified, ++ OUT gcuVIDMEM_NODE_PTR * Node ++ ); ++ ++/* Free memory. */ ++gceSTATUS ++gckVIDMEM_Free( ++ IN gckKERNEL Kernel, ++ IN gcuVIDMEM_NODE_PTR Node ++ ); ++ ++/* Lock memory. */ ++gceSTATUS ++gckVIDMEM_Lock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ IN gctBOOL Cacheable, ++ OUT gctUINT32 * Address, ++ OUT gctUINT32 * Gid, ++ OUT gctUINT64 * PhysicalAddress ++ ); ++ ++/* Unlock memory. */ ++gceSTATUS ++gckVIDMEM_Unlock( ++ IN gckKERNEL Kernel, ++ IN gckVIDMEM_NODE Node, ++ IN gceSURF_TYPE Type, ++ IN OUT gctBOOL * Asynchroneous ++ ); ++ ++/* Construct a gcuVIDMEM_NODE union for virtual memory. */ ++gceSTATUS ++gckVIDMEM_ConstructVirtual( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 Flag, ++ IN gctSIZE_T Bytes, ++ OUT gcuVIDMEM_NODE_PTR * Node ++ ); ++ ++/* Destroy a gcuVIDMEM_NODE union for virtual memory. */ ++gceSTATUS ++gckVIDMEM_DestroyVirtual( ++ IN gcuVIDMEM_NODE_PTR Node ++ ); ++ ++/******************************************************************************\ ++******************************** gckKERNEL Object ****************************** ++\******************************************************************************/ ++ ++struct _gcsHAL_INTERFACE; ++ ++/* Notifications. */ ++typedef enum _gceNOTIFY ++{ ++ gcvNOTIFY_INTERRUPT, ++ gcvNOTIFY_COMMAND_QUEUE, ++} ++gceNOTIFY; ++ ++/* Flush flags. */ ++typedef enum _gceKERNEL_FLUSH ++{ ++ gcvFLUSH_COLOR = 0x01, ++ gcvFLUSH_DEPTH = 0x02, ++ gcvFLUSH_TEXTURE = 0x04, ++ gcvFLUSH_2D = 0x08, ++ gcvFLUSH_TILE_STATUS = 0x20, ++ gcvFLUSH_ALL = gcvFLUSH_COLOR ++ | gcvFLUSH_DEPTH ++ | gcvFLUSH_TEXTURE ++ | gcvFLUSH_2D ++ | gcvFLUSH_TILE_STATUS ++} ++gceKERNEL_FLUSH; ++ ++/* Construct a new gckKERNEL object. */ ++gceSTATUS ++gckKERNEL_Construct( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctPOINTER Context, ++ IN gckDB SharedDB, ++ OUT gckKERNEL * Kernel ++ ); ++ ++/* Destroy an gckKERNEL object. */ ++gceSTATUS ++gckKERNEL_Destroy( ++ IN gckKERNEL Kernel ++ ); ++ ++/* Dispatch a user-level command. */ ++gceSTATUS ++gckKERNEL_Dispatch( ++ IN gckKERNEL Kernel, ++ IN gctBOOL FromUser, ++ IN OUT struct _gcsHAL_INTERFACE * Interface ++ ); ++ ++/* Query Database requirements. */ ++gceSTATUS ++ gckKERNEL_QueryDatabase( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ); ++ ++/* Query the video memory. */ ++gceSTATUS ++gckKERNEL_QueryVideoMemory( ++ IN gckKERNEL Kernel, ++ OUT struct _gcsHAL_INTERFACE * Interface ++ ); ++ ++/* Lookup the gckVIDMEM object for a pool. */ ++gceSTATUS ++gckKERNEL_GetVideoMemoryPool( ++ IN gckKERNEL Kernel, ++ IN gcePOOL Pool, ++ OUT gckVIDMEM * VideoMemory ++ ); ++ ++gceSTATUS ++gckKERNEL_AllocateLinearMemory( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN OUT gcePOOL * Pool, ++ IN gctSIZE_T Bytes, ++ IN gctUINT32 Alignment, ++ IN gceSURF_TYPE Type, ++ IN gctUINT32 Flag, ++ OUT gctUINT32 * Node ++ ); ++ ++gceSTATUS ++gckKERNEL_ReleaseVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN gctUINT32 Handle ++ ); ++ ++gceSTATUS ++gckKERNEL_LockVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gceCORE Core, ++ IN gctUINT32 ProcessID, ++ IN gctBOOL FromUser, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ); ++ ++gceSTATUS ++gckKERNEL_UnlockVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 ProcessID, ++ IN OUT gcsHAL_INTERFACE * Interface ++ ); ++ ++/* Map video memory. */ ++gceSTATUS ++gckKERNEL_MapVideoMemory( ++ IN gckKERNEL Kernel, ++ IN gctBOOL InUserSpace, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Map video memory. */ ++gceSTATUS ++gckKERNEL_MapVideoMemoryEx( ++ IN gckKERNEL Kernel, ++ IN gceCORE Core, ++ IN gctBOOL InUserSpace, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Map memory. */ ++gceSTATUS ++gckKERNEL_MapMemory( ++ IN gckKERNEL Kernel, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ OUT gctPOINTER * Logical ++ ); ++ ++/* Unmap memory. */ ++gceSTATUS ++gckKERNEL_UnmapMemory( ++ IN gckKERNEL Kernel, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ); ++ ++/* Notification of events. */ ++gceSTATUS ++gckKERNEL_Notify( ++ IN gckKERNEL Kernel, ++ IN gceNOTIFY Notifcation, ++ IN gctBOOL Data ++ ); ++ ++gceSTATUS ++gckKERNEL_QuerySettings( ++ IN gckKERNEL Kernel, ++ OUT gcsKERNEL_SETTINGS * Settings ++ ); ++ ++/******************************************************************************* ++** ++** gckKERNEL_Recovery ++** ++** Try to recover the GPU from a fatal error. ++** ++** INPUT: ++** ++** gckKERNEL Kernel ++** Pointer to an gckKERNEL object. ++** ++** OUTPUT: ++** ++** Nothing. ++*/ ++gceSTATUS ++gckKERNEL_Recovery( ++ IN gckKERNEL Kernel ++ ); ++ ++/* Set the value of timeout on HW operation. */ ++void ++gckKERNEL_SetTimeOut( ++ IN gckKERNEL Kernel, ++ IN gctUINT32 timeOut ++ ); ++ ++/* Get access to the user data. */ ++gceSTATUS ++gckKERNEL_OpenUserData( ++ IN gckKERNEL Kernel, ++ IN gctBOOL NeedCopy, ++ IN gctPOINTER StaticStorage, ++ IN gctPOINTER UserPointer, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * KernelPointer ++ ); ++ ++/* Release resources associated with the user data connection. */ ++gceSTATUS ++gckKERNEL_CloseUserData( ++ IN gckKERNEL Kernel, ++ IN gctBOOL NeedCopy, ++ IN gctBOOL FlushData, ++ IN gctPOINTER UserPointer, ++ IN gctSIZE_T Size, ++ OUT gctPOINTER * KernelPointer ++ ); ++ ++gceSTATUS ++gckDVFS_Construct( ++ IN gckHARDWARE Hardware, ++ OUT gckDVFS * Frequency ++ ); ++ ++gceSTATUS ++gckDVFS_Destroy( ++ IN gckDVFS Dvfs ++ ); ++ ++gceSTATUS ++gckDVFS_Start( ++ IN gckDVFS Dvfs ++ ); ++ ++gceSTATUS ++gckDVFS_Stop( ++ IN gckDVFS Dvfs ++ ); ++ ++/******************************************************************************\ ++******************************* gckHARDWARE Object ***************************** ++\******************************************************************************/ ++ ++/* Construct a new gckHARDWARE object. */ ++gceSTATUS ++gckHARDWARE_Construct( ++ IN gckOS Os, ++ IN gceCORE Core, ++ OUT gckHARDWARE * Hardware ++ ); ++ ++/* Destroy an gckHARDWARE object. */ ++gceSTATUS ++gckHARDWARE_Destroy( ++ IN gckHARDWARE Hardware ++ ); ++ ++/* Get hardware type. */ ++gceSTATUS ++gckHARDWARE_GetType( ++ IN gckHARDWARE Hardware, ++ OUT gceHARDWARE_TYPE * Type ++ ); ++ ++/* Query system memory requirements. */ ++gceSTATUS ++gckHARDWARE_QuerySystemMemory( ++ IN gckHARDWARE Hardware, ++ OUT gctSIZE_T * SystemSize, ++ OUT gctUINT32 * SystemBaseAddress ++ ); ++ ++/* Build virtual address. */ ++gceSTATUS ++gckHARDWARE_BuildVirtualAddress( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Index, ++ IN gctUINT32 Offset, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Query command buffer requirements. */ ++gceSTATUS ++gckHARDWARE_QueryCommandBuffer( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32 * Alignment, ++ OUT gctUINT32 * ReservedHead, ++ OUT gctUINT32 * ReservedTail ++ ); ++ ++/* Add a WAIT/LINK pair in the command queue. */ ++gceSTATUS ++gckHARDWARE_WaitLink( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Offset, ++ IN OUT gctUINT32 * Bytes, ++ OUT gctUINT32 * WaitOffset, ++ OUT gctUINT32 * WaitBytes ++ ); ++ ++/* Kickstart the command processor. */ ++gceSTATUS ++gckHARDWARE_Execute( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Address, ++ IN gctSIZE_T Bytes ++ ); ++ ++/* Add an END command in the command queue. */ ++gceSTATUS ++gckHARDWARE_End( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Add a NOP command in the command queue. */ ++gceSTATUS ++gckHARDWARE_Nop( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN OUT gctSIZE_T * Bytes ++ ); ++ ++/* Add a PIPESELECT command in the command queue. */ ++gceSTATUS ++gckHARDWARE_PipeSelect( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gcePIPE_SELECT Pipe, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Add a LINK command in the command queue. */ ++gceSTATUS ++gckHARDWARE_Link( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT32 FetchAddress, ++ IN gctUINT32 FetchSize, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Add an EVENT command in the command queue. */ ++gceSTATUS ++gckHARDWARE_Event( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT8 Event, ++ IN gceKERNEL_WHERE FromWhere, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Query the available memory. */ ++gceSTATUS ++gckHARDWARE_QueryMemory( ++ IN gckHARDWARE Hardware, ++ OUT gctSIZE_T * InternalSize, ++ OUT gctUINT32 * InternalBaseAddress, ++ OUT gctUINT32 * InternalAlignment, ++ OUT gctSIZE_T * ExternalSize, ++ OUT gctUINT32 * ExternalBaseAddress, ++ OUT gctUINT32 * ExternalAlignment, ++ OUT gctUINT32 * HorizontalTileSize, ++ OUT gctUINT32 * VerticalTileSize ++ ); ++ ++/* Query the identity of the hardware. */ ++gceSTATUS ++gckHARDWARE_QueryChipIdentity( ++ IN gckHARDWARE Hardware, ++ OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity ++ ); ++ ++/* Query the shader uniforms support. */ ++gceSTATUS ++gckHARDWARE_QueryShaderCaps( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT * VertexUniforms, ++ OUT gctUINT * FragmentUniforms, ++ OUT gctBOOL * UnifiedUnforms ++ ); ++ ++/* Split a harwdare specific address into API stuff. */ ++gceSTATUS ++gckHARDWARE_SplitMemory( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Address, ++ OUT gcePOOL * Pool, ++ OUT gctUINT32 * Offset ++ ); ++ ++/* Update command queue tail pointer. */ ++gceSTATUS ++gckHARDWARE_UpdateQueueTail( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctUINT32 Offset ++ ); ++ ++/* Convert logical address to hardware specific address. */ ++gceSTATUS ++gckHARDWARE_ConvertLogical( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctBOOL InUserSpace, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Interrupt manager. */ ++gceSTATUS ++gckHARDWARE_Interrupt( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL InterruptValid ++ ); ++ ++/* Program MMU. */ ++gceSTATUS ++gckHARDWARE_SetMMU( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical ++ ); ++ ++/* Flush the MMU. */ ++gceSTATUS ++gckHARDWARE_FlushMMU( ++ IN gckHARDWARE Hardware ++ ); ++ ++/* Set the page table base address. */ ++gceSTATUS ++gckHARDWARE_SetMMUv2( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Enable, ++ IN gctPOINTER MtlbAddress, ++ IN gceMMU_MODE Mode, ++ IN gctPOINTER SafeAddress, ++ IN gctBOOL FromPower ++ ); ++ ++#if gcdPROCESS_ADDRESS_SPACE ++/* Configure mmu configuration. */ ++gceSTATUS ++gckHARDWARE_ConfigMMU( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctPOINTER MtlbLogical, ++ IN gctUINT32 Offset, ++ IN OUT gctSIZE_T * Bytes, ++ OUT gctSIZE_T * WaitLinkOffset, ++ OUT gctSIZE_T * WaitLinkBytes ++ ); ++#endif ++ ++/* Get idle register. */ ++gceSTATUS ++gckHARDWARE_GetIdle( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Wait, ++ OUT gctUINT32 * Data ++ ); ++ ++/* Flush the caches. */ ++gceSTATUS ++gckHARDWARE_Flush( ++ IN gckHARDWARE Hardware, ++ IN gceKERNEL_FLUSH Flush, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++/* Enable/disable fast clear. */ ++gceSTATUS ++gckHARDWARE_SetFastClear( ++ IN gckHARDWARE Hardware, ++ IN gctINT Enable, ++ IN gctINT Compression ++ ); ++ ++gceSTATUS ++gckHARDWARE_ReadInterrupt( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32_PTR IDs ++ ); ++ ++/* Power management. */ ++gceSTATUS ++gckHARDWARE_SetPowerManagementState( ++ IN gckHARDWARE Hardware, ++ IN gceCHIPPOWERSTATE State ++ ); ++ ++gceSTATUS ++gckHARDWARE_QueryPowerManagementState( ++ IN gckHARDWARE Hardware, ++ OUT gceCHIPPOWERSTATE* State ++ ); ++ ++gceSTATUS ++gckHARDWARE_SetPowerManagement( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL PowerManagement ++ ); ++ ++gceSTATUS ++gckHARDWARE_SetPowerManagementLock( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Lock ++ ); ++ ++gceSTATUS ++gckHARDWARE_SetGpuProfiler( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL GpuProfiler ++ ); ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++gceSTATUS ++gckHARDWARE_SetFscaleValue( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 FscaleValue ++ ); ++ ++gceSTATUS ++gckHARDWARE_GetFscaleValue( ++ IN gckHARDWARE Hardware, ++ IN gctUINT * FscaleValue, ++ IN gctUINT * MinFscaleValue, ++ IN gctUINT * MaxFscaleValue ++ ); ++ ++gceSTATUS ++gckHARDWARE_SetMinFscaleValue( ++ IN gckHARDWARE Hardware, ++ IN gctUINT MinFscaleValue ++ ); ++#endif ++ ++#if gcdPOWEROFF_TIMEOUT ++gceSTATUS ++gckHARDWARE_SetPowerOffTimeout( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Timeout ++); ++ ++gceSTATUS ++gckHARDWARE_QueryPowerOffTimeout( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32* Timeout ++); ++#endif ++ ++/* Profile 2D Engine. */ ++gceSTATUS ++gckHARDWARE_ProfileEngine2D( ++ IN gckHARDWARE Hardware, ++ OUT gcs2D_PROFILE_PTR Profile ++ ); ++ ++gceSTATUS ++gckHARDWARE_InitializeHardware( ++ IN gckHARDWARE Hardware ++ ); ++ ++gceSTATUS ++gckHARDWARE_Reset( ++ IN gckHARDWARE Hardware ++ ); ++ ++typedef gceSTATUS (*gctISRMANAGERFUNC)(gctPOINTER Context, gceCORE Core); ++ ++gceSTATUS ++gckHARDWARE_SetIsrManager( ++ IN gckHARDWARE Hardware, ++ IN gctISRMANAGERFUNC StartIsr, ++ IN gctISRMANAGERFUNC StopIsr, ++ IN gctPOINTER Context ++ ); ++ ++/* Start a composition. */ ++gceSTATUS ++gckHARDWARE_Compose( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 ProcessID, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gctSIZE_T Offset, ++ IN gctSIZE_T Size, ++ IN gctUINT8 EventID ++ ); ++ ++/* Check for Hardware features. */ ++gceSTATUS ++gckHARDWARE_IsFeatureAvailable( ++ IN gckHARDWARE Hardware, ++ IN gceFEATURE Feature ++ ); ++ ++gceSTATUS ++gckHARDWARE_DumpMMUException( ++ IN gckHARDWARE Hardware ++ ); ++ ++gceSTATUS ++gckHARDWARE_DumpGPUState( ++ IN gckHARDWARE Hardware ++ ); ++ ++gceSTATUS ++gckHARDWARE_InitDVFS( ++ IN gckHARDWARE Hardware ++ ); ++ ++gceSTATUS ++gckHARDWARE_QueryLoad( ++ IN gckHARDWARE Hardware, ++ OUT gctUINT32 * Load ++ ); ++ ++gceSTATUS ++gckHARDWARE_SetDVFSPeroid( ++ IN gckHARDWARE Hardware, ++ IN gctUINT32 Frequency ++ ); ++ ++gceSTATUS ++gckHARDWARE_PrepareFunctions( ++ gckHARDWARE Hardware ++ ); ++ ++gceSTATUS ++gckHARDWARE_SetMMUStates( ++ IN gckHARDWARE Hardware, ++ IN gctPOINTER MtlbAddress, ++ IN gceMMU_MODE Mode, ++ IN gctPOINTER SafeAddress, ++ IN gctPOINTER Logical, ++ IN OUT gctUINT32 * Bytes ++ ); ++ ++#if !gcdENABLE_VG ++/******************************************************************************\ ++***************************** gckINTERRUPT Object ****************************** ++\******************************************************************************/ ++ ++typedef struct _gckINTERRUPT * gckINTERRUPT; ++ ++typedef gceSTATUS (* gctINTERRUPT_HANDLER)( ++ IN gckKERNEL Kernel ++ ); ++ ++gceSTATUS ++gckINTERRUPT_Construct( ++ IN gckKERNEL Kernel, ++ OUT gckINTERRUPT * Interrupt ++ ); ++ ++gceSTATUS ++gckINTERRUPT_Destroy( ++ IN gckINTERRUPT Interrupt ++ ); ++ ++gceSTATUS ++gckINTERRUPT_SetHandler( ++ IN gckINTERRUPT Interrupt, ++ IN OUT gctINT32_PTR Id, ++ IN gctINTERRUPT_HANDLER Handler ++ ); ++ ++gceSTATUS ++gckINTERRUPT_Notify( ++ IN gckINTERRUPT Interrupt, ++ IN gctBOOL Valid ++ ); ++#endif ++/******************************************************************************\ ++******************************** gckEVENT Object ******************************* ++\******************************************************************************/ ++ ++typedef struct _gckEVENT * gckEVENT; ++ ++/* Construct a new gckEVENT object. */ ++gceSTATUS ++gckEVENT_Construct( ++ IN gckKERNEL Kernel, ++ OUT gckEVENT * Event ++ ); ++ ++/* Destroy an gckEVENT object. */ ++gceSTATUS ++gckEVENT_Destroy( ++ IN gckEVENT Event ++ ); ++ ++/* Add a new event to the list of events. */ ++gceSTATUS ++gckEVENT_AddList( ++ IN gckEVENT Event, ++ IN gcsHAL_INTERFACE_PTR Interface, ++ IN gceKERNEL_WHERE FromWhere, ++ IN gctBOOL AllocateAllowed, ++ IN gctBOOL FromKernel ++ ); ++ ++/* Schedule a FreeNonPagedMemory event. */ ++gceSTATUS ++gckEVENT_FreeNonPagedMemory( ++ IN gckEVENT Event, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gceKERNEL_WHERE FromWhere ++ ); ++ ++/* Schedule a FreeContiguousMemory event. */ ++gceSTATUS ++gckEVENT_FreeContiguousMemory( ++ IN gckEVENT Event, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gceKERNEL_WHERE FromWhere ++ ); ++ ++/* Schedule a FreeVideoMemory event. */ ++gceSTATUS ++gckEVENT_FreeVideoMemory( ++ IN gckEVENT Event, ++ IN gcuVIDMEM_NODE_PTR VideoMemory, ++ IN gceKERNEL_WHERE FromWhere ++ ); ++ ++/* Schedule a signal event. */ ++gceSTATUS ++gckEVENT_Signal( ++ IN gckEVENT Event, ++ IN gctSIGNAL Signal, ++ IN gceKERNEL_WHERE FromWhere ++ ); ++ ++/* Schedule an Unlock event. */ ++gceSTATUS ++gckEVENT_Unlock( ++ IN gckEVENT Event, ++ IN gceKERNEL_WHERE FromWhere, ++ IN gctPOINTER Node, ++ IN gceSURF_TYPE Type ++ ); ++ ++gceSTATUS ++gckEVENT_CommitDone( ++ IN gckEVENT Event, ++ IN gceKERNEL_WHERE FromWhere ++ ); ++ ++/* Schedule a FreeVirtualCommandBuffer event. */ ++gceSTATUS ++gckEVENT_DestroyVirtualCommandBuffer( ++ IN gckEVENT Event, ++ IN gctSIZE_T Bytes, ++ IN gctPHYS_ADDR Physical, ++ IN gctPOINTER Logical, ++ IN gceKERNEL_WHERE FromWhere ++ ); ++ ++gceSTATUS ++gckEVENT_Submit( ++ IN gckEVENT Event, ++ IN gctBOOL Wait, ++ IN gctBOOL FromPower, ++ IN gctBOOL FromCommand ++ ); ++ ++gceSTATUS ++gckEVENT_Commit( ++ IN gckEVENT Event, ++ IN gcsQUEUE_PTR Queue ++ ); ++ ++/* Schedule a composition event. */ ++gceSTATUS ++gckEVENT_Compose( ++ IN gckEVENT Event, ++ IN gcsHAL_COMPOSE_PTR Info ++ ); ++ ++/* Event callback routine. */ ++gceSTATUS ++gckEVENT_Notify( ++ IN gckEVENT Event, ++ IN gctUINT32 IDs ++ ); ++ ++/* Event callback routine. */ ++gceSTATUS ++gckEVENT_Interrupt( ++ IN gckEVENT Event, ++ IN gctUINT32 IDs ++ ); ++ ++gceSTATUS ++gckEVENT_Dump( ++ IN gckEVENT Event ++ ); ++/******************************************************************************\ ++******************************* gckCOMMAND Object ****************************** ++\******************************************************************************/ ++ ++typedef struct _gckCOMMAND * gckCOMMAND; ++ ++/* Construct a new gckCOMMAND object. */ ++gceSTATUS ++gckCOMMAND_Construct( ++ IN gckKERNEL Kernel, ++ OUT gckCOMMAND * Command ++ ); ++ ++/* Destroy an gckCOMMAND object. */ ++gceSTATUS ++gckCOMMAND_Destroy( ++ IN gckCOMMAND Command ++ ); ++ ++/* Acquire command queue synchronization objects. */ ++gceSTATUS ++gckCOMMAND_EnterCommit( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromPower ++ ); ++ ++/* Release command queue synchronization objects. */ ++gceSTATUS ++gckCOMMAND_ExitCommit( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromPower ++ ); ++ ++/* Start the command queue. */ ++gceSTATUS ++gckCOMMAND_Start( ++ IN gckCOMMAND Command ++ ); ++ ++/* Stop the command queue. */ ++gceSTATUS ++gckCOMMAND_Stop( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromRecovery ++ ); ++ ++gceSTATUS ++gckCOMMAND_Commit( ++ IN gckCOMMAND Command, ++ IN gckCONTEXT Context, ++ IN gcoCMDBUF CommandBuffer, ++ IN gcsSTATE_DELTA_PTR StateDelta, ++ IN gcsQUEUE_PTR EventQueue, ++ IN gctUINT32 ProcessID ++ ); ++ ++/* Reserve space in the command buffer. */ ++gceSTATUS ++gckCOMMAND_Reserve( ++ IN gckCOMMAND Command, ++ IN gctUINT32 RequestedBytes, ++ OUT gctPOINTER * Buffer, ++ OUT gctUINT32 * BufferSize ++ ); ++ ++/* Execute reserved space in the command buffer. */ ++gceSTATUS ++gckCOMMAND_Execute( ++ IN gckCOMMAND Command, ++ IN gctUINT32 RequstedBytes ++ ); ++ ++/* Stall the command queue. */ ++gceSTATUS ++gckCOMMAND_Stall( ++ IN gckCOMMAND Command, ++ IN gctBOOL FromPower ++ ); ++ ++/* Attach user process. */ ++gceSTATUS ++gckCOMMAND_Attach( ++ IN gckCOMMAND Command, ++ OUT gckCONTEXT * Context, ++ OUT gctSIZE_T * StateCount, ++ IN gctUINT32 ProcessID ++ ); ++ ++/* Detach user process. */ ++gceSTATUS ++gckCOMMAND_Detach( ++ IN gckCOMMAND Command, ++ IN gckCONTEXT Context ++ ); ++ ++/* Dump command buffer being executed by GPU. */ ++gceSTATUS ++gckCOMMAND_DumpExecutingBuffer( ++ IN gckCOMMAND Command ++ ); ++ ++/* Whether a kernel command buffer address. */ ++gceSTATUS ++gckCOMMAND_AddressInKernelCommandBuffer( ++ IN gckCOMMAND Command, ++ IN gctUINT32 Address, ++ OUT gctBOOL *In ++ ); ++ ++/******************************************************************************\ ++********************************* gckMMU Object ******************************** ++\******************************************************************************/ ++ ++typedef struct _gckMMU * gckMMU; ++ ++/* Construct a new gckMMU object. */ ++gceSTATUS ++gckMMU_Construct( ++ IN gckKERNEL Kernel, ++ IN gctSIZE_T MmuSize, ++ OUT gckMMU * Mmu ++ ); ++ ++/* Destroy an gckMMU object. */ ++gceSTATUS ++gckMMU_Destroy( ++ IN gckMMU Mmu ++ ); ++ ++/* Allocate pages inside the MMU. */ ++gceSTATUS ++gckMMU_AllocatePages( ++ IN gckMMU Mmu, ++ IN gctSIZE_T PageCount, ++ OUT gctPOINTER * PageTable, ++ OUT gctUINT32 * Address ++ ); ++ ++gceSTATUS ++gckMMU_AllocatePagesEx( ++ IN gckMMU Mmu, ++ IN gctSIZE_T PageCount, ++ IN gceSURF_TYPE Type, ++ OUT gctPOINTER * PageTable, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Remove a page table from the MMU. */ ++gceSTATUS ++gckMMU_FreePages( ++ IN gckMMU Mmu, ++ IN gctPOINTER PageTable, ++ IN gctSIZE_T PageCount ++ ); ++ ++/* Set the MMU page with info. */ ++gceSTATUS ++gckMMU_SetPage( ++ IN gckMMU Mmu, ++ IN gctUINT32 PageAddress, ++ IN gctUINT32 *PageEntry ++ ); ++ ++gceSTATUS ++gckMMU_Flush( ++ IN gckMMU Mmu, ++ IN gceSURF_TYPE Type ++ ); ++ ++gceSTATUS ++gckMMU_DumpPageTableEntry( ++ IN gckMMU Mmu, ++ IN gctUINT32 Address ++ ); ++ ++ ++#if VIVANTE_PROFILER ++gceSTATUS ++gckHARDWARE_QueryProfileRegisters( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Reset, ++ OUT gcsPROFILER_COUNTERS * Counters ++ ); ++#endif ++ ++#if VIVANTE_PROFILER_CONTEXT ++gceSTATUS ++gckHARDWARE_QueryContextProfile( ++ IN gckHARDWARE Hardware, ++ IN gctBOOL Reset, ++ IN gckCONTEXT Context, ++ OUT gcsPROFILER_COUNTERS * Counters ++ ); ++ ++gceSTATUS ++gckHARDWARE_UpdateContextProfile( ++ IN gckHARDWARE Hardware, ++ IN gckCONTEXT Context ++ ); ++#endif ++ ++#if VIVANTE_PROFILER_NEW ++gceSTATUS ++gckHARDWARE_InitProfiler( ++ IN gckHARDWARE Hardware ++ ); ++#endif ++ ++gceSTATUS ++gckOS_SignalQueryHardware( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ OUT gckHARDWARE * Hardware ++ ); ++ ++gceSTATUS ++gckOS_SignalSetHardware( ++ IN gckOS Os, ++ IN gctSIGNAL Signal, ++ gckHARDWARE Hardware ++ ); ++ ++gceSTATUS ++gckOS_DetectProcessByName( ++ IN gctCONST_POINTER Name ++ ); ++ ++void ++gckOS_DumpParam( ++ void ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#if gcdENABLE_VG ++#include "gc_hal_vg.h" ++#endif ++ ++#endif /* __gc_hal_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,218 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_kernel_buffer_h_ ++#define __gc_hal_kernel_buffer_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++************************ Command Buffer and Event Objects ********************** ++\******************************************************************************/ ++ ++/* The number of context buffers per user. */ ++#define gcdCONTEXT_BUFFER_COUNT 2 ++ ++/* State delta record. */ ++typedef struct _gcsSTATE_DELTA_RECORD * gcsSTATE_DELTA_RECORD_PTR; ++typedef struct _gcsSTATE_DELTA_RECORD ++{ ++ /* State address. */ ++ gctUINT address; ++ ++ /* State mask. */ ++ gctUINT32 mask; ++ ++ /* State data. */ ++ gctUINT32 data; ++} ++gcsSTATE_DELTA_RECORD; ++ ++/* State delta. */ ++typedef struct _gcsSTATE_DELTA ++{ ++ /* For debugging: the number of delta in the order of creation. */ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++ gctUINT num; ++#endif ++ ++ /* Main state delta ID. Every time state delta structure gets reinitialized, ++ main ID is incremented. If main state ID overflows, all map entry IDs get ++ reinitialized to make sure there is no potential erroneous match after ++ the overflow.*/ ++ gctUINT id; ++ ++ /* The number of contexts pending modification by the delta. */ ++ gctINT refCount; ++ ++ /* Vertex element count for the delta buffer. */ ++ gctUINT elementCount; ++ ++ /* Number of states currently stored in the record array. */ ++ gctUINT recordCount; ++ ++ /* Record array; holds all modified states in gcsSTATE_DELTA_RECORD. */ ++ gctUINT64 recordArray; ++ ++ /* Map entry ID is used for map entry validation. If map entry ID does not ++ match the main state delta ID, the entry and the corresponding state are ++ considered not in use. */ ++ gctUINT64 mapEntryID; ++ gctUINT mapEntryIDSize; ++ ++ /* If the map entry ID matches the main state delta ID, index points to ++ the state record in the record array. */ ++ gctUINT64 mapEntryIndex; ++ ++ /* Previous and next state deltas in gcsSTATE_DELTA. */ ++ gctUINT64 prev; ++ gctUINT64 next; ++} ++gcsSTATE_DELTA; ++ ++/* Command buffer patch record. */ ++struct _gcsPATCH ++{ ++ /* Pointer within the buffer. */ ++ gctUINT32_PTR pointer; ++ ++ /* 32-bit data to write at the specified offset. */ ++ gctUINT32 data; ++}; ++ ++/* List of patches for the command buffer. */ ++struct _gcsPATCH_LIST ++{ ++ /* Array of patch records. */ ++ struct _gcsPATCH patch[1024]; ++ ++ /* Number of patches in the array. */ ++ gctUINT count; ++ ++ /* Next item in the list. */ ++ struct _gcsPATCH_LIST *next; ++}; ++ ++/* Command buffer object. */ ++struct _gcoCMDBUF ++{ ++ /* The object. */ ++ gcsOBJECT object; ++ ++ /* Commit count. */ ++ gctUINT count; ++ ++ /* Command buffer entry and exit pipes. */ ++ gcePIPE_SELECT entryPipe; ++ gcePIPE_SELECT exitPipe; ++ ++ /* Feature usage flags. */ ++ gctBOOL using2D; ++ gctBOOL using3D; ++ gctBOOL usingFilterBlit; ++ gctBOOL usingPalette; ++ ++ /* Physical address of command buffer. Just a name. */ ++ gctUINT32 physical; ++ ++ /* Logical address of command buffer. */ ++ gctUINT64 logical; ++ ++ /* Number of bytes in command buffer. */ ++ gctUINT32 bytes; ++ ++ /* Start offset into the command buffer. */ ++ gctUINT32 startOffset; ++ ++ /* Current offset into the command buffer. */ ++ gctUINT32 offset; ++ ++ /* Number of free bytes in command buffer. */ ++ gctUINT32 free; ++ ++ /* Location of the last reserved area. */ ++ gctUINT64 lastReserve; ++ gctUINT32 lastOffset; ++ ++#if gcmIS_DEBUG(gcdDEBUG_CODE) ++ /* Last load state command location and hardware address. */ ++ gctUINT64 lastLoadStatePtr; ++ gctUINT32 lastLoadStateAddress; ++ gctUINT32 lastLoadStateCount; ++#endif ++ ++ /* Completion signal. */ ++ gctSIGNAL signal; ++ ++ /* List of patches. */ ++ struct _gcsPATCH_LIST *patchHead; ++ struct _gcsPATCH_LIST *patchTail; ++ ++ /* Link to the siblings. */ ++ gcoCMDBUF prev; ++ gcoCMDBUF next; ++}; ++ ++typedef struct _gcsQUEUE ++{ ++ /* Pointer to next gcsQUEUE structure in gcsQUEUE. */ ++ gctUINT64 next; ++ ++ /* Event information. */ ++ gcsHAL_INTERFACE iface; ++} ++gcsQUEUE; ++ ++/* Event queue. */ ++struct _gcoQUEUE ++{ ++ /* The object. */ ++ gcsOBJECT object; ++ ++ /* Pointer to current event queue. */ ++ gcsQUEUE_PTR head; ++ gcsQUEUE_PTR tail; ++ ++ /* chunks of the records. */ ++ gctPOINTER chunks; ++ ++ /* List of free records. */ ++ gcsQUEUE_PTR freeList; ++ ++ #define gcdIN_QUEUE_RECORD_LIMIT 16 ++ /* Number of records currently in queue */ ++ gctUINT32 recordCount; ++}; ++ ++struct _gcsTEMPCMDBUF ++{ ++ gctUINT32 currentByteSize; ++ gctPOINTER buffer; ++ gctBOOL inUse; ++}; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_kernel_buffer_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_mem.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_mem.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_mem.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_mem.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,530 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++/* ++** Include file for the local memory management. ++*/ ++ ++#ifndef __gc_hal_mem_h_ ++#define __gc_hal_mem_h_ ++#if (gcdENABLE_3D || gcdENABLE_VG) ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************* ++** Usage: ++ ++ The macros to declare MemPool type and functions are ++ gcmMEM_DeclareFSMemPool (Type, TypeName, Prefix) ++ gcmMEM_DeclareVSMemPool (Type, TypeName, Prefix) ++ gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) ++ ++ The data structures for MemPool are ++ typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; ++ typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; ++ typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; ++ ++ The MemPool constructor and destructor functions are ++ gcfMEM_InitFSMemPool(gcsMEM_FS_MEM_POOL *, gcoOS, gctUINT, gctUINT); ++ gcfMEM_FreeFSMemPool(gcsMEM_FS_MEM_POOL *); ++ gcfMEM_InitVSMemPool(gcsMEM_VS_MEM_POOL *, gcoOS, gctUINT, gctBOOL); ++ gcfMEM_FreeVSMemPool(gcsMEM_VS_MEM_POOL *); ++ gcfMEM_InitAFSMemPool(gcsMEM_AFS_MEM_POOL *, gcoOS, gctUINT); ++ gcfMEM_FreeAFSMemPool(gcsMEM_AFS_MEM_POOL *); ++ ++ FS: for Fixed-Size data structures ++ VS: for Variable-size data structures ++ AFS: for Array of Fixed-Size data structures ++ ++ ++ // Example 1: For a fixed-size data structure, struct gcsNode. ++ // It is used locally in a file, so the functions are static without prefix. ++ // At top level, declear allocate and free functions. ++ // The first argument is the data type. ++ // The second armument is the short name used in the fuctions. ++ gcmMEM_DeclareFSMemPool(struct gcsNode, Node, ); ++ ++ // The previous macro creates two inline functions, ++ // _AllocateNode and _FreeNode. ++ ++ // In function or struct ++ gcsMEM_FS_MEM_POOL nodeMemPool; ++ ++ // In function, ++ struct gcsNode * node; ++ gceSTATUS status; ++ ++ // Before using the memory pool, initialize it. ++ // The second argument is the gcoOS object. ++ // The third argument is the number of data structures to allocate for each chunk. ++ status = gcfMEM_InitFSMemPool(&nodeMemPool, os, 100, sizeof(struct gcsNode)); ++ ... ++ ++ // Allocate a node. ++ status = _AllocateNode(nodeMemPool, &node); ++ ... ++ // Free a node. ++ _FreeNode(nodeMemPool, node); ++ ++ // After using the memory pool, free it. ++ gcfMEM_FreeFSMemPool(&nodeMemPool); ++ ++ ++ // Example 2: For array of fixed-size data structures, struct gcsNode. ++ // It is used in several files, so the functions are extern with prefix. ++ // At top level, declear allocate and free functions. ++ // The first argument is the data type, and the second one is the short name ++ // used in the fuctions. ++ gcmMEM_DeclareAFSMemPool(struct gcsNode, NodeArray, gcfOpt); ++ ++ // The previous macro creates two inline functions, ++ // gcfOpt_AllocateNodeArray and gcfOpt_FreeNodeArray. ++ ++ // In function or struct ++ gcsMEM_AFS_MEM_POOL nodeArrayMemPool; ++ ++ // In function, ++ struct gcsNode * nodeArray; ++ gceSTATUS status; ++ ++ // Before using the array memory pool, initialize it. ++ // The second argument is the gcoOS object, the third is the number of data ++ // structures to allocate for each chunk. ++ status = gcfMEM_InitAFSMemPool(&nodeArrayMemPool, os, sizeof(struct gcsNode)); ++ ... ++ ++ // Allocate a node array of size 100. ++ status = gcfOpt_AllocateNodeArray(nodeArrayMemPool, &nodeArray, 100); ++ ... ++ // Free a node array. ++ gcfOpt_FreeNodeArray(&nodeArrayMemPool, nodeArray); ++ ++ // After using the array memory pool, free it. ++ gcfMEM_FreeAFSMemPool(&nodeArrayMemPool); ++ ++*******************************************************************************/ ++ ++/******************************************************************************* ++** To switch back to use gcoOS_Allocate and gcoOS_Free, add ++** #define USE_LOCAL_MEMORY_POOL 0 ++** before including this file. ++*******************************************************************************/ ++#ifndef USE_LOCAL_MEMORY_POOL ++/* ++ USE_LOCAL_MEMORY_POOL ++ ++ This define enables the local memory management to improve performance. ++*/ ++#define USE_LOCAL_MEMORY_POOL 1 ++#endif ++ ++/******************************************************************************* ++** Memory Pool Data Structures ++*******************************************************************************/ ++#if USE_LOCAL_MEMORY_POOL ++ typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; ++ typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; ++ typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; ++#else ++ typedef gcoOS gcsMEM_FS_MEM_POOL; ++ typedef gcoOS gcsMEM_VS_MEM_POOL; ++ typedef gcoOS gcsMEM_AFS_MEM_POOL; ++#endif ++ ++/******************************************************************************* ++** Memory Pool Macros ++*******************************************************************************/ ++#if USE_LOCAL_MEMORY_POOL ++#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ ++gceSTATUS \ ++Prefix##_Allocate##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type ** Pointer \ ++ ) \ ++{ \ ++ return(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_CAllocate##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type ** Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ gcmERR_RETURN(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ ++ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type)); \ ++ gcmFOOTER(); \ ++ return gcvSTATUS_OK; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_Free##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type * Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ status = gcfMEM_FSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_Free##TypeName##List( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type * FirstPointer, \ ++ Type * LastPointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x FirstPointer=0x%x LastPointer=0x%x", MemPool, FirstPointer, LastPointer); \ ++ status = gcfMEM_FSMemPoolFreeAList(MemPool, (gctPOINTER) FirstPointer, (gctPOINTER) LastPointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} ++ ++#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ ++gceSTATUS \ ++Prefix##_Allocate##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Size \ ++ ) \ ++{ \ ++ gceSTATUS status;\ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ ++ status = gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} \ ++ \ ++gceSTATUS \ ++ Prefix##_CAllocate##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Size \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ ++ gcmERR_RETURN(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \ ++ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, size); \ ++ gcmFOOTER(); \ ++ return gcvSTATUS_OK; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_Free##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type * Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pinter); \ ++ status = gcfMEM_VSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} ++ ++#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ ++gceSTATUS \ ++Prefix##_Allocate##TypeName( \ ++ gcsMEM_AFS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Count \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ ++ status = gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_CAllocate##TypeName( \ ++ gcsMEM_AFS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Count \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ ++ gcmERR_RETURN(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \ ++ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type)); \ ++ gcmFOOTER(); \ ++ return gcvSTATUS_OK; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_Free##TypeName( \ ++ gcsMEM_AFS_MEM_POOL MemPool, \ ++ Type * Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ status = gcfMEM_AFSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} ++ ++#else ++ ++#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ ++gceSTATUS \ ++Prefix##_Allocate##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type ** Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ status = gcoOS_Allocate(MemPool, \ ++ gcmSIZEOF(Type), \ ++ (gctPOINTER *) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_CAllocate##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type ** Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ gcmERR_RETURN(gcoOS_Allocate(MemPool, \ ++ gcmSIZEOF(Type), \ ++ (gctPOINTER *) Pointer)); \ ++ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type)); \ ++ gcmFOOTER(); \ ++ return gcvSTATUS_OK; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_Free##TypeName( \ ++ gcsMEM_FS_MEM_POOL MemPool, \ ++ Type * Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ status = gcmOS_SAFE_FREE(MemPool, Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} ++ ++#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ ++gceSTATUS \ ++Prefix##_Allocate##TypeName( \ ++ gcsMEM_VS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Size \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ ++ status = gcoOS_Allocate(MemPool, \ ++ Size, \ ++ (gctPOINTER *) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_CAllocate##TypeName( \ ++ gcsMEM_VS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Size \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ ++ gcmERR_RETURN(gcoOS_Allocate(MemPool, \ ++ Size, \ ++ (gctPOINTER *) Pointer)); \ ++ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Size); \ ++ gcmFOOTER(); \ ++ return gcvSTATUS_OK; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_Free##TypeName( \ ++ gcsMEM_VS_MEM_POOL MemPool, \ ++ Type * Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ status = gcmOS_SAFE_FREE(MemPool, Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} ++ ++#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ ++gceSTATUS \ ++Prefix##_Allocate##TypeName( \ ++ gcsMEM_AFS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Count \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ ++ status = gcoOS_Allocate(MemPool, \ ++ Count * gcmSIZEOF(Type), \ ++ (gctPOINTER *) Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_CAllocate##TypeName( \ ++ gcsMEM_AFS_MEM_POOL MemPool, \ ++ Type ** Pointer, \ ++ gctUINT Count \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ ++ gcmERR_RETURN(gcoOS_Allocate(MemPool, \ ++ Count * gcmSIZEOF(Type), \ ++ (gctPOINTER *) Pointer)); \ ++ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type)); \ ++ gcmFOOTER(); \ ++ return gcvSTATUS_OK; \ ++} \ ++ \ ++gceSTATUS \ ++Prefix##_Free##TypeName( \ ++ gcsMEM_AFS_MEM_POOL MemPool, \ ++ Type * Pointer \ ++ ) \ ++{ \ ++ gceSTATUS status; \ ++ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ ++ status = gcmOS_SAFE_FREE(MemPool, Pointer); \ ++ gcmFOOTER(); \ ++ return status; \ ++} ++#endif ++ ++/******************************************************************************* ++** Memory Pool Data Functions ++*******************************************************************************/ ++gceSTATUS ++gcfMEM_InitFSMemPool( ++ IN gcsMEM_FS_MEM_POOL * MemPool, ++ IN gcoOS OS, ++ IN gctUINT NodeCount, ++ IN gctUINT NodeSize ++ ); ++ ++gceSTATUS ++gcfMEM_FreeFSMemPool( ++ IN gcsMEM_FS_MEM_POOL * MemPool ++ ); ++ ++gceSTATUS ++gcfMEM_FSMemPoolGetANode( ++ IN gcsMEM_FS_MEM_POOL MemPool, ++ OUT gctPOINTER * Node ++ ); ++ ++gceSTATUS ++gcfMEM_FSMemPoolFreeANode( ++ IN gcsMEM_FS_MEM_POOL MemPool, ++ IN gctPOINTER Node ++ ); ++ ++gceSTATUS ++gcfMEM_FSMemPoolFreeAList( ++ IN gcsMEM_FS_MEM_POOL MemPool, ++ IN gctPOINTER FirstNode, ++ IN gctPOINTER LastNode ++ ); ++ ++gceSTATUS ++gcfMEM_InitVSMemPool( ++ IN gcsMEM_VS_MEM_POOL * MemPool, ++ IN gcoOS OS, ++ IN gctUINT BlockSize, ++ IN gctBOOL RecycleFreeNode ++ ); ++ ++gceSTATUS ++gcfMEM_FreeVSMemPool( ++ IN gcsMEM_VS_MEM_POOL * MemPool ++ ); ++ ++gceSTATUS ++gcfMEM_VSMemPoolGetANode( ++ IN gcsMEM_VS_MEM_POOL MemPool, ++ IN gctUINT Size, ++ IN gctUINT Alignment, ++ OUT gctPOINTER * Node ++ ); ++ ++gceSTATUS ++gcfMEM_VSMemPoolFreeANode( ++ IN gcsMEM_VS_MEM_POOL MemPool, ++ IN gctPOINTER Node ++ ); ++ ++gceSTATUS ++gcfMEM_InitAFSMemPool( ++ IN gcsMEM_AFS_MEM_POOL *MemPool, ++ IN gcoOS OS, ++ IN gctUINT NodeCount, ++ IN gctUINT NodeSize ++ ); ++ ++gceSTATUS ++gcfMEM_FreeAFSMemPool( ++ IN gcsMEM_AFS_MEM_POOL *MemPool ++ ); ++ ++gceSTATUS ++gcfMEM_AFSMemPoolGetANode( ++ IN gcsMEM_AFS_MEM_POOL MemPool, ++ IN gctUINT Count, ++ OUT gctPOINTER * Node ++ ); ++ ++gceSTATUS ++gcfMEM_AFSMemPoolFreeANode( ++ IN gcsMEM_AFS_MEM_POOL MemPool, ++ IN gctPOINTER Node ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* (gcdENABLE_3D || gcdENABLE_VG) */ ++#endif /* __gc_hal_mem_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_options.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_options.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_options.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_options.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,1194 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++#ifndef __gc_hal_options_h_ ++#define __gc_hal_options_h_ ++ ++/* ++ gcdPRINT_VERSION ++ ++ Print HAL version. ++*/ ++#ifndef gcdPRINT_VERSION ++# define gcdPRINT_VERSION 0 ++#endif ++ ++/* ++ VIVANTE_PROFILER ++ ++ This define enables the profiler. ++*/ ++#ifndef VIVANTE_PROFILER ++# define VIVANTE_PROFILER 1 ++#endif ++ ++/* ++ VIVANTE_PROFILER_CONTEXT ++ ++ This define enables the profiler according each context. ++*/ ++#ifndef VIVANTE_PROFILER_CONTEXT ++# define VIVANTE_PROFILER_CONTEXT 1 ++#endif ++ ++#ifndef VIVANTE_PROFILER_PERDRAW ++# define VIVANTE_PROFILER_PERDRAW 0 ++#endif ++ ++#ifndef VIVANTE_PROFILER_NEW ++# define VIVANTE_PROFILER_NEW 0 ++#endif ++ ++#ifndef VIVANTE_PROFILER_PM ++# define VIVANTE_PROFILER_PM 1 ++#endif ++/* ++ gcdUSE_VG ++ ++ Enable VG HAL layer (only for GC350). ++*/ ++#ifndef gcdUSE_VG ++# define gcdUSE_VG 0 ++#endif ++ ++/* ++ USE_SW_FB ++ ++ Set to 1 if the frame buffer memory cannot be accessed by the GPU. ++*/ ++#ifndef USE_SW_FB ++# define USE_SW_FB 0 ++#endif ++ ++/* ++ PROFILE_HAL_COUNTERS ++ ++ This define enables HAL counter profiling support. HW and SHADER ++ counter profiling depends on this. ++*/ ++#ifndef PROFILE_HAL_COUNTERS ++# define PROFILE_HAL_COUNTERS 1 ++#endif ++ ++/* ++ PROFILE_HW_COUNTERS ++ ++ This define enables HW counter profiling support. ++*/ ++#ifndef PROFILE_HW_COUNTERS ++# define PROFILE_HW_COUNTERS 1 ++#endif ++ ++/* ++ PROFILE_SHADER_COUNTERS ++ ++ This define enables SHADER counter profiling support. ++*/ ++#ifndef PROFILE_SHADER_COUNTERS ++# define PROFILE_SHADER_COUNTERS 1 ++#endif ++ ++/* ++ gcdDUMP_KEY ++ ++ Set this to a string that appears in 'cat /proc//cmdline'. E.g. 'camera'. ++ HAL will create dumps for the processes matching this key. ++*/ ++#ifndef gcdDUMP_KEY ++# define gcdDUMP_KEY "process" ++#endif ++ ++/* ++ gcdDUMP_PATH ++ ++ The dump file location. Some processes cannot write to the sdcard. ++ Try apps' data dir, e.g. /data/data/com.android.launcher ++*/ ++#ifndef gcdDUMP_PATH ++#if defined(ANDROID) ++# define gcdDUMP_PATH "/mnt/sdcard/" ++#else ++# define gcdDUMP_PATH "./" ++#endif ++#endif ++ ++/* ++ gcdDUMP ++ ++ When set to 1, a dump of all states and memory uploads, as well as other ++ hardware related execution will be printed to the debug console. This ++ data can be used for playing back applications. ++*/ ++#ifndef gcdDUMP ++# define gcdDUMP 0 ++#endif ++ ++/* ++ gcdDUMP_API ++ ++ When set to 1, a high level dump of the EGL and GL/VG APs's are ++ captured. ++*/ ++#ifndef gcdDUMP_API ++# define gcdDUMP_API 0 ++#endif ++ ++ ++ ++/* ++ gcdDEBUG_OPTION ++ When set to 1, the debug options are enabled. We must set other MACRO to enable ++ sub case. ++*/ ++#ifndef gcdDEBUG_OPTION ++# define gcdDEBUG_OPTION 0 ++ ++#if gcdDEBUG_OPTION ++/* ++ gcdDEBUG_OPTION_KEY ++ The process name of debug application. ++*/ ++#ifndef gcdDEBUG_OPTION_KEY ++# define gcdDEBUG_OPTION_KEY "process" ++# endif ++/* ++ gcdDEBUG_OPTION_NO_GL_DRAWS ++ When set to 1, all glDrawArrays and glDrawElements will be skip. ++*/ ++#ifndef gcdDEBUG_OPTION_NO_GL_DRAWS ++# define gcdDEBUG_OPTION_NO_GL_DRAWS 0 ++# endif ++/* ++ gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES ++ When set to 1, all DrawPrimitives will be skip. ++*/ ++#ifndef gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES ++# define gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES 0 ++# endif ++/* ++ gcdDEBUG_OPTION_SKIP_SWAP ++ When set to 1, just one out of gcdDEBUG_OPTION_SKIP_FRAMES(such as 1/10) eglSwapBuffers will be resolve, ++ others skip. ++*/ ++#ifndef gcdDEBUG_OPTION_SKIP_SWAP ++# define gcdDEBUG_OPTION_SKIP_SWAP 0 ++# define gcdDEBUG_OPTION_SKIP_FRAMES 10 ++# endif ++/* ++ gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET ++ When set to 1, the format of render target will force to RGB565. ++*/ ++#ifndef gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET ++# define gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET 0 ++# endif ++/* ++ gcdDEBUG_OPTION_NONE_TEXTURE ++ When set to 1, the type of texture will be set to AQ_TEXTURE_SAMPLE_MODE_TYPE_NONE. ++*/ ++#ifndef gcdDEBUG_OPTION_NONE_TEXTURE ++# define gcdDEBUG_OPTION_NONE_TEXTURE 0 ++# endif ++/* ++ gcdDEBUG_OPTION_NONE_DEPTH ++ When set to 1, the depth format of surface will be set to gcvSURF_UNKNOWN. ++*/ ++#ifndef gcdDEBUG_OPTION_NONE_DEPTH ++# define gcdDEBUG_OPTION_NONE_DEPTH 0 ++# endif ++ ++# endif ++#endif ++ ++/* ++ gcdDUMP_SWAP_PER_DRAW ++ ++ When set to 1, dump swap command for every single draw to make simulation comparison happy. ++ Only valid for ES3 driver for now. ++*/ ++#ifndef gcdDUMP_SWAP_PER_DRAW ++# define gcdDUMP_SWAP_PER_DRAW 0 ++#endif ++ ++/* ++ gcdDUMP_FRAMERATE ++ When set to a value other than zero, averaqe frame rate will be dumped. ++ The value set is the starting frame that the average will be calculated. ++ This is needed because sometimes first few frames are too slow to be included ++ in the average. Frame count starts from 1. ++*/ ++#ifndef gcdDUMP_FRAMERATE ++# define gcdDUMP_FRAMERATE 0 ++#endif ++ ++/* ++ gcdENABLE_FSCALE_VAL_ADJUST ++ When non-zero, FSCALE_VAL when gcvPOWER_ON can be adjusted externally. ++ */ ++#ifndef gcdENABLE_FSCALE_VAL_ADJUST ++# define gcdENABLE_FSCALE_VAL_ADJUST 1 ++#endif ++ ++/* ++ gcdDUMP_IN_KERNEL ++ ++ When set to 1, all dumps will happen in the kernel. This is handy if ++ you want the kernel to dump its command buffers as well and the data ++ needs to be in sync. ++*/ ++#ifndef gcdDUMP_IN_KERNEL ++# define gcdDUMP_IN_KERNEL 0 ++#endif ++ ++/* ++ gcdDUMP_COMMAND ++ ++ When set to non-zero, the command queue will dump all incoming command ++ and context buffers as well as all other modifications to the command ++ queue. ++*/ ++#ifndef gcdDUMP_COMMAND ++# define gcdDUMP_COMMAND 0 ++#endif ++ ++/* ++ gcdDUMP_2D ++ ++ When set to non-zero, it will dump the 2D command and surface. ++*/ ++#ifndef gcdDUMP_2D ++# define gcdDUMP_2D 0 ++#endif ++ ++/* ++ gcdDUMP_FRAME_TGA ++ ++ When set to a value other than 0, a dump of the frame specified by the value, ++ will be done into frame.tga. Frame count starts from 1. ++ */ ++#ifndef gcdDUMP_FRAME_TGA ++# define gcdDUMP_FRAME_TGA 0 ++#endif ++/* ++ gcdNULL_DRIVER ++ ++ Set to 1 for infinite speed hardware. ++ Set to 2 for bypassing the HAL. ++ Set to 3 for bypassing the drivers. ++*/ ++#ifndef gcdNULL_DRIVER ++# define gcdNULL_DRIVER 0 ++#endif ++ ++/* ++ gcdENABLE_TIMEOUT_DETECTION ++ ++ Enable timeout detection. ++*/ ++#ifndef gcdENABLE_TIMEOUT_DETECTION ++# define gcdENABLE_TIMEOUT_DETECTION 0 ++#endif ++ ++/* ++ gcdCMD_BUFFER_SIZE ++ ++ Number of bytes in a command buffer. ++*/ ++#ifndef gcdCMD_BUFFER_SIZE ++# define gcdCMD_BUFFER_SIZE (128 << 10) ++#endif ++ ++/* ++ gcdCMD_BUFFERS ++ ++ Number of command buffers to use per client. ++*/ ++#ifndef gcdCMD_BUFFERS ++# define gcdCMD_BUFFERS 2 ++#endif ++ ++/* ++ gcdMAX_CMD_BUFFERS ++ ++ Maximum number of command buffers to use per client. ++*/ ++#ifndef gcdMAX_CMD_BUFFERS ++# define gcdMAX_CMD_BUFFERS 8 ++#endif ++ ++/* ++ gcdCOMMAND_QUEUES ++ ++ Number of command queues in the kernel. ++*/ ++#ifndef gcdCOMMAND_QUEUES ++# define gcdCOMMAND_QUEUES 2 ++#endif ++ ++/* ++ gcdPOWER_CONTROL_DELAY ++ ++ The delay in milliseconds required to wait until the GPU has woke up ++ from a suspend or power-down state. This is system dependent because ++ the bus clock also needs to stabalize. ++*/ ++#ifndef gcdPOWER_CONTROL_DELAY ++# define gcdPOWER_CONTROL_DELAY 0 ++#endif ++ ++/* ++ gcdMIRROR_PAGETABLE ++ ++ Enable it when GPUs with old MMU and new MMU exist at same SoC. It makes ++ each GPU use same virtual address to access same physical memory. ++*/ ++#ifndef gcdMIRROR_PAGETABLE ++# define gcdMIRROR_PAGETABLE 0 ++#endif ++ ++/* ++ gcdMMU_SIZE ++ ++ Size of the MMU page table in bytes. Each 4 bytes can hold 4kB worth of ++ virtual data. ++*/ ++#ifndef gcdMMU_SIZE ++#if gcdMIRROR_PAGETABLE ++# define gcdMMU_SIZE 0x200000 ++#else ++# define gcdMMU_SIZE (2048 << 10) ++#endif ++#endif ++ ++/* ++ gcdSECURE_CACHE_SLOTS ++ ++ Number of slots in the logical to DMA address cache table. Each time a ++ logical address needs to be translated into a DMA address for the GPU, ++ this cache will be walked. The replacement scheme is LRU. ++*/ ++#ifndef gcdSECURE_CACHE_SLOTS ++# define gcdSECURE_CACHE_SLOTS 1024 ++#endif ++ ++/* ++ gcdSECURE_CACHE_METHOD ++ ++ Replacement scheme used for Secure Cache. The following options are ++ available: ++ ++ gcdSECURE_CACHE_LRU ++ A standard LRU cache. ++ ++ gcdSECURE_CACHE_LINEAR ++ A linear walker with the idea that an application will always ++ render the scene in a similar way, so the next entry in the ++ cache should be a hit most of the time. ++ ++ gcdSECURE_CACHE_HASH ++ A 256-entry hash table. ++ ++ gcdSECURE_CACHE_TABLE ++ A simple cache but with potential of a lot of cache replacement. ++*/ ++#ifndef gcdSECURE_CACHE_METHOD ++# define gcdSECURE_CACHE_METHOD gcdSECURE_CACHE_HASH ++#endif ++ ++/* ++ gcdREGISTER_ACCESS_FROM_USER ++ ++ Set to 1 to allow IOCTL calls to get through from user land. This ++ should only be in debug or development drops. ++*/ ++#ifndef gcdREGISTER_ACCESS_FROM_USER ++# define gcdREGISTER_ACCESS_FROM_USER 1 ++#endif ++ ++/* ++ gcdHEAP_SIZE ++ ++ Set the allocation size for the internal heaps. Each time a heap is ++ full, a new heap will be allocated with this minmimum amount of bytes. ++ The bigger this size, the fewer heaps there are to allocate, the better ++ the performance. However, heaps won't be freed until they are ++ completely free, so there might be some more memory waste if the size is ++ too big. ++*/ ++#ifndef gcdHEAP_SIZE ++# define gcdHEAP_SIZE (64 << 10) ++#endif ++ ++/* ++ gcdPOWER_SUSPEND_WHEN_IDLE ++ ++ Set to 1 to make GPU enter gcvPOWER_SUSPEND when idle detected, ++ otherwise GPU will enter gcvPOWER_IDLE. ++*/ ++#ifndef gcdPOWER_SUSPEND_WHEN_IDLE ++# define gcdPOWER_SUSPEND_WHEN_IDLE 0 ++#endif ++ ++#ifndef gcdFPGA_BUILD ++# define gcdFPGA_BUILD 0 ++#endif ++ ++/* ++ gcdGPU_TIMEOUT ++ ++ This define specified the number of milliseconds the system will wait ++ before it broadcasts the GPU is stuck. In other words, it will define ++ the timeout of any operation that needs to wait for the GPU. ++ ++ If the value is 0, no timeout will be checked for. ++*/ ++#ifndef gcdGPU_TIMEOUT ++#if gcdFPGA_BUILD ++# define gcdGPU_TIMEOUT 0 ++# define gcdGPU_2D_TIMEOUT 0 ++# else ++# define gcdGPU_TIMEOUT 20000 ++# define gcdGPU_2D_TIMEOUT 4000 ++# endif ++#endif ++ ++/* ++ gcdGPU_ADVANCETIMER ++ ++ it is advance timer. ++*/ ++#ifndef gcdGPU_ADVANCETIMER ++# define gcdGPU_ADVANCETIMER 250 ++#endif ++ ++/* ++ gcdSTATIC_LINK ++ ++ This define disalbes static linking; ++*/ ++#ifndef gcdSTATIC_LINK ++# define gcdSTATIC_LINK 0 ++#endif ++ ++/* ++ gcdUSE_NEW_HEAP ++ ++ Setting this define to 1 enables new heap. ++*/ ++#ifndef gcdUSE_NEW_HEAP ++# define gcdUSE_NEW_HEAP 0 ++#endif ++ ++/* ++ gcdCMD_NO_2D_CONTEXT ++ ++ This define enables no-context 2D command buffer. ++*/ ++#ifndef gcdCMD_NO_2D_CONTEXT ++# define gcdCMD_NO_2D_CONTEXT 1 ++#endif ++ ++/* ++ gcdENABLE_BUFFER_ALIGNMENT ++ ++ When enabled, video memory is allocated with atleast 16KB aligment ++ between multiple sub-buffers. ++*/ ++#ifndef gcdENABLE_BUFFER_ALIGNMENT ++# define gcdENABLE_BUFFER_ALIGNMENT 1 ++#endif ++ ++/* ++ gcdENABLE_BANK_ALIGNMENT ++ ++ When enabled, video memory is allocated bank aligned. The vendor can modify ++ _GetSurfaceBankAlignment() and _GetBankOffsetBytes() to define how ++ different types of allocations are bank and channel aligned. ++ When disabled (default), no bank alignment is done. ++*/ ++#ifndef gcdENABLE_BANK_ALIGNMENT ++# define gcdENABLE_BANK_ALIGNMENT 0 ++#endif ++ ++/* ++ gcdBANK_BIT_START ++ ++ Specifies the start bit of the bank (inclusive). ++*/ ++#ifndef gcdBANK_BIT_START ++# define gcdBANK_BIT_START 12 ++#endif ++ ++/* ++ gcdBANK_BIT_END ++ ++ Specifies the end bit of the bank (inclusive). ++*/ ++#ifndef gcdBANK_BIT_END ++# define gcdBANK_BIT_END 14 ++#endif ++ ++/* ++ gcdBANK_CHANNEL_BIT ++ ++ When set, video memory when allocated bank aligned is allocated such that ++ render and depth buffer addresses alternate on the channel bit specified. ++ This option has an effect only when gcdENABLE_BANK_ALIGNMENT is enabled. ++ When disabled (default), no alteration is done. ++*/ ++#ifndef gcdBANK_CHANNEL_BIT ++# define gcdBANK_CHANNEL_BIT 7 ++#endif ++ ++/* ++ gcdDYNAMIC_SPEED ++ ++ When non-zero, it informs the kernel driver to use the speed throttling ++ broadcasting functions to inform the system the GPU should be spet up or ++ slowed down. It will send a broadcast for slowdown each "interval" ++ specified by this define in milliseconds ++ (gckOS_BroadcastCalibrateSpeed). ++*/ ++#ifndef gcdDYNAMIC_SPEED ++# define gcdDYNAMIC_SPEED 2000 ++#endif ++ ++/* ++ gcdDYNAMIC_EVENT_THRESHOLD ++ ++ When non-zero, it specifies the maximum number of available events at ++ which the kernel driver will issue a broadcast to speed up the GPU ++ (gckOS_BroadcastHurry). ++*/ ++#ifndef gcdDYNAMIC_EVENT_THRESHOLD ++# define gcdDYNAMIC_EVENT_THRESHOLD 5 ++#endif ++ ++/* ++ gcdENABLE_PROFILING ++ ++ Enable profiling macros. ++*/ ++#ifndef gcdENABLE_PROFILING ++# define gcdENABLE_PROFILING 0 ++#endif ++ ++/* ++ gcdENABLE_128B_MERGE ++ ++ Enable 128B merge for the BUS control. ++*/ ++#ifndef gcdENABLE_128B_MERGE ++# define gcdENABLE_128B_MERGE 0 ++#endif ++ ++/* ++ gcdFRAME_DB ++ ++ When non-zero, it specified the number of frames inside the frame ++ database. The frame DB will collect per-frame timestamps and hardware ++ counters. ++*/ ++#ifndef gcdFRAME_DB ++# define gcdFRAME_DB 0 ++# define gcdFRAME_DB_RESET 0 ++# define gcdFRAME_DB_NAME "/var/log/frameDB.log" ++#endif ++ ++/* ++ gcdDISABLE_CORES_2D3D ++ disable the 2D3D cores for 2D openVG ++*/ ++#ifndef gcdDISABLE_CORES_2D3D ++# define gcdDISABLE_CORES_2D3D 0 ++#endif ++ ++/* ++ gcdPAGED_MEMORY_CACHEABLE ++ ++ When non-zero, paged memory will be cacheable. ++ ++ Normally, driver will detemines whether a video memory ++ is cacheable or not. When cacheable is not neccessary, ++ it will be writecombine. ++ ++ This option is only for those SOC which can't enable ++ writecombine without enabling cacheable. ++*/ ++#ifndef gcdPAGED_MEMORY_CACHEABLE ++# define gcdPAGED_MEMORY_CACHEABLE 0 ++#endif ++ ++/* ++ gcdNONPAGED_MEMORY_CACHEABLE ++ ++ When non-zero, non paged memory will be cacheable. ++*/ ++#ifndef gcdNONPAGED_MEMORY_CACHEABLE ++# define gcdNONPAGED_MEMORY_CACHEABLE 0 ++#endif ++ ++/* ++ gcdNONPAGED_MEMORY_BUFFERABLE ++ ++ When non-zero, non paged memory will be bufferable. ++ gcdNONPAGED_MEMORY_BUFFERABLE and gcdNONPAGED_MEMORY_CACHEABLE ++ can't be set 1 at same time ++*/ ++#ifndef gcdNONPAGED_MEMORY_BUFFERABLE ++# define gcdNONPAGED_MEMORY_BUFFERABLE 1 ++#endif ++ ++/* ++ gcdENABLE_INFINITE_SPEED_HW ++ enable the Infinte HW , this is for 2D openVG ++*/ ++#ifndef gcdENABLE_INFINITE_SPEED_HW ++# define gcdENABLE_INFINITE_SPEED_HW 0 ++#endif ++ ++/* ++ gcdPOWEROFF_TIMEOUT ++ ++ When non-zero, GPU will power off automatically from ++ idle state, and gcdPOWEROFF_TIMEOUT is also the default ++ timeout in milliseconds. ++ */ ++#ifndef gcdPOWEROFF_TIMEOUT ++# define gcdPOWEROFF_TIMEOUT 300 ++#endif ++ ++/* ++ gcdRENDER_THREADS ++ ++ Number of render threads. Make it zero, and there will be no render ++ threads. ++*/ ++#ifndef gcdRENDER_THREADS ++# define gcdRENDER_THREADS 0 ++#endif ++ ++/* ++ gcdSMP ++ ++ This define enables SMP support. ++ ++ Currently, it only works on Linux/Android, ++ Kbuild will config it according to whether ++ CONFIG_SMP is set. ++ ++*/ ++#ifndef gcdSMP ++# define gcdSMP 0 ++#endif ++ ++/* ++ gcdSHARED_RESOLVE_BUFFER_ENABLED ++ ++ Use shared resolve buffer for all app buffers. ++*/ ++#ifndef gcdSHARED_RESOLVE_BUFFER_ENABLED ++# define gcdSHARED_RESOLVE_BUFFER_ENABLED 0 ++#endif ++ ++/* ++ gcdUSE_TRIANGLE_STRIP_PATCH ++ */ ++#ifndef gcdUSE_TRIANGLE_STRIP_PATCH ++# define gcdUSE_TRIANGLE_STRIP_PATCH 1 ++#endif ++ ++/* ++ gcdPROCESS_ADDRESS_SPACE ++ ++ When non-zero, every process which attaches to galcore has its own GPU ++ address space, size of which is gcdPROCESS_ADDRESS_SPACE_SIZE. ++*/ ++#ifndef gcdPROCESS_ADDRESS_SPACE ++# define gcdPROCESS_ADDRESS_SPACE 0 ++# define gcdPROCESS_ADDRESS_SPACE_SIZE 0x80000000 ++#endif ++ ++/* ++ gcdSHARED_PAGETABLE ++ ++ When non-zero, multiple GPUs in one chip with same MMU use ++ one shared pagetable. So that when accessing same surface, ++ they can use same GPU virtual address. ++*/ ++#ifndef gcdSHARED_PAGETABLE ++# define gcdSHARED_PAGETABLE !gcdPROCESS_ADDRESS_SPACE ++#endif ++ ++#ifndef gcdUSE_PVR ++# define gcdUSE_PVR 1 ++#endif ++ ++/* ++ gcdSMALL_BLOCK_SIZE ++ ++ When non-zero, a part of VIDMEM will be reserved for requests ++ whose requesting size is less than gcdSMALL_BLOCK_SIZE. ++ ++ For Linux, it's the size of a page. If this requeset fallbacks ++ to gcvPOOL_CONTIGUOUS or gcvPOOL_VIRTUAL, memory will be wasted ++ because they allocate a page at least. ++*/ ++#ifndef gcdSMALL_BLOCK_SIZE ++# define gcdSMALL_BLOCK_SIZE 4096 ++# define gcdRATIO_FOR_SMALL_MEMORY 32 ++#endif ++ ++/* ++ gcdCONTIGUOUS_SIZE_LIMIT ++ When non-zero, size of video node from gcvPOOL_CONTIGUOUS is ++ limited by gcdCONTIGUOUS_SIZE_LIMIT. ++*/ ++#ifndef gcdCONTIGUOUS_SIZE_LIMIT ++# define gcdCONTIGUOUS_SIZE_LIMIT 0 ++#endif ++ ++/* ++ gcdLINK_QUEUE_SIZE ++ ++ When non-zero, driver maintains a queue to record information of ++ latest lined context buffer and command buffer. Data in this queue ++ is be used to debug. ++*/ ++#ifndef gcdLINK_QUEUE_SIZE ++# define gcdLINK_QUEUE_SIZE 5 ++#endif ++ ++/* gcdALPHA_KILL_IN_SHADER ++ ++ Enable alpha kill inside the shader. This will be set automatically by the ++ HAL if certain states match a criteria. ++*/ ++#ifndef gcdALPHA_KILL_IN_SHADER ++# define gcdALPHA_KILL_IN_SHADER 1 ++#endif ++ ++ ++ ++/* ++ gcdDVFS ++ ++ When non-zero, software will make use of dynamic voltage and ++ frequency feature. ++ */ ++#ifndef gcdDVFS ++# define gcdDVFS 0 ++# define gcdDVFS_ANAYLSE_WINDOW 4 ++# define gcdDVFS_POLLING_TIME (gcdDVFS_ANAYLSE_WINDOW * 4) ++#endif ++ ++#ifndef gcdSYNC ++# define gcdSYNC 1 ++#endif ++ ++#ifndef gcdSHADER_SRC_BY_MACHINECODE ++# define gcdSHADER_SRC_BY_MACHINECODE 1 ++#endif ++ ++#ifndef gcdGLB27_SHADER_REPLACE_OPTIMIZATION ++# define gcdGLB27_SHADER_REPLACE_OPTIMIZATION 1 ++#endif ++ ++/* ++ gcdSTREAM_OUT_BUFFER ++ ++ Enable suppport for the secondary stream out buffer. ++*/ ++#ifndef gcdSTREAM_OUT_BUFFER ++# define gcdSTREAM_OUT_BUFFER 0 ++# define gcdSTREAM_OUT_NAIVE_SYNC 0 ++#endif ++ ++/* ++ gcdUSE_HARDWARE_CONFIGURATION_TABLES ++ ++ Enable the use of hardware configuration tables, ++ instead of query hardware and determine the features. ++*/ ++#ifndef gcdUSE_HARDWARE_CONFIGURATION_TABLES ++# define gcdUSE_HARDWARE_CONFIGURATION_TABLES 0 ++#endif ++ ++/* ++ gcdSUPPORT_SWAP_RECTANGLE ++ ++ Support swap with a specific rectangle. ++ ++ Set the rectangle with eglSetSwapRectangleVIV api. ++ Android only. ++*/ ++#ifndef gcdSUPPORT_SWAP_RECTANGLE ++# define gcdSUPPORT_SWAP_RECTANGLE 1 ++#endif ++ ++/* ++ gcdGPU_LINEAR_BUFFER_ENABLED ++ ++ Use linear buffer for GPU apps so HWC can do 2D composition. ++ Android only. ++*/ ++#ifndef gcdGPU_LINEAR_BUFFER_ENABLED ++# define gcdGPU_LINEAR_BUFFER_ENABLED 1 ++#endif ++ ++/* ++ gcdENABLE_RENDER_INTO_WINDOW ++ ++ Enable Render-Into-Window (ie, No-Resolve) feature on android. ++ NOTE that even if enabled, it still depends on hardware feature and ++ android application behavior. When hardware feature or application ++ behavior can not support render into window mode, it will fail back ++ to normal mode. ++ When Render-Into-Window is finally used, window back buffer of android ++ applications will be allocated matching render target tiling format. ++ Otherwise buffer tiling is decided by the above option ++ 'gcdGPU_LINEAR_BUFFER_ENABLED'. ++ Android only for now. ++*/ ++#ifndef gcdENABLE_RENDER_INTO_WINDOW ++# define gcdENABLE_RENDER_INTO_WINDOW 1 ++#endif ++ ++/* ++ gcdENABLE_RENDER_INTO_WINDOW_WITH_FC ++ ++ Enable Direct-rendering (ie, No-Resolve) with tile status. ++ This is expremental and in development stage. ++ This will dynamically check if color compression is available. ++*/ ++#ifndef gcdENABLE_RENDER_INTO_WINDOW_WITH_FC ++# define gcdENABLE_RENDER_INTO_WINDOW_WITH_FC 1 ++#endif ++ ++/* ++ gcdENABLE_BLIT_BUFFER_PRESERVE ++ ++ Render-Into-Window (ie, No-Resolve) does not include preserved swap ++ behavior. This feature can enable buffer preserve in No-Resolve mode. ++ When enabled, previous buffer (may be part of ) will be resolve-blitted ++ to current buffer. ++*/ ++#ifndef gcdENABLE_BLIT_BUFFER_PRESERVE ++# define gcdENABLE_BLIT_BUFFER_PRESERVE 1 ++#endif ++ ++/* ++ gcdANDROID_NATIVE_FENCE_SYNC ++ ++ Enable android native fence sync. It is introduced since jellybean-4.2. ++ Depends on linux kernel option: CONFIG_SYNC. ++ ++ 0: Disabled ++ 1: Build framework for native fence sync feature, and EGL extension ++ 2: Enable async swap buffers for client ++ * Native fence sync for client 'queueBuffer' in EGL, which is ++ 'acquireFenceFd' for layer in compositor side. ++ 3. Enable async hwcomposer composition. ++ * 'releaseFenceFd' for layer in compositor side, which is native ++ fence sync when client 'dequeueBuffer' ++ * Native fence sync for compositor 'queueBuffer' in EGL, which is ++ 'acquireFenceFd' for framebuffer target for DC ++ */ ++#ifndef gcdANDROID_NATIVE_FENCE_SYNC ++# define gcdANDROID_NATIVE_FENCE_SYNC 0 ++#endif ++ ++/* ++ gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC ++ ++ Enable implicit android native buffer sync. ++ ++ For non-HW_RENDER buffer, CPU (or other hardware) and GPU can access ++ the buffer at the same time. This is to add implicit synchronization ++ between CPU (or the hardware) and GPU. ++ ++ Eventually, please do not use implicit native buffer sync, but use ++ "fence sync" or "android native fence sync" instead in libgui, which ++ can be enabled in frameworks/native/libs/gui/Android.mk. This kind ++ of synchronization should be done by app but not driver itself. ++ ++ Please disable this option when either "fence sync" or ++ "android native fence sync" is enabled. ++ */ ++#ifndef gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC ++# define gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC 1 ++#endif ++ ++/* ++ * Implicit native buffer sync is not needed when ANDROID_native_fence_sync ++ * is available. ++ */ ++#if gcdANDROID_NATIVE_FENCE_SYNC ++# undef gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC ++# define gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC 0 ++#endif ++ ++/* ++ gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST ++ ++ Enable source surface address adjust when composition on android. ++ Android only. ++*/ ++#ifndef gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST ++# define gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST 1 ++#endif ++ ++/* ++ gcdUSE_WCLIP_PATCH ++ ++ Enable wclipping patch. ++*/ ++#ifndef gcdUSE_WCLIP_PATCH ++# define gcdUSE_WCLIP_PATCH 1 ++#endif ++ ++#ifndef gcdUSE_NPOT_PATCH ++# define gcdUSE_NPOT_PATCH 1 ++#endif ++ ++/* ++ gcd3DBLIT ++ ++ TODO: Should be replaced by feature bit if available. ++*/ ++#ifndef gcd3DBLIT ++# define gcd3DBLIT 0 ++#endif ++ ++/* ++ gcdINTERNAL_COMMENT ++ ++ Wrap internal comment, content wrapped by it and the macor itself ++ will be removed in release driver. ++*/ ++#ifndef gcdINTERNAL_COMMENT ++# define gcdINTERNAL_COMMENT 1 ++#endif ++ ++/* ++ gcdRTT_DISABLE_FC ++ ++ Disable RTT FC support. For test only. ++*/ ++#ifndef gcdRTT_DISABLE_FC ++# define gcdRTT_DISABLE_FC 0 ++#endif ++ ++/* ++ gcdFORCE_MIPMAP ++ ++ Force generate mipmap for texture. ++*/ ++#ifndef gcdFORCE_MIPMAP ++# define gcdFORCE_MIPMAP 0 ++#endif ++ ++/* ++ gcdFORCE_BILINEAR ++ ++ Force bilinear for mipfilter. ++*/ ++#ifndef gcdFORCE_BILINEAR ++# define gcdFORCE_BILINEAR 1 ++#endif ++ ++/* ++ gcdBINARY_TRACE ++ ++ When non-zero, binary trace will be generated. ++ ++ When gcdBINARY_TRACE_FILE_SIZE is non-zero, binary trace buffer will ++ be written to a file which size is limited to ++ gcdBINARY_TRACE_FILE_SIZE. ++*/ ++#ifndef gcdBINARY_TRACE ++# define gcdBINARY_TRACE 0 ++# define gcdBINARY_TRACE_FILE_SIZE 0 ++#endif ++ ++#ifndef gcdMOVG ++# define gcdMOVG 0 ++#if gcdMOVG ++# define GC355_PROFILER 1 ++# endif ++# define gcdENABLE_TS_DOUBLE_BUFFER 1 ++#else ++#if gcdMOVG ++# define GC355_PROFILER 1 ++# define gcdENABLE_TS_DOUBLE_BUFFER 0 ++#else ++# define gcdENABLE_TS_DOUBLE_BUFFER 1 ++#endif ++#endif ++ ++/* gcdINTERRUPT_STATISTIC ++ * ++ * Monitor the event send to GPU and interrupt issued by GPU. ++ */ ++ ++#ifndef gcdINTERRUPT_STATISTIC ++#if defined(LINUX) ++# define gcdINTERRUPT_STATISTIC 1 ++#else ++# define gcdINTERRUPT_STATISTIC 0 ++#endif ++#endif ++ ++/* ++ gcdYINVERTED_RENDERING ++ When it's not zero, we will rendering display buffer ++ with top-bottom direction. All other offscreen rendering ++ will be bottom-top, which follow OpenGL ES spec. ++*/ ++#ifndef gcdYINVERTED_RENDERING ++# define gcdYINVERTED_RENDERING 1 ++#endif ++ ++#if gcdYINVERTED_RENDERING ++/* disable unaligned linear composition adjust in Y-inverted rendering mode. */ ++# undef gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST ++# define gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST 0 ++#endif ++ ++/* ++ gcdFENCE_WAIT_LOOP_COUNT ++ Wait fence, loop count. ++*/ ++#ifndef gcdFENCE_WAIT_LOOP_COUNT ++# define gcdFENCE_WAIT_LOOP_COUNT 100 ++#endif ++ ++/* ++ gcdHAL_3D_DRAWBLIT ++ When it's not zero, we will enable HAL 3D drawblit ++ to replace client 3dblit. ++*/ ++#ifndef gcdHAL_3D_DRAWBLIT ++# define gcdHAL_3D_DRAWBLIT 1 ++#endif ++ ++/* ++ gcdPARTIAL_FAST_CLEAR ++ When it's not zero, partial fast clear is enabled. ++ Depends on gcdHAL_3D_DRAWBLIT, if gcdHAL_3D_DRAWBLIT is not enabled, ++ only available when scissor box is completely aligned. ++ Expremental, under test. ++*/ ++#ifndef gcdPARTIAL_FAST_CLEAR ++# define gcdPARTIAL_FAST_CLEAR 1 ++#endif ++ ++/* ++ gcdREMOVE_SURF_ORIENTATION ++ When it's not zero, we will remove surface orientation function. ++ It wil become to a parameter of resolve function. ++*/ ++#ifndef gcdREMOVE_SURF_ORIENTATION ++# define gcdREMOVE_SURF_ORIENTATION 0 ++#endif ++ ++/* ++ gcdPATTERN_FAST_PATH ++ For pattern match ++*/ ++#ifndef gcdPATTERN_FAST_PATH ++# define gcdPATTERN_FAST_PATH 1 ++#endif ++ ++/* ++ gcdUSE_INPUT_DEVICE ++ disable input devices usage under fb mode to support fb+vdk multi-process ++*/ ++#ifndef gcdUSE_INPUT_DEVICE ++# define gcdUSE_INPUT_DEVICE 1 ++#endif ++ ++ ++/* ++ gcdFRAMEINFO_STATISTIC ++ When enable, collect frame information. ++*/ ++#ifndef gcdFRAMEINFO_STATISTIC ++ ++#if (defined(DBG) && DBG) || defined(DEBUG) || defined(_DEBUG) || gcdDUMP ++# define gcdFRAMEINFO_STATISTIC 1 ++#else ++# define gcdFRAMEINFO_STATISTIC 0 ++#endif ++ ++#endif ++ ++/* ++ gcdPACKED_OUTPUT_ADDRESS ++ When it's not zero, ps output is already packed after linked ++*/ ++#ifndef gcdPACKED_OUTPUT_ADDRESS ++# define gcdPACKED_OUTPUT_ADDRESS 1 ++#endif ++ ++/* ++ gcdENABLE_THIRD_PARTY_OPERATION ++ Enable third party operation like tpc or not. ++*/ ++#ifndef gcdENABLE_THIRD_PARTY_OPERATION ++# define gcdENABLE_THIRD_PARTY_OPERATION 1 ++#endif ++ ++ ++/* ++ Core configurations. By default enable all cores. ++*/ ++#ifndef gcdENABLE_3D ++# define gcdENABLE_3D 1 ++#endif ++ ++#ifndef gcdENABLE_2D ++# define gcdENABLE_2D 1 ++#endif ++ ++#ifndef gcdENABLE_VG ++# define gcdENABLE_VG 0 ++#endif ++ ++#ifndef gcdGC355_MEM_PRINT ++# define gcdGC355_MEM_PRINT 0 ++#else ++#if (!((gcdENABLE_3D == 0) && (gcdENABLE_2D == 0) && (gcdENABLE_VG == 1))) ++# undef gcdGC355_MEM_PRINT ++# define gcdGC355_MEM_PRINT 0 ++# endif ++#endif ++ ++#ifndef gcdENABLE_UNIFIED_CONSTANT ++# define gcdENABLE_UNIFIED_CONSTANT 1 ++#endif ++ ++/* ++ gcdRECORD_COMMAND ++*/ ++#ifndef gcdRECORD_COMMAND ++# define gcdRECORD_COMMAND 0 ++#endif ++ ++#endif /* __gc_hal_options_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_profiler.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_profiler.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_profiler.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_profiler.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,585 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_profiler_h_ ++#define __gc_hal_profiler_h_ ++ ++#if VIVANTE_PROFILER_NEW ++#include "gc_hal_engine.h" ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define GLVERTEX_OBJECT 10 ++#define GLVERTEX_OBJECT_BYTES 11 ++ ++#define GLINDEX_OBJECT 20 ++#define GLINDEX_OBJECT_BYTES 21 ++ ++#define GLTEXTURE_OBJECT 30 ++#define GLTEXTURE_OBJECT_BYTES 31 ++ ++#define GLBUFOBJ_OBJECT 40 ++#define GLBUFOBJ_OBJECT_BYTES 41 ++ ++#if VIVANTE_PROFILER ++#define gcmPROFILE_GC(Enum, Value) gcoPROFILER_Count(gcvNULL, Enum, Value) ++#else ++#define gcmPROFILE_GC(Enum, Value) do { } while (gcvFALSE) ++#endif ++ ++#ifndef gcdNEW_PROFILER_FILE ++#define gcdNEW_PROFILER_FILE 1 ++#endif ++ ++#define ES11_CALLS 151 ++#define ES11_DRAWCALLS (ES11_CALLS + 1) ++#define ES11_STATECHANGECALLS (ES11_DRAWCALLS + 1) ++#define ES11_POINTCOUNT (ES11_STATECHANGECALLS + 1) ++#define ES11_LINECOUNT (ES11_POINTCOUNT + 1) ++#define ES11_TRIANGLECOUNT (ES11_LINECOUNT + 1) ++ ++#define ES30_CALLS 159 ++#define ES30_DRAWCALLS (ES30_CALLS + 1) ++#define ES30_STATECHANGECALLS (ES30_DRAWCALLS + 1) ++#define ES30_POINTCOUNT (ES30_STATECHANGECALLS + 1) ++#define ES30_LINECOUNT (ES30_POINTCOUNT + 1) ++#define ES30_TRIANGLECOUNT (ES30_LINECOUNT + 1) ++ ++#define VG11_CALLS 88 ++#define VG11_DRAWCALLS (VG11_CALLS + 1) ++#define VG11_STATECHANGECALLS (VG11_DRAWCALLS + 1) ++#define VG11_FILLCOUNT (VG11_STATECHANGECALLS + 1) ++#define VG11_STROKECOUNT (VG11_FILLCOUNT + 1) ++/* End of Driver API ID Definitions. */ ++ ++/* HAL & MISC IDs. */ ++#define HAL_VERTBUFNEWBYTEALLOC 1 ++#define HAL_VERTBUFTOTALBYTEALLOC (HAL_VERTBUFNEWBYTEALLOC + 1) ++#define HAL_VERTBUFNEWOBJALLOC (HAL_VERTBUFTOTALBYTEALLOC + 1) ++#define HAL_VERTBUFTOTALOBJALLOC (HAL_VERTBUFNEWOBJALLOC + 1) ++#define HAL_INDBUFNEWBYTEALLOC (HAL_VERTBUFTOTALOBJALLOC + 1) ++#define HAL_INDBUFTOTALBYTEALLOC (HAL_INDBUFNEWBYTEALLOC + 1) ++#define HAL_INDBUFNEWOBJALLOC (HAL_INDBUFTOTALBYTEALLOC + 1) ++#define HAL_INDBUFTOTALOBJALLOC (HAL_INDBUFNEWOBJALLOC + 1) ++#define HAL_TEXBUFNEWBYTEALLOC (HAL_INDBUFTOTALOBJALLOC + 1) ++#define HAL_TEXBUFTOTALBYTEALLOC (HAL_TEXBUFNEWBYTEALLOC + 1) ++#define HAL_TEXBUFNEWOBJALLOC (HAL_TEXBUFTOTALBYTEALLOC + 1) ++#define HAL_TEXBUFTOTALOBJALLOC (HAL_TEXBUFNEWOBJALLOC + 1) ++ ++#define GPU_CYCLES 1 ++#define GPU_READ64BYTE (GPU_CYCLES + 1) ++#define GPU_WRITE64BYTE (GPU_READ64BYTE + 1) ++#define GPU_TOTALCYCLES (GPU_WRITE64BYTE + 1) ++#define GPU_IDLECYCLES (GPU_TOTALCYCLES + 1) ++ ++#define VS_INSTCOUNT 1 ++#define VS_BRANCHINSTCOUNT (VS_INSTCOUNT + 1) ++#define VS_TEXLDINSTCOUNT (VS_BRANCHINSTCOUNT + 1) ++#define VS_RENDEREDVERTCOUNT (VS_TEXLDINSTCOUNT + 1) ++#define VS_SOURCE (VS_RENDEREDVERTCOUNT + 1) ++ ++#define PS_INSTCOUNT 1 ++#define PS_BRANCHINSTCOUNT (PS_INSTCOUNT + 1) ++#define PS_TEXLDINSTCOUNT (PS_BRANCHINSTCOUNT + 1) ++#define PS_RENDEREDPIXCOUNT (PS_TEXLDINSTCOUNT + 1) ++#define PS_SOURCE (PS_RENDEREDPIXCOUNT + 1) ++ ++#define PA_INVERTCOUNT 1 ++#define PA_INPRIMCOUNT (PA_INVERTCOUNT + 1) ++#define PA_OUTPRIMCOUNT (PA_INPRIMCOUNT + 1) ++#define PA_DEPTHCLIPCOUNT (PA_OUTPRIMCOUNT + 1) ++#define PA_TRIVIALREJCOUNT (PA_DEPTHCLIPCOUNT + 1) ++#define PA_CULLCOUNT (PA_TRIVIALREJCOUNT + 1) ++ ++#define SE_TRIANGLECOUNT 1 ++#define SE_LINECOUNT (SE_TRIANGLECOUNT + 1) ++ ++#define RA_VALIDPIXCOUNT 1 ++#define RA_TOTALQUADCOUNT (RA_VALIDPIXCOUNT + 1) ++#define RA_VALIDQUADCOUNTEZ (RA_TOTALQUADCOUNT + 1) ++#define RA_TOTALPRIMCOUNT (RA_VALIDQUADCOUNTEZ + 1) ++#define RA_PIPECACHEMISSCOUNT (RA_TOTALPRIMCOUNT + 1) ++#define RA_PREFCACHEMISSCOUNT (RA_PIPECACHEMISSCOUNT + 1) ++#define RA_EEZCULLCOUNT (RA_PREFCACHEMISSCOUNT + 1) ++ ++#define TX_TOTBILINEARREQ 1 ++#define TX_TOTTRILINEARREQ (TX_TOTBILINEARREQ + 1) ++#define TX_TOTDISCARDTEXREQ (TX_TOTTRILINEARREQ + 1) ++#define TX_TOTTEXREQ (TX_TOTDISCARDTEXREQ + 1) ++#define TX_MEMREADCOUNT (TX_TOTTEXREQ + 1) ++#define TX_MEMREADIN8BCOUNT (TX_MEMREADCOUNT + 1) ++#define TX_CACHEMISSCOUNT (TX_MEMREADIN8BCOUNT + 1) ++#define TX_CACHEHITTEXELCOUNT (TX_CACHEMISSCOUNT + 1) ++#define TX_CACHEMISSTEXELCOUNT (TX_CACHEHITTEXELCOUNT + 1) ++ ++#define PE_KILLEDBYCOLOR 1 ++#define PE_KILLEDBYDEPTH (PE_KILLEDBYCOLOR + 1) ++#define PE_DRAWNBYCOLOR (PE_KILLEDBYDEPTH + 1) ++#define PE_DRAWNBYDEPTH (PE_DRAWNBYCOLOR + 1) ++ ++#define MC_READREQ8BPIPE 1 ++#define MC_READREQ8BIP (MC_READREQ8BPIPE + 1) ++#define MC_WRITEREQ8BPIPE (MC_READREQ8BIP + 1) ++ ++#define AXI_READREQSTALLED 1 ++#define AXI_WRITEREQSTALLED (AXI_READREQSTALLED + 1) ++#define AXI_WRITEDATASTALLED (AXI_WRITEREQSTALLED + 1) ++ ++#define PVS_INSTRCOUNT 1 ++#define PVS_ALUINSTRCOUNT (PVS_INSTRCOUNT + 1) ++#define PVS_TEXINSTRCOUNT (PVS_ALUINSTRCOUNT + 1) ++#define PVS_ATTRIBCOUNT (PVS_TEXINSTRCOUNT + 1) ++#define PVS_UNIFORMCOUNT (PVS_ATTRIBCOUNT + 1) ++#define PVS_FUNCTIONCOUNT (PVS_UNIFORMCOUNT + 1) ++#define PVS_SOURCE (PVS_FUNCTIONCOUNT + 1) ++ ++#define PPS_INSTRCOUNT 1 ++#define PPS_ALUINSTRCOUNT (PPS_INSTRCOUNT + 1) ++#define PPS_TEXINSTRCOUNT (PPS_ALUINSTRCOUNT + 1) ++#define PPS_ATTRIBCOUNT (PPS_TEXINSTRCOUNT + 1) ++#define PPS_UNIFORMCOUNT (PPS_ATTRIBCOUNT + 1) ++#define PPS_FUNCTIONCOUNT (PPS_UNIFORMCOUNT + 1) ++#define PPS_SOURCE (PPS_FUNCTIONCOUNT + 1) ++/* End of MISC Counter IDs. */ ++ ++#ifdef gcdNEW_PROFILER_FILE ++ ++/* Category Constants. */ ++#define VPHEADER 0x010000 ++#define VPG_INFO 0x020000 ++#define VPG_TIME 0x030000 ++#define VPG_MEM 0x040000 ++#define VPG_ES11 0x050000 ++#define VPG_ES30 0x060000 ++#define VPG_VG11 0x070000 ++#define VPG_HAL 0x080000 ++#define VPG_HW 0x090000 ++#define VPG_GPU 0x0a0000 ++#define VPG_VS 0x0b0000 ++#define VPG_PS 0x0c0000 ++#define VPG_PA 0x0d0000 ++#define VPG_SETUP 0x0e0000 ++#define VPG_RA 0x0f0000 ++#define VPG_TX 0x100000 ++#define VPG_PE 0x110000 ++#define VPG_MC 0x120000 ++#define VPG_AXI 0x130000 ++#define VPG_PROG 0x140000 ++#define VPG_PVS 0x150000 ++#define VPG_PPS 0x160000 ++#define VPG_ES11_TIME 0x170000 ++#define VPG_ES30_TIME 0x180000 ++#define VPG_FRAME 0x190000 ++#define VPG_ES11_DRAW 0x200000 ++#define VPG_ES30_DRAW 0x210000 ++#define VPG_VG11_TIME 0x220000 ++#define VPG_END 0xff0000 ++ ++/* Info. */ ++#define VPC_INFOCOMPANY (VPG_INFO + 1) ++#define VPC_INFOVERSION (VPC_INFOCOMPANY + 1) ++#define VPC_INFORENDERER (VPC_INFOVERSION + 1) ++#define VPC_INFOREVISION (VPC_INFORENDERER + 1) ++#define VPC_INFODRIVER (VPC_INFOREVISION + 1) ++#define VPC_INFODRIVERMODE (VPC_INFODRIVER + 1) ++#define VPC_INFOSCREENSIZE (VPC_INFODRIVERMODE + 1) ++ ++/* Counter Constants. */ ++#define VPC_ELAPSETIME (VPG_TIME + 1) ++#define VPC_CPUTIME (VPC_ELAPSETIME + 1) ++ ++#define VPC_MEMMAXRES (VPG_MEM + 1) ++#define VPC_MEMSHARED (VPC_MEMMAXRES + 1) ++#define VPC_MEMUNSHAREDDATA (VPC_MEMSHARED + 1) ++#define VPC_MEMUNSHAREDSTACK (VPC_MEMUNSHAREDDATA + 1) ++ ++/* OpenGL ES11 Statics Counter IDs. */ ++#define VPC_ES11CALLS (VPG_ES11 + ES11_CALLS) ++#define VPC_ES11DRAWCALLS (VPG_ES11 + ES11_DRAWCALLS) ++#define VPC_ES11STATECHANGECALLS (VPG_ES11 + ES11_STATECHANGECALLS) ++#define VPC_ES11POINTCOUNT (VPG_ES11 + ES11_POINTCOUNT) ++#define VPC_ES11LINECOUNT (VPG_ES11 + ES11_LINECOUNT) ++#define VPC_ES11TRIANGLECOUNT (VPG_ES11 + ES11_TRIANGLECOUNT) ++ ++/* OpenGL ES30 Statistics Counter IDs. */ ++#define VPC_ES30CALLS (VPG_ES30 + ES30_CALLS) ++#define VPC_ES30DRAWCALLS (VPG_ES30 + ES30_DRAWCALLS) ++#define VPC_ES30STATECHANGECALLS (VPG_ES30 + ES30_STATECHANGECALLS) ++#define VPC_ES30POINTCOUNT (VPG_ES30 + ES30_POINTCOUNT) ++#define VPC_ES30LINECOUNT (VPG_ES30 + ES30_LINECOUNT) ++#define VPC_ES30TRIANGLECOUNT (VPG_ES30 + ES30_TRIANGLECOUNT) ++ ++/* OpenVG Statistics Counter IDs. */ ++#define VPC_VG11CALLS (VPG_VG11 + VG11_CALLS) ++#define VPC_VG11DRAWCALLS (VPG_VG11 + VG11_DRAWCALLS) ++#define VPC_VG11STATECHANGECALLS (VPG_VG11 + VG11_STATECHANGECALLS) ++#define VPC_VG11FILLCOUNT (VPG_VG11 + VG11_FILLCOUNT) ++#define VPC_VG11STROKECOUNT (VPG_VG11 + VG11_STROKECOUNT) ++ ++/* HAL Counters. */ ++#define VPC_HALVERTBUFNEWBYTEALLOC (VPG_HAL + HAL_VERTBUFNEWBYTEALLOC) ++#define VPC_HALVERTBUFTOTALBYTEALLOC (VPG_HAL + HAL_VERTBUFTOTALBYTEALLOC) ++#define VPC_HALVERTBUFNEWOBJALLOC (VPG_HAL + HAL_VERTBUFNEWOBJALLOC) ++#define VPC_HALVERTBUFTOTALOBJALLOC (VPG_HAL + HAL_VERTBUFTOTALOBJALLOC) ++#define VPC_HALINDBUFNEWBYTEALLOC (VPG_HAL + HAL_INDBUFNEWBYTEALLOC) ++#define VPC_HALINDBUFTOTALBYTEALLOC (VPG_HAL + HAL_INDBUFTOTALBYTEALLOC) ++#define VPC_HALINDBUFNEWOBJALLOC (VPG_HAL + HAL_INDBUFNEWOBJALLOC) ++#define VPC_HALINDBUFTOTALOBJALLOC (VPG_HAL + HAL_INDBUFTOTALOBJALLOC) ++#define VPC_HALTEXBUFNEWBYTEALLOC (VPG_HAL + HAL_TEXBUFNEWBYTEALLOC) ++#define VPC_HALTEXBUFTOTALBYTEALLOC (VPG_HAL + HAL_TEXBUFTOTALBYTEALLOC) ++#define VPC_HALTEXBUFNEWOBJALLOC (VPG_HAL + HAL_TEXBUFNEWOBJALLOC) ++#define VPC_HALTEXBUFTOTALOBJALLOC (VPG_HAL + HAL_TEXBUFTOTALOBJALLOC) ++ ++/* HW: GPU Counters. */ ++#define VPC_GPUCYCLES (VPG_GPU + GPU_CYCLES) ++#define VPC_GPUREAD64BYTE (VPG_GPU + GPU_READ64BYTE) ++#define VPC_GPUWRITE64BYTE (VPG_GPU + GPU_WRITE64BYTE) ++#define VPC_GPUTOTALCYCLES (VPG_GPU + GPU_TOTALCYCLES) ++#define VPC_GPUIDLECYCLES (VPG_GPU + GPU_IDLECYCLES) ++ ++/* HW: Shader Counters. */ ++#define VPC_VSINSTCOUNT (VPG_VS + VS_INSTCOUNT) ++#define VPC_VSBRANCHINSTCOUNT (VPG_VS + VS_BRANCHINSTCOUNT) ++#define VPC_VSTEXLDINSTCOUNT (VPG_VS + VS_TEXLDINSTCOUNT) ++#define VPC_VSRENDEREDVERTCOUNT (VPG_VS + VS_RENDEREDVERTCOUNT) ++/* HW: PS Count. */ ++#define VPC_PSINSTCOUNT (VPG_PS + PS_INSTCOUNT) ++#define VPC_PSBRANCHINSTCOUNT (VPG_PS + PS_BRANCHINSTCOUNT) ++#define VPC_PSTEXLDINSTCOUNT (VPG_PS + PS_TEXLDINSTCOUNT) ++#define VPC_PSRENDEREDPIXCOUNT (VPG_PS + PS_RENDEREDPIXCOUNT) ++ ++ ++/* HW: PA Counters. */ ++#define VPC_PAINVERTCOUNT (VPG_PA + PA_INVERTCOUNT) ++#define VPC_PAINPRIMCOUNT (VPG_PA + PA_INPRIMCOUNT) ++#define VPC_PAOUTPRIMCOUNT (VPG_PA + PA_OUTPRIMCOUNT) ++#define VPC_PADEPTHCLIPCOUNT (VPG_PA + PA_DEPTHCLIPCOUNT) ++#define VPC_PATRIVIALREJCOUNT (VPG_PA + PA_TRIVIALREJCOUNT) ++#define VPC_PACULLCOUNT (VPG_PA + PA_CULLCOUNT) ++ ++/* HW: Setup Counters. */ ++#define VPC_SETRIANGLECOUNT (VPG_SETUP + SE_TRIANGLECOUNT) ++#define VPC_SELINECOUNT (VPG_SETUP + SE_LINECOUNT) ++ ++/* HW: RA Counters. */ ++#define VPC_RAVALIDPIXCOUNT (VPG_RA + RA_VALIDPIXCOUNT) ++#define VPC_RATOTALQUADCOUNT (VPG_RA + RA_TOTALQUADCOUNT) ++#define VPC_RAVALIDQUADCOUNTEZ (VPG_RA + RA_VALIDQUADCOUNTEZ) ++#define VPC_RATOTALPRIMCOUNT (VPG_RA + RA_TOTALPRIMCOUNT) ++#define VPC_RAPIPECACHEMISSCOUNT (VPG_RA + RA_PIPECACHEMISSCOUNT) ++#define VPC_RAPREFCACHEMISSCOUNT (VPG_RA + RA_PREFCACHEMISSCOUNT) ++#define VPC_RAEEZCULLCOUNT (VPG_RA + RA_EEZCULLCOUNT) ++ ++/* HW: TEX Counters. */ ++#define VPC_TXTOTBILINEARREQ (VPG_TX + TX_TOTBILINEARREQ) ++#define VPC_TXTOTTRILINEARREQ (VPG_TX + TX_TOTTRILINEARREQ) ++#define VPC_TXTOTDISCARDTEXREQ (VPG_TX + TX_TOTDISCARDTEXREQ) ++#define VPC_TXTOTTEXREQ (VPG_TX + TX_TOTTEXREQ) ++#define VPC_TXMEMREADCOUNT (VPG_TX + TX_MEMREADCOUNT) ++#define VPC_TXMEMREADIN8BCOUNT (VPG_TX + TX_MEMREADIN8BCOUNT) ++#define VPC_TXCACHEMISSCOUNT (VPG_TX + TX_CACHEMISSCOUNT) ++#define VPC_TXCACHEHITTEXELCOUNT (VPG_TX + TX_CACHEHITTEXELCOUNT) ++#define VPC_TXCACHEMISSTEXELCOUNT (VPG_TX + TX_CACHEMISSTEXELCOUNT) ++ ++/* HW: PE Counters. */ ++#define VPC_PEKILLEDBYCOLOR (VPG_PE + PE_KILLEDBYCOLOR) ++#define VPC_PEKILLEDBYDEPTH (VPG_PE + PE_KILLEDBYDEPTH) ++#define VPC_PEDRAWNBYCOLOR (VPG_PE + PE_DRAWNBYCOLOR) ++#define VPC_PEDRAWNBYDEPTH (VPG_PE + PE_DRAWNBYDEPTH) ++ ++/* HW: MC Counters. */ ++#define VPC_MCREADREQ8BPIPE (VPG_MC + MC_READREQ8BPIPE) ++#define VPC_MCREADREQ8BIP (VPG_MC + MC_READREQ8BIP) ++#define VPC_MCWRITEREQ8BPIPE (VPG_MC + MC_WRITEREQ8BPIPE) ++ ++/* HW: AXI Counters. */ ++#define VPC_AXIREADREQSTALLED (VPG_AXI + AXI_READREQSTALLED) ++#define VPC_AXIWRITEREQSTALLED (VPG_AXI + AXI_WRITEREQSTALLED) ++#define VPC_AXIWRITEDATASTALLED (VPG_AXI + AXI_WRITEDATASTALLED) ++ ++/* PROGRAM: Shader program counters. */ ++#define VPC_PVSINSTRCOUNT (VPG_PVS + PVS_INSTRCOUNT) ++#define VPC_PVSALUINSTRCOUNT (VPG_PVS + PVS_ALUINSTRCOUNT) ++#define VPC_PVSTEXINSTRCOUNT (VPG_PVS + PVS_TEXINSTRCOUNT) ++#define VPC_PVSATTRIBCOUNT (VPG_PVS + PVS_ATTRIBCOUNT) ++#define VPC_PVSUNIFORMCOUNT (VPG_PVS + PVS_UNIFORMCOUNT) ++#define VPC_PVSFUNCTIONCOUNT (VPG_PVS + PVS_FUNCTIONCOUNT) ++#define VPC_PVSSOURCE (VPG_PVS + PVS_SOURCE) ++ ++#define VPC_PPSINSTRCOUNT (VPG_PPS + PPS_INSTRCOUNT) ++#define VPC_PPSALUINSTRCOUNT (VPG_PPS + PPS_ALUINSTRCOUNT) ++#define VPC_PPSTEXINSTRCOUNT (VPG_PPS + PPS_TEXINSTRCOUNT) ++#define VPC_PPSATTRIBCOUNT (VPG_PPS + PPS_ATTRIBCOUNT) ++#define VPC_PPSUNIFORMCOUNT (VPG_PPS + PPS_UNIFORMCOUNT) ++#define VPC_PPSFUNCTIONCOUNT (VPG_PPS + PPS_FUNCTIONCOUNT) ++#define VPC_PPSSOURCE (VPG_PPS + PPS_SOURCE) ++ ++#define VPC_PROGRAMHANDLE (VPG_PROG + 1) ++ ++#define VPC_ES30_DRAW_NO (VPG_ES30_DRAW + 1) ++#define VPC_ES11_DRAW_NO (VPG_ES11_DRAW + 1) ++#endif ++ ++ ++/* HW profile information. */ ++typedef struct _gcsPROFILER_COUNTERS ++{ ++ /* HW static counters. */ ++ gctUINT32 gpuClock; ++ gctUINT32 axiClock; ++ gctUINT32 shaderClock; ++ ++ /* HW vairable counters. */ ++ gctUINT32 gpuClockStart; ++ gctUINT32 gpuClockEnd; ++ ++ /* HW vairable counters. */ ++ gctUINT32 gpuCyclesCounter; ++ gctUINT32 gpuTotalCyclesCounter; ++ gctUINT32 gpuIdleCyclesCounter; ++ gctUINT32 gpuTotalRead64BytesPerFrame; ++ gctUINT32 gpuTotalWrite64BytesPerFrame; ++ ++ /* PE */ ++ gctUINT32 pe_pixel_count_killed_by_color_pipe; ++ gctUINT32 pe_pixel_count_killed_by_depth_pipe; ++ gctUINT32 pe_pixel_count_drawn_by_color_pipe; ++ gctUINT32 pe_pixel_count_drawn_by_depth_pipe; ++ ++ /* SH */ ++ gctUINT32 ps_inst_counter; ++ gctUINT32 rendered_pixel_counter; ++ gctUINT32 vs_inst_counter; ++ gctUINT32 rendered_vertice_counter; ++ gctUINT32 vtx_branch_inst_counter; ++ gctUINT32 vtx_texld_inst_counter; ++ gctUINT32 pxl_branch_inst_counter; ++ gctUINT32 pxl_texld_inst_counter; ++ ++ /* PA */ ++ gctUINT32 pa_input_vtx_counter; ++ gctUINT32 pa_input_prim_counter; ++ gctUINT32 pa_output_prim_counter; ++ gctUINT32 pa_depth_clipped_counter; ++ gctUINT32 pa_trivial_rejected_counter; ++ gctUINT32 pa_culled_counter; ++ ++ /* SE */ ++ gctUINT32 se_culled_triangle_count; ++ gctUINT32 se_culled_lines_count; ++ ++ /* RA */ ++ gctUINT32 ra_valid_pixel_count; ++ gctUINT32 ra_total_quad_count; ++ gctUINT32 ra_valid_quad_count_after_early_z; ++ gctUINT32 ra_total_primitive_count; ++ gctUINT32 ra_pipe_cache_miss_counter; ++ gctUINT32 ra_prefetch_cache_miss_counter; ++ gctUINT32 ra_eez_culled_counter; ++ ++ /* TX */ ++ gctUINT32 tx_total_bilinear_requests; ++ gctUINT32 tx_total_trilinear_requests; ++ gctUINT32 tx_total_discarded_texture_requests; ++ gctUINT32 tx_total_texture_requests; ++ gctUINT32 tx_mem_read_count; ++ gctUINT32 tx_mem_read_in_8B_count; ++ gctUINT32 tx_cache_miss_count; ++ gctUINT32 tx_cache_hit_texel_count; ++ gctUINT32 tx_cache_miss_texel_count; ++ ++ /* MC */ ++ gctUINT32 mc_total_read_req_8B_from_pipeline; ++ gctUINT32 mc_total_read_req_8B_from_IP; ++ gctUINT32 mc_total_write_req_8B_from_pipeline; ++ ++ /* HI */ ++ gctUINT32 hi_axi_cycles_read_request_stalled; ++ gctUINT32 hi_axi_cycles_write_request_stalled; ++ gctUINT32 hi_axi_cycles_write_data_stalled; ++} ++gcsPROFILER_COUNTERS; ++ ++#if VIVANTE_PROFILER_NEW ++#define NumOfDrawBuf 64 ++#endif ++ ++/* HAL profile information. */ ++typedef struct _gcsPROFILER ++{ ++ gctUINT32 enable; ++ gctBOOL enableHal; ++ gctBOOL enableHW; ++ gctBOOL enableSH; ++ gctBOOL isSyncMode; ++ gctBOOL disableOutputCounter; ++ ++ gctBOOL useSocket; ++ gctINT sockFd; ++ ++ gctFILE file; ++ ++ /* Aggregate Information */ ++ ++ /* Clock Info */ ++ gctUINT64 frameStart; ++ gctUINT64 frameEnd; ++ ++ /* Current frame information */ ++ gctUINT32 frameNumber; ++ gctUINT64 frameStartTimeusec; ++ gctUINT64 frameEndTimeusec; ++ gctUINT64 frameStartCPUTimeusec; ++ gctUINT64 frameEndCPUTimeusec; ++ ++#if PROFILE_HAL_COUNTERS ++ gctUINT32 vertexBufferTotalBytesAlloc; ++ gctUINT32 vertexBufferNewBytesAlloc; ++ int vertexBufferTotalObjectsAlloc; ++ int vertexBufferNewObjectsAlloc; ++ ++ gctUINT32 indexBufferTotalBytesAlloc; ++ gctUINT32 indexBufferNewBytesAlloc; ++ int indexBufferTotalObjectsAlloc; ++ int indexBufferNewObjectsAlloc; ++ ++ gctUINT32 textureBufferTotalBytesAlloc; ++ gctUINT32 textureBufferNewBytesAlloc; ++ int textureBufferTotalObjectsAlloc; ++ int textureBufferNewObjectsAlloc; ++ ++ gctUINT32 numCommits; ++ gctUINT32 drawPointCount; ++ gctUINT32 drawLineCount; ++ gctUINT32 drawTriangleCount; ++ gctUINT32 drawVertexCount; ++ gctUINT32 redundantStateChangeCalls; ++#endif ++ ++ gctUINT32 prevVSInstCount; ++ gctUINT32 prevVSBranchInstCount; ++ gctUINT32 prevVSTexInstCount; ++ gctUINT32 prevVSVertexCount; ++ gctUINT32 prevPSInstCount; ++ gctUINT32 prevPSBranchInstCount; ++ gctUINT32 prevPSTexInstCount; ++ gctUINT32 prevPSPixelCount; ++ ++#if VIVANTE_PROFILER_NEW ++ gcoBUFOBJ newCounterBuf[NumOfDrawBuf]; ++ gctUINT32 curBufId; ++#endif ++ ++} ++gcsPROFILER; ++ ++/* Memory profile information. */ ++struct _gcsMemProfile ++{ ++ /* Memory Usage */ ++ gctUINT32 videoMemUsed; ++ gctUINT32 systemMemUsed; ++ gctUINT32 commitBufferSize; ++ gctUINT32 contextBufferCopyBytes; ++}; ++ ++/* Shader profile information. */ ++struct _gcsSHADER_PROFILER ++{ ++ gctUINT32 shaderLength; ++ gctUINT32 shaderALUCycles; ++ gctUINT32 shaderTexLoadCycles; ++ gctUINT32 shaderTempRegCount; ++ gctUINT32 shaderSamplerRegCount; ++ gctUINT32 shaderInputRegCount; ++ gctUINT32 shaderOutputRegCount; ++}; ++ ++/* Initialize the gcsProfiler. */ ++gceSTATUS ++gcoPROFILER_Initialize( ++ IN gcoHAL Hal, ++ IN gctBOOL Enable ++ ); ++ ++/* Destroy the gcProfiler. */ ++gceSTATUS ++gcoPROFILER_Destroy( ++ IN gcoHAL Hal ++ ); ++ ++/* Write data to profiler. */ ++gceSTATUS ++gcoPROFILER_Write( ++ IN gcoHAL Hal, ++ IN gctSIZE_T ByteCount, ++ IN gctCONST_POINTER Data ++ ); ++ ++/* Flush data out. */ ++gceSTATUS ++gcoPROFILER_Flush( ++ IN gcoHAL Hal ++ ); ++ ++/* Call to signal end of frame. */ ++gceSTATUS ++gcoPROFILER_EndFrame( ++ IN gcoHAL Hal ++ ); ++ ++/* Call to signal end of draw. */ ++gceSTATUS ++gcoPROFILER_EndDraw( ++ IN gcoHAL Hal, ++ IN gctBOOL FirstDraw ++ ); ++ ++/* Increase profile counter Enum by Value. */ ++gceSTATUS ++gcoPROFILER_Count( ++ IN gcoHAL Hal, ++ IN gctUINT32 Enum, ++ IN gctINT Value ++ ); ++ ++/* Profile input vertex shader. */ ++gceSTATUS ++gcoPROFILER_ShaderVS( ++ IN gcoHAL Hal, ++ IN gctPOINTER Vs ++ ); ++ ++/* Profile input fragment shader. */ ++gceSTATUS ++gcoPROFILER_ShaderFS( ++ IN gcoHAL Hal, ++ IN gctPOINTER Fs ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_profiler_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_raster.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_raster.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_raster.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_raster.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,1038 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_raster_h_ ++#define __gc_hal_raster_h_ ++ ++#include "gc_hal_enum.h" ++#include "gc_hal_types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++****************************** Object Declarations ***************************** ++\******************************************************************************/ ++ ++typedef struct _gcoBRUSH * gcoBRUSH; ++typedef struct _gcoBRUSH_CACHE * gcoBRUSH_CACHE; ++ ++/******************************************************************************\ ++******************************** gcoBRUSH Object ******************************* ++\******************************************************************************/ ++ ++/* Create a new solid color gcoBRUSH object. */ ++gceSTATUS ++gcoBRUSH_ConstructSingleColor( ++ IN gcoHAL Hal, ++ IN gctUINT32 ColorConvert, ++ IN gctUINT32 Color, ++ IN gctUINT64 Mask, ++ gcoBRUSH * Brush ++ ); ++ ++/* Create a new monochrome gcoBRUSH object. */ ++gceSTATUS ++gcoBRUSH_ConstructMonochrome( ++ IN gcoHAL Hal, ++ IN gctUINT32 OriginX, ++ IN gctUINT32 OriginY, ++ IN gctUINT32 ColorConvert, ++ IN gctUINT32 FgColor, ++ IN gctUINT32 BgColor, ++ IN gctUINT64 Bits, ++ IN gctUINT64 Mask, ++ gcoBRUSH * Brush ++ ); ++ ++/* Create a color gcoBRUSH object. */ ++gceSTATUS ++gcoBRUSH_ConstructColor( ++ IN gcoHAL Hal, ++ IN gctUINT32 OriginX, ++ IN gctUINT32 OriginY, ++ IN gctPOINTER Address, ++ IN gceSURF_FORMAT Format, ++ IN gctUINT64 Mask, ++ gcoBRUSH * Brush ++ ); ++ ++/* Destroy an gcoBRUSH object. */ ++gceSTATUS ++gcoBRUSH_Destroy( ++ IN gcoBRUSH Brush ++ ); ++ ++/******************************************************************************\ ++******************************** gcoSURF Object ******************************* ++\******************************************************************************/ ++ ++/* Set cipping rectangle. */ ++gceSTATUS ++gcoSURF_SetClipping( ++ IN gcoSURF Surface ++ ); ++ ++/* Clear one or more rectangular areas. */ ++gceSTATUS ++gcoSURF_Clear2D( ++ IN gcoSURF DestSurface, ++ IN gctUINT32 RectCount, ++ IN gcsRECT_PTR DestRect, ++ IN gctUINT32 LoColor, ++ IN gctUINT32 HiColor ++ ); ++ ++/* Draw one or more Bresenham lines. */ ++gceSTATUS ++gcoSURF_Line( ++ IN gcoSURF Surface, ++ IN gctUINT32 LineCount, ++ IN gcsRECT_PTR Position, ++ IN gcoBRUSH Brush, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop ++ ); ++ ++/* Generic rectangular blit. */ ++gceSTATUS ++gcoSURF_Blit( ++ IN OPTIONAL gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gctUINT32 RectCount, ++ IN OPTIONAL gcsRECT_PTR SrcRect, ++ IN gcsRECT_PTR DestRect, ++ IN OPTIONAL gcoBRUSH Brush, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN OPTIONAL gceSURF_TRANSPARENCY Transparency, ++ IN OPTIONAL gctUINT32 TransparencyColor, ++ IN OPTIONAL gctPOINTER Mask, ++ IN OPTIONAL gceSURF_MONOPACK MaskPack ++ ); ++ ++/* Monochrome blit. */ ++gceSTATUS ++gcoSURF_MonoBlit( ++ IN gcoSURF DestSurface, ++ IN gctPOINTER Source, ++ IN gceSURF_MONOPACK SourcePack, ++ IN gcsPOINT_PTR SourceSize, ++ IN gcsPOINT_PTR SourceOrigin, ++ IN gcsRECT_PTR DestRect, ++ IN OPTIONAL gcoBRUSH Brush, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gctBOOL ColorConvert, ++ IN gctUINT8 MonoTransparency, ++ IN gceSURF_TRANSPARENCY Transparency, ++ IN gctUINT32 FgColor, ++ IN gctUINT32 BgColor ++ ); ++ ++/* Filter blit. */ ++gceSTATUS ++gcoSURF_FilterBlit( ++ IN gcoSURF SrcSurface, ++ IN gcoSURF DestSurface, ++ IN gcsRECT_PTR SrcRect, ++ IN gcsRECT_PTR DestRect, ++ IN gcsRECT_PTR DestSubRect ++ ); ++ ++/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ ++gceSTATUS ++gcoSURF_EnableAlphaBlend( ++ IN gcoSURF Surface, ++ IN gctUINT8 SrcGlobalAlphaValue, ++ IN gctUINT8 DstGlobalAlphaValue, ++ IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, ++ IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, ++ IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, ++ IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, ++ IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, ++ IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, ++ IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, ++ IN gceSURF_PIXEL_COLOR_MODE DstColorMode ++ ); ++ ++/* Disable alpha blending engine in the hardware and engage the ROP engine. */ ++gceSTATUS ++gcoSURF_DisableAlphaBlend( ++ IN gcoSURF Surface ++ ); ++ ++/* Copy a rectangular area with format conversion. */ ++gceSTATUS ++gcoSURF_CopyPixels( ++ IN gcoSURF Source, ++ IN gcoSURF Target, ++ IN gctINT SourceX, ++ IN gctINT SourceY, ++ IN gctINT TargetX, ++ IN gctINT TargetY, ++ IN gctINT Width, ++ IN gctINT Height ++ ); ++ ++/* Read surface pixel. */ ++gceSTATUS ++gcoSURF_ReadPixel( ++ IN gcoSURF Surface, ++ IN gctPOINTER Memory, ++ IN gctINT X, ++ IN gctINT Y, ++ IN gceSURF_FORMAT Format, ++ OUT gctPOINTER PixelValue ++ ); ++ ++/* Write surface pixel. */ ++gceSTATUS ++gcoSURF_WritePixel( ++ IN gcoSURF Surface, ++ IN gctPOINTER Memory, ++ IN gctINT X, ++ IN gctINT Y, ++ IN gceSURF_FORMAT Format, ++ IN gctPOINTER PixelValue ++ ); ++ ++gceSTATUS ++gcoSURF_SetDither( ++ IN gcoSURF Surface, ++ IN gctBOOL Dither ++ ); ++ ++gceSTATUS ++gcoSURF_Set2DSource( ++ gcoSURF Surface, ++ gceSURF_ROTATION Rotation ++ ); ++ ++gceSTATUS ++gcoSURF_Set2DTarget( ++ gcoSURF Surface, ++ gceSURF_ROTATION Rotation ++ ); ++ ++/******************************************************************************\ ++********************************** gco2D Object ********************************* ++\******************************************************************************/ ++ ++/* Construct a new gco2D object. */ ++gceSTATUS ++gco2D_Construct( ++ IN gcoHAL Hal, ++ OUT gco2D * Hardware ++ ); ++ ++/* Destroy an gco2D object. */ ++gceSTATUS ++gco2D_Destroy( ++ IN gco2D Hardware ++ ); ++ ++/* Sets the maximum number of brushes in the brush cache. */ ++gceSTATUS ++gco2D_SetBrushLimit( ++ IN gco2D Hardware, ++ IN gctUINT MaxCount ++ ); ++ ++/* Flush the brush. */ ++gceSTATUS ++gco2D_FlushBrush( ++ IN gco2D Engine, ++ IN gcoBRUSH Brush, ++ IN gceSURF_FORMAT Format ++ ); ++ ++/* Program the specified solid color brush. */ ++gceSTATUS ++gco2D_LoadSolidBrush( ++ IN gco2D Engine, ++ IN gceSURF_FORMAT Format, ++ IN gctUINT32 ColorConvert, ++ IN gctUINT32 Color, ++ IN gctUINT64 Mask ++ ); ++ ++gceSTATUS ++gco2D_LoadMonochromeBrush( ++ IN gco2D Engine, ++ IN gctUINT32 OriginX, ++ IN gctUINT32 OriginY, ++ IN gctUINT32 ColorConvert, ++ IN gctUINT32 FgColor, ++ IN gctUINT32 BgColor, ++ IN gctUINT64 Bits, ++ IN gctUINT64 Mask ++ ); ++ ++gceSTATUS ++gco2D_LoadColorBrush( ++ IN gco2D Engine, ++ IN gctUINT32 OriginX, ++ IN gctUINT32 OriginY, ++ IN gctUINT32 Address, ++ IN gceSURF_FORMAT Format, ++ IN gctUINT64 Mask ++ ); ++ ++/* Configure monochrome source. */ ++gceSTATUS ++gco2D_SetMonochromeSource( ++ IN gco2D Engine, ++ IN gctBOOL ColorConvert, ++ IN gctUINT8 MonoTransparency, ++ IN gceSURF_MONOPACK DataPack, ++ IN gctBOOL CoordRelative, ++ IN gceSURF_TRANSPARENCY Transparency, ++ IN gctUINT32 FgColor, ++ IN gctUINT32 BgColor ++ ); ++ ++/* Configure color source. */ ++gceSTATUS ++gco2D_SetColorSource( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctBOOL CoordRelative, ++ IN gceSURF_TRANSPARENCY Transparency, ++ IN gctUINT32 TransparencyColor ++ ); ++ ++/* Configure color source extension for full rotation. */ ++gceSTATUS ++gco2D_SetColorSourceEx( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctUINT32 SurfaceHeight, ++ IN gctBOOL CoordRelative, ++ IN gceSURF_TRANSPARENCY Transparency, ++ IN gctUINT32 TransparencyColor ++ ); ++ ++/* Configure color source. */ ++gceSTATUS ++gco2D_SetColorSourceAdvanced( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctUINT32 SurfaceHeight, ++ IN gctBOOL CoordRelative ++ ); ++ ++gceSTATUS ++gco2D_SetColorSourceN( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctUINT32 SurfaceHeight, ++ IN gctUINT32 SurfaceNumber ++ ); ++ ++/* Configure masked color source. */ ++gceSTATUS ++gco2D_SetMaskedSource( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_FORMAT Format, ++ IN gctBOOL CoordRelative, ++ IN gceSURF_MONOPACK MaskPack ++ ); ++ ++/* Configure masked color source extension for full rotation. */ ++gceSTATUS ++gco2D_SetMaskedSourceEx( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_FORMAT Format, ++ IN gctBOOL CoordRelative, ++ IN gceSURF_MONOPACK MaskPack, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctUINT32 SurfaceHeight ++ ); ++ ++/* Setup the source rectangle. */ ++gceSTATUS ++gco2D_SetSource( ++ IN gco2D Engine, ++ IN gcsRECT_PTR SrcRect ++ ); ++ ++/* Set clipping rectangle. */ ++gceSTATUS ++gco2D_SetClipping( ++ IN gco2D Engine, ++ IN gcsRECT_PTR Rect ++ ); ++ ++/* Configure destination. */ ++gceSTATUS ++gco2D_SetTarget( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth ++ ); ++ ++/* Configure destination extension for full rotation. */ ++gceSTATUS ++gco2D_SetTargetEx( ++ IN gco2D Engine, ++ IN gctUINT32 Address, ++ IN gctUINT32 Stride, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctUINT32 SurfaceHeight ++ ); ++ ++/* Calculate and program the stretch factors. */ ++gceSTATUS ++gco2D_CalcStretchFactor( ++ IN gco2D Engine, ++ IN gctINT32 SrcSize, ++ IN gctINT32 DestSize, ++ OUT gctUINT32_PTR Factor ++ ); ++ ++gceSTATUS ++gco2D_SetStretchFactors( ++ IN gco2D Engine, ++ IN gctUINT32 HorFactor, ++ IN gctUINT32 VerFactor ++ ); ++ ++/* Calculate and program the stretch factors based on the rectangles. */ ++gceSTATUS ++gco2D_SetStretchRectFactors( ++ IN gco2D Engine, ++ IN gcsRECT_PTR SrcRect, ++ IN gcsRECT_PTR DestRect ++ ); ++ ++/* Create a new solid color gcoBRUSH object. */ ++gceSTATUS ++gco2D_ConstructSingleColorBrush( ++ IN gco2D Engine, ++ IN gctUINT32 ColorConvert, ++ IN gctUINT32 Color, ++ IN gctUINT64 Mask, ++ gcoBRUSH * Brush ++ ); ++ ++/* Create a new monochrome gcoBRUSH object. */ ++gceSTATUS ++gco2D_ConstructMonochromeBrush( ++ IN gco2D Engine, ++ IN gctUINT32 OriginX, ++ IN gctUINT32 OriginY, ++ IN gctUINT32 ColorConvert, ++ IN gctUINT32 FgColor, ++ IN gctUINT32 BgColor, ++ IN gctUINT64 Bits, ++ IN gctUINT64 Mask, ++ gcoBRUSH * Brush ++ ); ++ ++/* Create a color gcoBRUSH object. */ ++gceSTATUS ++gco2D_ConstructColorBrush( ++ IN gco2D Engine, ++ IN gctUINT32 OriginX, ++ IN gctUINT32 OriginY, ++ IN gctPOINTER Address, ++ IN gceSURF_FORMAT Format, ++ IN gctUINT64 Mask, ++ gcoBRUSH * Brush ++ ); ++ ++/* Clear one or more rectangular areas. */ ++gceSTATUS ++gco2D_Clear( ++ IN gco2D Engine, ++ IN gctUINT32 RectCount, ++ IN gcsRECT_PTR Rect, ++ IN gctUINT32 Color32, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++/* Draw one or more Bresenham lines. */ ++gceSTATUS ++gco2D_Line( ++ IN gco2D Engine, ++ IN gctUINT32 LineCount, ++ IN gcsRECT_PTR Position, ++ IN gcoBRUSH Brush, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++/* Draw one or more Bresenham lines based on the 32-bit color. */ ++gceSTATUS ++gco2D_ColorLine( ++ IN gco2D Engine, ++ IN gctUINT32 LineCount, ++ IN gcsRECT_PTR Position, ++ IN gctUINT32 Color32, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++/* Generic blit. */ ++gceSTATUS ++gco2D_Blit( ++ IN gco2D Engine, ++ IN gctUINT32 RectCount, ++ IN gcsRECT_PTR Rect, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++gceSTATUS ++gco2D_Blend( ++ IN gco2D Engine, ++ IN gctUINT32 SrcCount, ++ IN gctUINT32 RectCount, ++ IN gcsRECT_PTR Rect, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++/* Batch blit. */ ++gceSTATUS ++gco2D_BatchBlit( ++ IN gco2D Engine, ++ IN gctUINT32 RectCount, ++ IN gcsRECT_PTR SrcRect, ++ IN gcsRECT_PTR DestRect, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++/* Stretch blit. */ ++gceSTATUS ++gco2D_StretchBlit( ++ IN gco2D Engine, ++ IN gctUINT32 RectCount, ++ IN gcsRECT_PTR Rect, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++/* Monochrome blit. */ ++gceSTATUS ++gco2D_MonoBlit( ++ IN gco2D Engine, ++ IN gctPOINTER StreamBits, ++ IN gcsPOINT_PTR StreamSize, ++ IN gcsRECT_PTR StreamRect, ++ IN gceSURF_MONOPACK SrcStreamPack, ++ IN gceSURF_MONOPACK DestStreamPack, ++ IN gcsRECT_PTR DestRect, ++ IN gctUINT32 FgRop, ++ IN gctUINT32 BgRop, ++ IN gceSURF_FORMAT DestFormat ++ ); ++ ++gceSTATUS ++gco2D_MonoBlitEx( ++ IN gco2D Engine, ++ IN gctPOINTER StreamBits, ++ IN gctINT32 StreamStride, ++ IN gctINT32 StreamWidth, ++ IN gctINT32 StreamHeight, ++ IN gctINT32 StreamX, ++ IN gctINT32 StreamY, ++ IN gctUINT32 FgColor, ++ IN gctUINT32 BgColor, ++ IN gcsRECT_PTR SrcRect, ++ IN gcsRECT_PTR DstRect, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop ++ ); ++ ++/* Set kernel size. */ ++gceSTATUS ++gco2D_SetKernelSize( ++ IN gco2D Engine, ++ IN gctUINT8 HorKernelSize, ++ IN gctUINT8 VerKernelSize ++ ); ++ ++/* Set filter type. */ ++gceSTATUS ++gco2D_SetFilterType( ++ IN gco2D Engine, ++ IN gceFILTER_TYPE FilterType ++ ); ++ ++/* Set the filter kernel by user. */ ++gceSTATUS ++gco2D_SetUserFilterKernel( ++ IN gco2D Engine, ++ IN gceFILTER_PASS_TYPE PassType, ++ IN gctUINT16_PTR KernelArray ++ ); ++ ++/* Select the pass(es) to be done for user defined filter. */ ++gceSTATUS ++gco2D_EnableUserFilterPasses( ++ IN gco2D Engine, ++ IN gctBOOL HorPass, ++ IN gctBOOL VerPass ++ ); ++ ++/* Frees the temporary buffer allocated by filter blit operation. */ ++gceSTATUS ++gco2D_FreeFilterBuffer( ++ IN gco2D Engine ++ ); ++ ++/* Filter blit. */ ++gceSTATUS ++gco2D_FilterBlit( ++ IN gco2D Engine, ++ IN gctUINT32 SrcAddress, ++ IN gctUINT SrcStride, ++ IN gctUINT32 SrcUAddress, ++ IN gctUINT SrcUStride, ++ IN gctUINT32 SrcVAddress, ++ IN gctUINT SrcVStride, ++ IN gceSURF_FORMAT SrcFormat, ++ IN gceSURF_ROTATION SrcRotation, ++ IN gctUINT32 SrcSurfaceWidth, ++ IN gcsRECT_PTR SrcRect, ++ IN gctUINT32 DestAddress, ++ IN gctUINT DestStride, ++ IN gceSURF_FORMAT DestFormat, ++ IN gceSURF_ROTATION DestRotation, ++ IN gctUINT32 DestSurfaceWidth, ++ IN gcsRECT_PTR DestRect, ++ IN gcsRECT_PTR DestSubRect ++ ); ++ ++/* Filter blit extension for full rotation. */ ++gceSTATUS ++gco2D_FilterBlitEx( ++ IN gco2D Engine, ++ IN gctUINT32 SrcAddress, ++ IN gctUINT SrcStride, ++ IN gctUINT32 SrcUAddress, ++ IN gctUINT SrcUStride, ++ IN gctUINT32 SrcVAddress, ++ IN gctUINT SrcVStride, ++ IN gceSURF_FORMAT SrcFormat, ++ IN gceSURF_ROTATION SrcRotation, ++ IN gctUINT32 SrcSurfaceWidth, ++ IN gctUINT32 SrcSurfaceHeight, ++ IN gcsRECT_PTR SrcRect, ++ IN gctUINT32 DestAddress, ++ IN gctUINT DestStride, ++ IN gceSURF_FORMAT DestFormat, ++ IN gceSURF_ROTATION DestRotation, ++ IN gctUINT32 DestSurfaceWidth, ++ IN gctUINT32 DestSurfaceHeight, ++ IN gcsRECT_PTR DestRect, ++ IN gcsRECT_PTR DestSubRect ++ ); ++ ++gceSTATUS ++gco2D_FilterBlitEx2( ++ IN gco2D Engine, ++ IN gctUINT32_PTR SrcAddresses, ++ IN gctUINT32 SrcAddressNum, ++ IN gctUINT32_PTR SrcStrides, ++ IN gctUINT32 SrcStrideNum, ++ IN gceTILING SrcTiling, ++ IN gceSURF_FORMAT SrcFormat, ++ IN gceSURF_ROTATION SrcRotation, ++ IN gctUINT32 SrcSurfaceWidth, ++ IN gctUINT32 SrcSurfaceHeight, ++ IN gcsRECT_PTR SrcRect, ++ IN gctUINT32_PTR DestAddresses, ++ IN gctUINT32 DestAddressNum, ++ IN gctUINT32_PTR DestStrides, ++ IN gctUINT32 DestStrideNum, ++ IN gceTILING DestTiling, ++ IN gceSURF_FORMAT DestFormat, ++ IN gceSURF_ROTATION DestRotation, ++ IN gctUINT32 DestSurfaceWidth, ++ IN gctUINT32 DestSurfaceHeight, ++ IN gcsRECT_PTR DestRect, ++ IN gcsRECT_PTR DestSubRect ++ ); ++ ++/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ ++gceSTATUS ++gco2D_EnableAlphaBlend( ++ IN gco2D Engine, ++ IN gctUINT8 SrcGlobalAlphaValue, ++ IN gctUINT8 DstGlobalAlphaValue, ++ IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, ++ IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, ++ IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, ++ IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, ++ IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, ++ IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, ++ IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, ++ IN gceSURF_PIXEL_COLOR_MODE DstColorMode ++ ); ++ ++/* Enable alpha blending engine in the hardware. */ ++gceSTATUS ++gco2D_EnableAlphaBlendAdvanced( ++ IN gco2D Engine, ++ IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, ++ IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, ++ IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, ++ IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, ++ IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, ++ IN gceSURF_BLEND_FACTOR_MODE DstFactorMode ++ ); ++ ++/* Enable alpha blending engine with Porter Duff rule. */ ++gceSTATUS ++gco2D_SetPorterDuffBlending( ++ IN gco2D Engine, ++ IN gce2D_PORTER_DUFF_RULE Rule ++ ); ++ ++/* Disable alpha blending engine in the hardware and engage the ROP engine. */ ++gceSTATUS ++gco2D_DisableAlphaBlend( ++ IN gco2D Engine ++ ); ++ ++/* Retrieve the maximum number of 32-bit data chunks for a single DE command. */ ++gctUINT32 ++gco2D_GetMaximumDataCount( ++ void ++ ); ++ ++/* Retrieve the maximum number of rectangles, that can be passed in a single DE command. */ ++gctUINT32 ++gco2D_GetMaximumRectCount( ++ void ++ ); ++ ++/* Returns the pixel alignment of the surface. */ ++gceSTATUS ++gco2D_GetPixelAlignment( ++ gceSURF_FORMAT Format, ++ gcsPOINT_PTR Alignment ++ ); ++ ++/* Retrieve monochrome stream pack size. */ ++gceSTATUS ++gco2D_GetPackSize( ++ IN gceSURF_MONOPACK StreamPack, ++ OUT gctUINT32 * PackWidth, ++ OUT gctUINT32 * PackHeight ++ ); ++ ++/* Flush the 2D pipeline. */ ++gceSTATUS ++gco2D_Flush( ++ IN gco2D Engine ++ ); ++ ++/* Load 256-entry color table for INDEX8 source surfaces. */ ++gceSTATUS ++gco2D_LoadPalette( ++ IN gco2D Engine, ++ IN gctUINT FirstIndex, ++ IN gctUINT IndexCount, ++ IN gctPOINTER ColorTable, ++ IN gctBOOL ColorConvert ++ ); ++ ++/* Enable/disable 2D BitBlt mirrorring. */ ++gceSTATUS ++gco2D_SetBitBlitMirror( ++ IN gco2D Engine, ++ IN gctBOOL HorizontalMirror, ++ IN gctBOOL VerticalMirror ++ ); ++ ++/* ++ * Set the transparency for source, destination and pattern. ++ * It also enable or disable the DFB color key mode. ++ */ ++gceSTATUS ++gco2D_SetTransparencyAdvancedEx( ++ IN gco2D Engine, ++ IN gce2D_TRANSPARENCY SrcTransparency, ++ IN gce2D_TRANSPARENCY DstTransparency, ++ IN gce2D_TRANSPARENCY PatTransparency, ++ IN gctBOOL EnableDFBColorKeyMode ++ ); ++ ++/* Set the transparency for source, destination and pattern. */ ++gceSTATUS ++gco2D_SetTransparencyAdvanced( ++ IN gco2D Engine, ++ IN gce2D_TRANSPARENCY SrcTransparency, ++ IN gce2D_TRANSPARENCY DstTransparency, ++ IN gce2D_TRANSPARENCY PatTransparency ++ ); ++ ++/* Set the source color key. */ ++gceSTATUS ++gco2D_SetSourceColorKeyAdvanced( ++ IN gco2D Engine, ++ IN gctUINT32 ColorKey ++ ); ++ ++/* Set the source color key range. */ ++gceSTATUS ++gco2D_SetSourceColorKeyRangeAdvanced( ++ IN gco2D Engine, ++ IN gctUINT32 ColorKeyLow, ++ IN gctUINT32 ColorKeyHigh ++ ); ++ ++/* Set the target color key. */ ++gceSTATUS ++gco2D_SetTargetColorKeyAdvanced( ++ IN gco2D Engine, ++ IN gctUINT32 ColorKey ++ ); ++ ++/* Set the target color key range. */ ++gceSTATUS ++gco2D_SetTargetColorKeyRangeAdvanced( ++ IN gco2D Engine, ++ IN gctUINT32 ColorKeyLow, ++ IN gctUINT32 ColorKeyHigh ++ ); ++ ++/* Set the YUV color space mode. */ ++gceSTATUS ++gco2D_SetYUVColorMode( ++ IN gco2D Engine, ++ IN gce2D_YUV_COLOR_MODE Mode ++ ); ++ ++/* Setup the source global color value in ARGB8 format. */ ++gceSTATUS gco2D_SetSourceGlobalColorAdvanced( ++ IN gco2D Engine, ++ IN gctUINT32 Color32 ++ ); ++ ++/* Setup the target global color value in ARGB8 format. */ ++gceSTATUS gco2D_SetTargetGlobalColorAdvanced( ++ IN gco2D Engine, ++ IN gctUINT32 Color32 ++ ); ++ ++/* Setup the source and target pixel multiply modes. */ ++gceSTATUS ++gco2D_SetPixelMultiplyModeAdvanced( ++ IN gco2D Engine, ++ IN gce2D_PIXEL_COLOR_MULTIPLY_MODE SrcPremultiplySrcAlpha, ++ IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstPremultiplyDstAlpha, ++ IN gce2D_GLOBAL_COLOR_MULTIPLY_MODE SrcPremultiplyGlobalMode, ++ IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstDemultiplyDstAlpha ++ ); ++ ++/* Set the GPU clock cycles after which the idle engine will keep auto-flushing. */ ++gceSTATUS ++gco2D_SetAutoFlushCycles( ++ IN gco2D Engine, ++ IN gctUINT32 Cycles ++ ); ++ ++#if VIVANTE_PROFILER ++/* Read the profile registers available in the 2D engine and sets them in the profile. ++ The function will also reset the pixelsRendered counter every time. ++*/ ++gceSTATUS ++gco2D_ProfileEngine( ++ IN gco2D Engine, ++ OPTIONAL gcs2D_PROFILE_PTR Profile ++ ); ++#endif ++ ++/* Enable or disable 2D dithering. */ ++gceSTATUS ++gco2D_EnableDither( ++ IN gco2D Engine, ++ IN gctBOOL Enable ++ ); ++ ++gceSTATUS ++gco2D_SetGenericSource( ++ IN gco2D Engine, ++ IN gctUINT32_PTR Addresses, ++ IN gctUINT32 AddressNum, ++ IN gctUINT32_PTR Strides, ++ IN gctUINT32 StrideNum, ++ IN gceTILING Tiling, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctUINT32 SurfaceHeight ++); ++ ++gceSTATUS ++gco2D_SetGenericTarget( ++ IN gco2D Engine, ++ IN gctUINT32_PTR Addresses, ++ IN gctUINT32 AddressNum, ++ IN gctUINT32_PTR Strides, ++ IN gctUINT32 StrideNum, ++ IN gceTILING Tiling, ++ IN gceSURF_FORMAT Format, ++ IN gceSURF_ROTATION Rotation, ++ IN gctUINT32 SurfaceWidth, ++ IN gctUINT32 SurfaceHeight ++); ++ ++gceSTATUS ++gco2D_SetCurrentSourceIndex( ++ IN gco2D Engine, ++ IN gctUINT32 SrcIndex ++ ); ++ ++gceSTATUS ++gco2D_MultiSourceBlit( ++ IN gco2D Engine, ++ IN gctUINT32 SourceMask, ++ IN gcsRECT_PTR DestRect, ++ IN gctUINT32 RectCount ++ ); ++ ++gceSTATUS ++gco2D_SetROP( ++ IN gco2D Engine, ++ IN gctUINT8 FgRop, ++ IN gctUINT8 BgRop ++ ); ++ ++gceSTATUS ++gco2D_SetGdiStretchMode( ++ IN gco2D Engine, ++ IN gctBOOL Enable ++ ); ++ ++gceSTATUS ++gco2D_SetSourceTileStatus( ++ IN gco2D Engine, ++ IN gce2D_TILE_STATUS_CONFIG TSControl, ++ IN gceSURF_FORMAT CompressedFormat, ++ IN gctUINT32 ClearValue, ++ IN gctUINT32 GpuAddress ++ ); ++ ++gceSTATUS ++gco2D_SetTargetTileStatus( ++ IN gco2D Engine, ++ IN gce2D_TILE_STATUS_CONFIG TileStatusConfig, ++ IN gceSURF_FORMAT CompressedFormat, ++ IN gctUINT32 ClearValue, ++ IN gctUINT32 GpuAddress ++ ); ++ ++gceSTATUS ++gco2D_QueryU32( ++ IN gco2D Engine, ++ IN gce2D_QUERY Item, ++ OUT gctUINT32_PTR Value ++ ); ++ ++gceSTATUS ++gco2D_SetStateU32( ++ IN gco2D Engine, ++ IN gce2D_STATE State, ++ IN gctUINT32 Value ++ ); ++ ++gceSTATUS ++gco2D_SetStateArrayI32( ++ IN gco2D Engine, ++ IN gce2D_STATE State, ++ IN gctINT32_PTR Array, ++ IN gctINT32 ArraySize ++ ); ++ ++gceSTATUS ++gco2D_SetStateArrayU32( ++ IN gco2D Engine, ++ IN gce2D_STATE State, ++ IN gctUINT32_PTR Array, ++ IN gctINT32 ArraySize ++ ); ++ ++gceSTATUS ++gco2D_SetTargetRect( ++ IN gco2D Engine, ++ IN gcsRECT_PTR Rect ++ ); ++ ++gceSTATUS ++gco2D_Set2DEngine( ++ IN gco2D Engine ++ ); ++ ++gceSTATUS ++gco2D_UnSet2DEngine( ++ IN gco2D Engine ++ ); ++ ++gceSTATUS ++gco2D_Get2DEngine( ++ OUT gco2D * Engine ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_raster_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_rename.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_rename.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_rename.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_rename.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,243 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_rename_h_ ++#define __gc_hal_rename_h_ ++ ++ ++#if defined(_HAL2D_APPENDIX) ++ ++#define _HAL2D_RENAME_2(api, appendix) api ## appendix ++#define _HAL2D_RENAME_1(api, appendix) _HAL2D_RENAME_2(api, appendix) ++#define gcmHAL2D(api) _HAL2D_RENAME_1(api, _HAL2D_APPENDIX) ++ ++ ++#define gckOS_Construct gcmHAL2D(gckOS_Construct) ++#define gckOS_Destroy gcmHAL2D(gckOS_Destroy) ++#define gckOS_QueryVideoMemory gcmHAL2D(gckOS_QueryVideoMemory) ++#define gckOS_Allocate gcmHAL2D(gckOS_Allocate) ++#define gckOS_Free gcmHAL2D(gckOS_Free) ++#define gckOS_AllocateMemory gcmHAL2D(gckOS_AllocateMemory) ++#define gckOS_FreeMemory gcmHAL2D(gckOS_FreeMemory) ++#define gckOS_AllocatePagedMemory gcmHAL2D(gckOS_AllocatePagedMemory) ++#define gckOS_AllocatePagedMemoryEx gcmHAL2D(gckOS_AllocatePagedMemoryEx) ++#define gckOS_LockPages gcmHAL2D(gckOS_LockPages) ++#define gckOS_MapPages gcmHAL2D(gckOS_MapPages) ++#define gckOS_UnlockPages gcmHAL2D(gckOS_UnlockPages) ++#define gckOS_FreePagedMemory gcmHAL2D(gckOS_FreePagedMemory) ++#define gckOS_AllocateNonPagedMemory gcmHAL2D(gckOS_AllocateNonPagedMemory) ++#define gckOS_FreeNonPagedMemory gcmHAL2D(gckOS_FreeNonPagedMemory) ++#define gckOS_AllocateContiguous gcmHAL2D(gckOS_AllocateContiguous) ++#define gckOS_FreeContiguous gcmHAL2D(gckOS_FreeContiguous) ++#define gckOS_GetPageSize gcmHAL2D(gckOS_GetPageSize) ++#define gckOS_GetPhysicalAddress gcmHAL2D(gckOS_GetPhysicalAddress) ++#define gckOS_UserLogicalToPhysical gcmHAL2D(gckOS_UserLogicalToPhysical) ++#define gckOS_GetPhysicalAddressProcess gcmHAL2D(gckOS_GetPhysicalAddressProcess) ++#define gckOS_MapPhysical gcmHAL2D(gckOS_MapPhysical) ++#define gckOS_UnmapPhysical gcmHAL2D(gckOS_UnmapPhysical) ++#define gckOS_ReadRegister gcmHAL2D(gckOS_ReadRegister) ++#define gckOS_WriteRegister gcmHAL2D(gckOS_WriteRegister) ++#define gckOS_WriteMemory gcmHAL2D(gckOS_WriteMemory) ++#define gckOS_MapMemory gcmHAL2D(gckOS_MapMemory) ++#define gckOS_UnmapMemory gcmHAL2D(gckOS_UnmapMemory) ++#define gckOS_UnmapMemoryEx gcmHAL2D(gckOS_UnmapMemoryEx) ++#define gckOS_CreateMutex gcmHAL2D(gckOS_CreateMutex) ++#define gckOS_DeleteMutex gcmHAL2D(gckOS_DeleteMutex) ++#define gckOS_AcquireMutex gcmHAL2D(gckOS_AcquireMutex) ++#define gckOS_ReleaseMutex gcmHAL2D(gckOS_ReleaseMutex) ++#define gckOS_AtomicExchange gcmHAL2D(gckOS_AtomicExchange) ++#define gckOS_AtomicExchangePtr gcmHAL2D(gckOS_AtomicExchangePtr) ++#define gckOS_AtomConstruct gcmHAL2D(gckOS_AtomConstruct) ++#define gckOS_AtomDestroy gcmHAL2D(gckOS_AtomDestroy) ++#define gckOS_AtomGet gcmHAL2D(gckOS_AtomGet) ++#define gckOS_AtomIncrement gcmHAL2D(gckOS_AtomIncrement) ++#define gckOS_AtomDecrement gcmHAL2D(gckOS_AtomDecrement) ++#define gckOS_Delay gcmHAL2D(gckOS_Delay) ++#define gckOS_GetTime gcmHAL2D(gckOS_GetTime) ++#define gckOS_MemoryBarrier gcmHAL2D(gckOS_MemoryBarrier) ++#define gckOS_MapUserPointer gcmHAL2D(gckOS_MapUserPointer) ++#define gckOS_UnmapUserPointer gcmHAL2D(gckOS_UnmapUserPointer) ++#define gckOS_QueryNeedCopy gcmHAL2D(gckOS_QueryNeedCopy) ++#define gckOS_CopyFromUserData gcmHAL2D(gckOS_CopyFromUserData) ++#define gckOS_CopyToUserData gcmHAL2D(gckOS_CopyToUserData) ++#define gckOS_SuspendInterrupt gcmHAL2D(gckOS_SuspendInterrupt) ++#define gckOS_ResumeInterrupt gcmHAL2D(gckOS_ResumeInterrupt) ++#define gckOS_GetBaseAddress gcmHAL2D(gckOS_GetBaseAddress) ++#define gckOS_MemCopy gcmHAL2D(gckOS_MemCopy) ++#define gckOS_ZeroMemory gcmHAL2D(gckOS_ZeroMemory) ++#define gckOS_DeviceControl gcmHAL2D(gckOS_DeviceControl) ++#define gckOS_GetProcessID gcmHAL2D(gckOS_GetProcessID) ++#define gckOS_GetThreadID gcmHAL2D(gckOS_GetThreadID) ++#define gckOS_CreateSignal gcmHAL2D(gckOS_CreateSignal) ++#define gckOS_DestroySignal gcmHAL2D(gckOS_DestroySignal) ++#define gckOS_Signal gcmHAL2D(gckOS_Signal) ++#define gckOS_WaitSignal gcmHAL2D(gckOS_WaitSignal) ++#define gckOS_MapSignal gcmHAL2D(gckOS_MapSignal) ++#define gckOS_MapUserMemory gcmHAL2D(gckOS_MapUserMemory) ++#define gckOS_UnmapUserMemory gcmHAL2D(gckOS_UnmapUserMemory) ++#define gckOS_CreateUserSignal gcmHAL2D(gckOS_CreateUserSignal) ++#define gckOS_DestroyUserSignal gcmHAL2D(gckOS_DestroyUserSignal) ++#define gckOS_WaitUserSignal gcmHAL2D(gckOS_WaitUserSignal) ++#define gckOS_SignalUserSignal gcmHAL2D(gckOS_SignalUserSignal) ++#define gckOS_UserSignal gcmHAL2D(gckOS_UserSignal) ++#define gckOS_UserSignal gcmHAL2D(gckOS_UserSignal) ++#define gckOS_CacheClean gcmHAL2D(gckOS_CacheClean) ++#define gckOS_CacheFlush gcmHAL2D(gckOS_CacheFlush) ++#define gckOS_SetDebugLevel gcmHAL2D(gckOS_SetDebugLevel) ++#define gckOS_SetDebugZone gcmHAL2D(gckOS_SetDebugZone) ++#define gckOS_SetDebugLevelZone gcmHAL2D(gckOS_SetDebugLevelZone) ++#define gckOS_SetDebugZones gcmHAL2D(gckOS_SetDebugZones) ++#define gckOS_SetDebugFile gcmHAL2D(gckOS_SetDebugFile) ++#define gckOS_Broadcast gcmHAL2D(gckOS_Broadcast) ++#define gckOS_SetGPUPower gcmHAL2D(gckOS_SetGPUPower) ++#define gckOS_CreateSemaphore gcmHAL2D(gckOS_CreateSemaphore) ++#define gckOS_DestroySemaphore gcmHAL2D(gckOS_DestroySemaphore) ++#define gckOS_AcquireSemaphore gcmHAL2D(gckOS_AcquireSemaphore) ++#define gckOS_ReleaseSemaphore gcmHAL2D(gckOS_ReleaseSemaphore) ++#define gckHEAP_Construct gcmHAL2D(gckHEAP_Construct) ++#define gckHEAP_Destroy gcmHAL2D(gckHEAP_Destroy) ++#define gckHEAP_Allocate gcmHAL2D(gckHEAP_Allocate) ++#define gckHEAP_Free gcmHAL2D(gckHEAP_Free) ++#define gckHEAP_ProfileStart gcmHAL2D(gckHEAP_ProfileStart) ++#define gckHEAP_ProfileEnd gcmHAL2D(gckHEAP_ProfileEnd) ++#define gckHEAP_Test gcmHAL2D(gckHEAP_Test) ++#define gckVIDMEM_Construct gcmHAL2D(gckVIDMEM_Construct) ++#define gckVIDMEM_Destroy gcmHAL2D(gckVIDMEM_Destroy) ++#define gckVIDMEM_Allocate gcmHAL2D(gckVIDMEM_Allocate) ++#define gckVIDMEM_AllocateLinear gcmHAL2D(gckVIDMEM_AllocateLinear) ++#define gckVIDMEM_Free gcmHAL2D(gckVIDMEM_Free) ++#define gckVIDMEM_Lock gcmHAL2D(gckVIDMEM_Lock) ++#define gckVIDMEM_Unlock gcmHAL2D(gckVIDMEM_Unlock) ++#define gckVIDMEM_ConstructVirtual gcmHAL2D(gckVIDMEM_ConstructVirtual) ++#define gckVIDMEM_DestroyVirtual gcmHAL2D(gckVIDMEM_DestroyVirtual) ++#define gckKERNEL_Construct gcmHAL2D(gckKERNEL_Construct) ++#define gckKERNEL_Destroy gcmHAL2D(gckKERNEL_Destroy) ++#define gckKERNEL_Dispatch gcmHAL2D(gckKERNEL_Dispatch) ++#define gckKERNEL_QueryVideoMemory gcmHAL2D(gckKERNEL_QueryVideoMemory) ++#define gckKERNEL_GetVideoMemoryPool gcmHAL2D(gckKERNEL_GetVideoMemoryPool) ++#define gckKERNEL_MapVideoMemory gcmHAL2D(gckKERNEL_MapVideoMemory) ++#define gckKERNEL_UnmapVideoMemory gcmHAL2D(gckKERNEL_UnmapVideoMemory) ++#define gckKERNEL_MapMemory gcmHAL2D(gckKERNEL_MapMemory) ++#define gckKERNEL_UnmapMemory gcmHAL2D(gckKERNEL_UnmapMemory) ++#define gckKERNEL_Notify gcmHAL2D(gckKERNEL_Notify) ++#define gckKERNEL_QuerySettings gcmHAL2D(gckKERNEL_QuerySettings) ++#define gckKERNEL_Recovery gcmHAL2D(gckKERNEL_Recovery) ++#define gckKERNEL_OpenUserData gcmHAL2D(gckKERNEL_OpenUserData) ++#define gckKERNEL_CloseUserData gcmHAL2D(gckKERNEL_CloseUserData) ++#define gckHARDWARE_Construct gcmHAL2D(gckHARDWARE_Construct) ++#define gckHARDWARE_Destroy gcmHAL2D(gckHARDWARE_Destroy) ++#define gckHARDWARE_QuerySystemMemory gcmHAL2D(gckHARDWARE_QuerySystemMemory) ++#define gckHARDWARE_BuildVirtualAddress gcmHAL2D(gckHARDWARE_BuildVirtualAddress) ++#define gckHARDWARE_QueryCommandBuffer gcmHAL2D(gckHARDWARE_QueryCommandBuffer) ++#define gckHARDWARE_WaitLink gcmHAL2D(gckHARDWARE_WaitLink) ++#define gckHARDWARE_Execute gcmHAL2D(gckHARDWARE_Execute) ++#define gckHARDWARE_End gcmHAL2D(gckHARDWARE_End) ++#define gckHARDWARE_Nop gcmHAL2D(gckHARDWARE_Nop) ++#define gckHARDWARE_PipeSelect gcmHAL2D(gckHARDWARE_PipeSelect) ++#define gckHARDWARE_Link gcmHAL2D(gckHARDWARE_Link) ++#define gckHARDWARE_Event gcmHAL2D(gckHARDWARE_Event) ++#define gckHARDWARE_QueryMemory gcmHAL2D(gckHARDWARE_QueryMemory) ++#define gckHARDWARE_QueryChipIdentity gcmHAL2D(gckHARDWARE_QueryChipIdentity) ++#define gckHARDWARE_QueryChipSpecs gcmHAL2D(gckHARDWARE_QueryChipSpecs) ++#define gckHARDWARE_QueryShaderCaps gcmHAL2D(gckHARDWARE_QueryShaderCaps) ++#define gckHARDWARE_ConvertFormat gcmHAL2D(gckHARDWARE_ConvertFormat) ++#define gckHARDWARE_SplitMemory gcmHAL2D(gckHARDWARE_SplitMemory) ++#define gckHARDWARE_AlignToTile gcmHAL2D(gckHARDWARE_AlignToTile) ++#define gckHARDWARE_UpdateQueueTail gcmHAL2D(gckHARDWARE_UpdateQueueTail) ++#define gckHARDWARE_ConvertLogical gcmHAL2D(gckHARDWARE_ConvertLogical) ++#define gckHARDWARE_Interrupt gcmHAL2D(gckHARDWARE_Interrupt) ++#define gckHARDWARE_SetMMU gcmHAL2D(gckHARDWARE_SetMMU) ++#define gckHARDWARE_FlushMMU gcmHAL2D(gckHARDWARE_FlushMMU) ++#define gckHARDWARE_GetIdle gcmHAL2D(gckHARDWARE_GetIdle) ++#define gckHARDWARE_Flush gcmHAL2D(gckHARDWARE_Flush) ++#define gckHARDWARE_SetFastClear gcmHAL2D(gckHARDWARE_SetFastClear) ++#define gckHARDWARE_ReadInterrupt gcmHAL2D(gckHARDWARE_ReadInterrupt) ++#define gckHARDWARE_SetPowerManagementState gcmHAL2D(gckHARDWARE_SetPowerManagementState) ++#define gckHARDWARE_QueryPowerManagementState gcmHAL2D(gckHARDWARE_QueryPowerManagementState) ++#define gckHARDWARE_ProfileEngine2D gcmHAL2D(gckHARDWARE_ProfileEngine2D) ++#define gckHARDWARE_InitializeHardware gcmHAL2D(gckHARDWARE_InitializeHardware) ++#define gckHARDWARE_Reset gcmHAL2D(gckHARDWARE_Reset) ++#define gckINTERRUPT_Construct gcmHAL2D(gckINTERRUPT_Construct) ++#define gckINTERRUPT_Destroy gcmHAL2D(gckINTERRUPT_Destroy) ++#define gckINTERRUPT_SetHandler gcmHAL2D(gckINTERRUPT_SetHandler) ++#define gckINTERRUPT_Notify gcmHAL2D(gckINTERRUPT_Notify) ++#define gckEVENT_Construct gcmHAL2D(gckEVENT_Construct) ++#define gckEVENT_Destroy gcmHAL2D(gckEVENT_Destroy) ++#define gckEVENT_AddList gcmHAL2D(gckEVENT_AddList) ++#define gckEVENT_FreeNonPagedMemory gcmHAL2D(gckEVENT_FreeNonPagedMemory) ++#define gckEVENT_FreeContiguousMemory gcmHAL2D(gckEVENT_FreeContiguousMemory) ++#define gckEVENT_FreeVideoMemory gcmHAL2D(gckEVENT_FreeVideoMemory) ++#define gckEVENT_Signal gcmHAL2D(gckEVENT_Signal) ++#define gckEVENT_Unlock gcmHAL2D(gckEVENT_Unlock) ++#define gckEVENT_Submit gcmHAL2D(gckEVENT_Submit) ++#define gckEVENT_Commit gcmHAL2D(gckEVENT_Commit) ++#define gckEVENT_Notify gcmHAL2D(gckEVENT_Notify) ++#define gckEVENT_Interrupt gcmHAL2D(gckEVENT_Interrupt) ++#define gckCOMMAND_Construct gcmHAL2D(gckCOMMAND_Construct) ++#define gckCOMMAND_Destroy gcmHAL2D(gckCOMMAND_Destroy) ++#define gckCOMMAND_EnterCommit gcmHAL2D(gckCOMMAND_EnterCommit) ++#define gckCOMMAND_ExitCommit gcmHAL2D(gckCOMMAND_ExitCommit) ++#define gckCOMMAND_Start gcmHAL2D(gckCOMMAND_Start) ++#define gckCOMMAND_Stop gcmHAL2D(gckCOMMAND_Stop) ++#define gckCOMMAND_Commit gcmHAL2D(gckCOMMAND_Commit) ++#define gckCOMMAND_Reserve gcmHAL2D(gckCOMMAND_Reserve) ++#define gckCOMMAND_Execute gcmHAL2D(gckCOMMAND_Execute) ++#define gckCOMMAND_Stall gcmHAL2D(gckCOMMAND_Stall) ++#define gckCOMMAND_Attach gcmHAL2D(gckCOMMAND_Attach) ++#define gckCOMMAND_Detach gcmHAL2D(gckCOMMAND_Detach) ++#define gckMMU_Construct gcmHAL2D(gckMMU_Construct) ++#define gckMMU_Destroy gcmHAL2D(gckMMU_Destroy) ++#define gckMMU_AllocatePages gcmHAL2D(gckMMU_AllocatePages) ++#define gckMMU_FreePages gcmHAL2D(gckMMU_FreePages) ++#define gckMMU_Test gcmHAL2D(gckMMU_Test) ++#define gckHARDWARE_QueryProfileRegisters gcmHAL2D(gckHARDWARE_QueryProfileRegisters) ++ ++ ++#define FindMdlMap gcmHAL2D(FindMdlMap) ++#define OnProcessExit gcmHAL2D(OnProcessExit) ++ ++#define gckGALDEVICE_Destroy gcmHAL2D(gckGALDEVICE_Destroy) ++#define gckOS_Print gcmHAL2D(gckOS_Print) ++#define gckGALDEVICE_FreeMemory gcmHAL2D(gckGALDEVICE_FreeMemory) ++#define gckGALDEVICE_AllocateMemory gcmHAL2D(gckGALDEVICE_AllocateMemory) ++#define gckOS_DebugBreak gcmHAL2D(gckOS_DebugBreak) ++#define gckGALDEVICE_Release_ISR gcmHAL2D(gckGALDEVICE_Release_ISR) ++#define gckOS_Verify gcmHAL2D(gckOS_Verify) ++#define gckCOMMAND_Release gcmHAL2D(gckCOMMAND_Release) ++#define gckGALDEVICE_Stop gcmHAL2D(gckGALDEVICE_Stop) ++#define gckGALDEVICE_Construct gcmHAL2D(gckGALDEVICE_Construct) ++#define gckOS_DebugFatal gcmHAL2D(gckOS_DebugFatal) ++#define gckOS_DebugTrace gcmHAL2D(gckOS_DebugTrace) ++#define gckHARDWARE_GetBaseAddress gcmHAL2D(gckHARDWARE_GetBaseAddress) ++#define gckGALDEVICE_Setup_ISR gcmHAL2D(gckGALDEVICE_Setup_ISR) ++#define gckKERNEL_AttachProcess gcmHAL2D(gckKERNEL_AttachProcess) ++#define gckKERNEL_AttachProcessEx gcmHAL2D(gckKERNEL_AttachProcessEx) ++#define gckGALDEVICE_Start_Thread gcmHAL2D(gckGALDEVICE_Start_Thread) ++#define gckHARDWARE_QueryIdle gcmHAL2D(gckHARDWARE_QueryIdle) ++#define gckGALDEVICE_Start gcmHAL2D(gckGALDEVICE_Start) ++#define gckOS_GetKernelLogical gcmHAL2D(gckOS_GetKernelLogical) ++#define gckOS_DebugTraceZone gcmHAL2D(gckOS_DebugTraceZone) ++#define gckGALDEVICE_Stop_Thread gcmHAL2D(gckGALDEVICE_Stop_Thread) ++#define gckHARDWARE_NeedBaseAddress gcmHAL2D(gckHARDWARE_NeedBaseAddress) ++ ++#endif ++ ++#endif /* __gc_hal_rename_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_statistics.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_statistics.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_statistics.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_statistics.h 2016-06-19 22:11:55.157149718 +0200 +@@ -0,0 +1,99 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_statistics_h_ ++#define __gc_hal_statistics_h_ ++ ++ ++#define VIV_STAT_ENABLE_STATISTICS 0 ++ ++/* Toal number of frames for which the frame time is accounted. We have storage ++ to keep frame times for last this many frames. ++*/ ++#define VIV_STAT_FRAME_BUFFER_SIZE 30 ++ ++ ++/* ++ Total number of frames sampled for a mode. This means ++ ++ # of frames for HZ Current : VIV_STAT_EARLY_Z_SAMPLE_FRAMES ++ # of frames for HZ Switched : VIV_STAT_EARLY_Z_SAMPLE_FRAMES ++ + ++ -------------------------------------------------------- ++ : (2 * VIV_STAT_EARLY_Z_SAMPLE_FRAMES) frames needed ++ ++ IMPORTANT: This total must be smaller than VIV_STAT_FRAME_BUFFER_SIZE ++*/ ++#define VIV_STAT_EARLY_Z_SAMPLE_FRAMES 7 ++#define VIV_STAT_EARLY_Z_LATENCY_FRAMES 2 ++ ++/* Multiplication factor for previous Hz off mode. Make it more than 1.0 to advertise HZ on.*/ ++#define VIV_STAT_EARLY_Z_FACTOR (1.05f) ++ ++/* Defines the statistical data keys monitored by the statistics module */ ++typedef enum _gceSTATISTICS ++{ ++ gcvFRAME_FPS = 1, ++} ++gceSTATISTICS; ++ ++/* HAL statistics information. */ ++typedef struct _gcsSTATISTICS_EARLYZ ++{ ++ gctUINT switchBackCount; ++ gctUINT nextCheckPoint; ++ gctBOOL disabled; ++} ++gcsSTATISTICS_EARLYZ; ++ ++ ++/* HAL statistics information. */ ++typedef struct _gcsSTATISTICS ++{ ++ gctUINT64 frameTime[VIV_STAT_FRAME_BUFFER_SIZE]; ++ gctUINT64 previousFrameTime; ++ gctUINT frame; ++ gcsSTATISTICS_EARLYZ earlyZ; ++} ++gcsSTATISTICS; ++ ++ ++/* Add a frame based data into current statistics. */ ++void ++gcfSTATISTICS_AddData( ++ IN gceSTATISTICS Key, ++ IN gctUINT Value ++ ); ++ ++/* Marks the frame end and triggers statistical calculations and decisions.*/ ++void ++gcfSTATISTICS_MarkFrameEnd ( ++ void ++ ); ++ ++/* Sets whether the dynmaic HZ is disabled or not .*/ ++void ++gcfSTATISTICS_DisableDynamicEarlyZ ( ++ IN gctBOOL Disabled ++ ); ++ ++#endif /*__gc_hal_statistics_h_ */ ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_types.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_types.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_types.h 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,911 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_types_h_ ++#define __gc_hal_types_h_ ++ ++#include "gc_hal_version.h" ++#include "gc_hal_options.h" ++ ++#if !defined(VIV_KMD) ++#if defined(__KERNEL__) ++#include "linux/version.h" ++#include "linux/types.h" ++#else ++#include ++#include ++#include ++#endif ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/******************************************************************************\ ++** Platform macros. ++*/ ++ ++#if defined(__GNUC__) ++# define gcdHAS_ELLIPSIS 1 /* GCC always has it. */ ++#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) ++# define gcdHAS_ELLIPSIS 1 /* C99 has it. */ ++#elif defined(_MSC_VER) && (_MSC_VER >= 1500) ++# define gcdHAS_ELLIPSIS 1 /* MSVC 2007+ has it. */ ++#elif defined(UNDER_CE) ++#if UNDER_CE >= 600 ++# define gcdHAS_ELLIPSIS 1 ++# else ++# define gcdHAS_ELLIPSIS 0 ++# endif ++#else ++# error "gcdHAS_ELLIPSIS: Platform could not be determined" ++#endif ++ ++/******************************************************************************\ ++************************************ Keyword *********************************** ++\******************************************************************************/ ++#if defined(ANDROID) && defined(__BIONIC_FORTIFY) ++# define gcmINLINE __inline__ __attribute__ ((always_inline)) __attribute__ ((gnu_inline)) __attribute__ ((artificial)) ++#elif ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))) ++# define gcmINLINE inline /* C99 keyword. */ ++#elif defined(__GNUC__) ++# define gcmINLINE __inline__ /* GNU keyword. */ ++#elif defined(_MSC_VER) || defined(UNDER_CE) ++# define gcmINLINE __inline /* Internal keyword. */ ++#else ++# error "gcmINLINE: Platform could not be determined" ++#endif ++ ++/* Possible debug flags. */ ++#define gcdDEBUG_NONE 0 ++#define gcdDEBUG_ALL (1 << 0) ++#define gcdDEBUG_FATAL (1 << 1) ++#define gcdDEBUG_TRACE (1 << 2) ++#define gcdDEBUG_BREAK (1 << 3) ++#define gcdDEBUG_ASSERT (1 << 4) ++#define gcdDEBUG_CODE (1 << 5) ++#define gcdDEBUG_STACK (1 << 6) ++ ++#define gcmIS_DEBUG(flag) ( gcdDEBUG & (flag | gcdDEBUG_ALL) ) ++ ++#ifndef gcdDEBUG ++#if defined(DEBUG) ++# define gcdDEBUG ( gcdDEBUG_FATAL | gcdDEBUG_TRACE | gcdDEBUG_BREAK | gcdDEBUG_ASSERT ) ++# else ++# define gcdDEBUG gcdDEBUG_NONE ++# endif ++#endif ++ ++#ifdef _USRDLL ++#ifdef _MSC_VER ++#ifdef HAL_EXPORTS ++# define HALAPI __declspec(dllexport) ++# else ++# define HALAPI __declspec(dllimport) ++# endif ++# define HALDECL __cdecl ++# else ++#ifdef HAL_EXPORTS ++# define HALAPI ++# else ++# define HALAPI extern ++# endif ++# endif ++#else ++# define HALAPI ++# define HALDECL ++#endif ++ ++/******************************************************************************\ ++********************************** Common Types ******************************** ++\******************************************************************************/ ++ ++#define gcvFALSE 0 ++#define gcvTRUE 1 ++ ++#define gcvINFINITE ((gctUINT32) ~0U) ++ ++#define gcvINVALID_HANDLE ((gctHANDLE) ~0U) ++ ++typedef int gctBOOL; ++typedef gctBOOL * gctBOOL_PTR; ++ ++typedef int gctINT; ++typedef signed char gctINT8; ++typedef signed short gctINT16; ++typedef signed int gctINT32; ++typedef signed long long gctINT64; ++ ++typedef gctINT * gctINT_PTR; ++typedef gctINT8 * gctINT8_PTR; ++typedef gctINT16 * gctINT16_PTR; ++typedef gctINT32 * gctINT32_PTR; ++typedef gctINT64 * gctINT64_PTR; ++ ++typedef unsigned int gctUINT; ++typedef unsigned char gctUINT8; ++typedef unsigned short gctUINT16; ++typedef unsigned int gctUINT32; ++typedef unsigned long long gctUINT64; ++typedef uintptr_t gctUINTPTR_T; ++ ++typedef gctUINT * gctUINT_PTR; ++typedef gctUINT8 * gctUINT8_PTR; ++typedef gctUINT16 * gctUINT16_PTR; ++typedef gctUINT32 * gctUINT32_PTR; ++typedef gctUINT64 * gctUINT64_PTR; ++ ++typedef size_t gctSIZE_T; ++typedef gctSIZE_T * gctSIZE_T_PTR; ++typedef gctUINT32 gctTRACE; ++ ++#ifdef __cplusplus ++# define gcvNULL 0 ++#else ++# define gcvNULL ((void *) 0) ++#endif ++ ++#define gcvMAXINT8 0x7f ++#define gcvMININT8 0x80 ++#define gcvMAXINT16 0x7fff ++#define gcvMININT16 0x8000 ++#define gcvMAXINT32 0x7fffffff ++#define gcvMININT32 0x80000000 ++#define gcvMAXINT64 0x7fffffffffffffff ++#define gcvMININT64 0x8000000000000000 ++#define gcvMAXUINT8 0xff ++#define gcvMINUINT8 0x0 ++#define gcvMAXUINT16 0xffff ++#define gcvMINUINT16 0x8000 ++#define gcvMAXUINT32 0xffffffff ++#define gcvMINUINT32 0x80000000 ++#define gcvMAXUINT64 0xffffffffffffffff ++#define gcvMINUINT64 0x8000000000000000 ++#define gcvMAXUINTPTR_T (~(gctUINTPTR_T)0) ++ ++typedef float gctFLOAT; ++typedef signed int gctFIXED_POINT; ++typedef float * gctFLOAT_PTR; ++ ++typedef void * gctPHYS_ADDR; ++typedef void * gctHANDLE; ++typedef void * gctFILE; ++typedef void * gctSIGNAL; ++typedef void * gctWINDOW; ++typedef void * gctIMAGE; ++typedef void * gctSYNC_POINT; ++typedef void * gctSHBUF; ++ ++typedef void * gctSEMAPHORE; ++ ++typedef void * gctPOINTER; ++typedef const void * gctCONST_POINTER; ++ ++typedef char gctCHAR; ++typedef char * gctSTRING; ++typedef const char * gctCONST_STRING; ++ ++typedef struct _gcsCOUNT_STRING ++{ ++ gctSIZE_T Length; ++ gctCONST_STRING String; ++} ++gcsCOUNT_STRING; ++ ++typedef union _gcuFLOAT_UINT32 ++{ ++ gctFLOAT f; ++ gctUINT32 u; ++} ++gcuFLOAT_UINT32; ++ ++/* Fixed point constants. */ ++#define gcvZERO_X ((gctFIXED_POINT) 0x00000000) ++#define gcvHALF_X ((gctFIXED_POINT) 0x00008000) ++#define gcvONE_X ((gctFIXED_POINT) 0x00010000) ++#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000) ++#define gcvTWO_X ((gctFIXED_POINT) 0x00020000) ++ ++ ++ ++#define gcmFIXEDCLAMP_NEG1_TO_1(_x) \ ++ (((_x) < gcvNEGONE_X) \ ++ ? gcvNEGONE_X \ ++ : (((_x) > gcvONE_X) \ ++ ? gcvONE_X \ ++ : (_x))) ++ ++#define gcmFLOATCLAMP_NEG1_TO_1(_f) \ ++ (((_f) < -1.0f) \ ++ ? -1.0f \ ++ : (((_f) > 1.0f) \ ++ ? 1.0f \ ++ : (_f))) ++ ++ ++#define gcmFIXEDCLAMP_0_TO_1(_x) \ ++ (((_x) < 0) \ ++ ? 0 \ ++ : (((_x) > gcvONE_X) \ ++ ? gcvONE_X \ ++ : (_x))) ++ ++#define gcmFLOATCLAMP_0_TO_1(_f) \ ++ (((_f) < 0.0f) \ ++ ? 0.0f \ ++ : (((_f) > 1.0f) \ ++ ? 1.0f \ ++ : (_f))) ++ ++ ++/******************************************************************************\ ++******************************* Multicast Values ******************************* ++\******************************************************************************/ ++ ++/* Value types. */ ++typedef enum _gceVALUE_TYPE ++{ ++ gcvVALUE_UINT = 0x0, ++ gcvVALUE_FIXED, ++ gcvVALUE_FLOAT, ++ gcvVALUE_INT, ++ ++ /* ++ ** The value need be unsigned denormalized. clamp (0.0-1.0) should be done first. ++ */ ++ gcvVALUE_FLAG_UNSIGNED_DENORM = 0x00010000, ++ ++ /* ++ ** The value need be signed denormalized. clamp (-1.0-1.0) should be done first. ++ */ ++ gcvVALUE_FLAG_SIGNED_DENORM = 0x00020000, ++ ++ /* ++ ** The value need to gammar ++ */ ++ gcvVALUE_FLAG_GAMMAR = 0x00040000, ++ ++ /* ++ ** The value need to convert from float to float16 ++ */ ++ gcvVALUE_FLAG_FLOAT_TO_FLOAT16 = 0x0080000, ++ ++ /* ++ ** Mask for flag field. ++ */ ++ gcvVALUE_FLAG_MASK = 0xFFFF0000, ++} ++gceVALUE_TYPE; ++ ++/* Value unions. */ ++typedef union _gcuVALUE ++{ ++ gctUINT uintValue; ++ gctFIXED_POINT fixedValue; ++ gctFLOAT floatValue; ++ gctINT intValue; ++} ++gcuVALUE; ++ ++ ++ ++ ++/* Stringizing macro. */ ++#define gcmSTRING(Value) #Value ++ ++/******************************************************************************\ ++******************************* Fixed Point Math ******************************* ++\******************************************************************************/ ++ ++#define gcmXMultiply(x1, x2) gcoMATH_MultiplyFixed(x1, x2) ++#define gcmXDivide(x1, x2) gcoMATH_DivideFixed(x1, x2) ++#define gcmXMultiplyDivide(x1, x2, x3) gcoMATH_MultiplyDivideFixed(x1, x2, x3) ++ ++/* 2D Engine profile. */ ++typedef struct _gcs2D_PROFILE ++{ ++ /* Cycle count. ++ 32bit counter incremented every 2D clock cycle. ++ Wraps back to 0 when the counter overflows. ++ */ ++ gctUINT32 cycleCount; ++ ++ /* Pixels rendered by the 2D engine. ++ Resets to 0 every time it is read. */ ++ gctUINT32 pixelsRendered; ++} ++gcs2D_PROFILE; ++ ++/* Macro to combine four characters into a Charcater Code. */ ++#define gcmCC(c1, c2, c3, c4) \ ++( \ ++ (char) (c1) \ ++ | \ ++ ((char) (c2) << 8) \ ++ | \ ++ ((char) (c3) << 16) \ ++ | \ ++ ((char) (c4) << 24) \ ++) ++ ++#define gcmPRINTABLE(c) ((((c) >= ' ') && ((c) <= '}')) ? ((c) != '%' ? (c) : ' ') : ' ') ++ ++#define gcmCC_PRINT(cc) \ ++ gcmPRINTABLE((char) ( (cc) & 0xFF)), \ ++ gcmPRINTABLE((char) (((cc) >> 8) & 0xFF)), \ ++ gcmPRINTABLE((char) (((cc) >> 16) & 0xFF)), \ ++ gcmPRINTABLE((char) (((cc) >> 24) & 0xFF)) ++ ++/******************************************************************************\ ++****************************** Function Parameters ***************************** ++\******************************************************************************/ ++ ++#define IN ++#define OUT ++#define INOUT ++#define OPTIONAL ++ ++/******************************************************************************\ ++********************************* Status Codes ********************************* ++\******************************************************************************/ ++ ++typedef enum _gceSTATUS ++{ ++ gcvSTATUS_OK = 0, ++ gcvSTATUS_FALSE = 0, ++ gcvSTATUS_TRUE = 1, ++ gcvSTATUS_NO_MORE_DATA = 2, ++ gcvSTATUS_CACHED = 3, ++ gcvSTATUS_MIPMAP_TOO_LARGE = 4, ++ gcvSTATUS_NAME_NOT_FOUND = 5, ++ gcvSTATUS_NOT_OUR_INTERRUPT = 6, ++ gcvSTATUS_MISMATCH = 7, ++ gcvSTATUS_MIPMAP_TOO_SMALL = 8, ++ gcvSTATUS_LARGER = 9, ++ gcvSTATUS_SMALLER = 10, ++ gcvSTATUS_CHIP_NOT_READY = 11, ++ gcvSTATUS_NEED_CONVERSION = 12, ++ gcvSTATUS_SKIP = 13, ++ gcvSTATUS_DATA_TOO_LARGE = 14, ++ gcvSTATUS_INVALID_CONFIG = 15, ++ gcvSTATUS_CHANGED = 16, ++ gcvSTATUS_NOT_SUPPORT_DITHER = 17, ++ gcvSTATUS_EXECUTED = 18, ++ gcvSTATUS_TERMINATE = 19, ++ ++ gcvSTATUS_INVALID_ARGUMENT = -1, ++ gcvSTATUS_INVALID_OBJECT = -2, ++ gcvSTATUS_OUT_OF_MEMORY = -3, ++ gcvSTATUS_MEMORY_LOCKED = -4, ++ gcvSTATUS_MEMORY_UNLOCKED = -5, ++ gcvSTATUS_HEAP_CORRUPTED = -6, ++ gcvSTATUS_GENERIC_IO = -7, ++ gcvSTATUS_INVALID_ADDRESS = -8, ++ gcvSTATUS_CONTEXT_LOSSED = -9, ++ gcvSTATUS_TOO_COMPLEX = -10, ++ gcvSTATUS_BUFFER_TOO_SMALL = -11, ++ gcvSTATUS_INTERFACE_ERROR = -12, ++ gcvSTATUS_NOT_SUPPORTED = -13, ++ gcvSTATUS_MORE_DATA = -14, ++ gcvSTATUS_TIMEOUT = -15, ++ gcvSTATUS_OUT_OF_RESOURCES = -16, ++ gcvSTATUS_INVALID_DATA = -17, ++ gcvSTATUS_INVALID_MIPMAP = -18, ++ gcvSTATUS_NOT_FOUND = -19, ++ gcvSTATUS_NOT_ALIGNED = -20, ++ gcvSTATUS_INVALID_REQUEST = -21, ++ gcvSTATUS_GPU_NOT_RESPONDING = -22, ++ gcvSTATUS_TIMER_OVERFLOW = -23, ++ gcvSTATUS_VERSION_MISMATCH = -24, ++ gcvSTATUS_LOCKED = -25, ++ gcvSTATUS_INTERRUPTED = -26, ++ gcvSTATUS_DEVICE = -27, ++ gcvSTATUS_NOT_MULTI_PIPE_ALIGNED = -28, ++ ++ /* Linker errors. */ ++ gcvSTATUS_GLOBAL_TYPE_MISMATCH = -1000, ++ gcvSTATUS_TOO_MANY_ATTRIBUTES = -1001, ++ gcvSTATUS_TOO_MANY_UNIFORMS = -1002, ++ gcvSTATUS_TOO_MANY_VARYINGS = -1003, ++ gcvSTATUS_UNDECLARED_VARYING = -1004, ++ gcvSTATUS_VARYING_TYPE_MISMATCH = -1005, ++ gcvSTATUS_MISSING_MAIN = -1006, ++ gcvSTATUS_NAME_MISMATCH = -1007, ++ gcvSTATUS_INVALID_INDEX = -1008, ++ gcvSTATUS_UNIFORM_MISMATCH = -1009, ++ gcvSTATUS_UNSAT_LIB_SYMBOL = -1010, ++ gcvSTATUS_TOO_MANY_SHADERS = -1011, ++ gcvSTATUS_LINK_INVALID_SHADERS = -1012, ++ gcvSTATUS_CS_NO_WORKGROUP_SIZE = -1013, ++ gcvSTATUS_LINK_LIB_ERROR = -1014, ++ gcvSTATUS_SHADER_VERSION_MISMATCH = -1015, ++ gcvSTATUS_TOO_MANY_INSTRUCTION = -1016, ++ gcvSTATUS_SSBO_MISMATCH = -1017, ++ gcvSTATUS_TOO_MANY_OUTPUT = -1018, ++ gcvSTATUS_TOO_MANY_INPUT = -1019, ++ gcvSTATUS_NOT_SUPPORT_CL = -1020, ++ gcvSTATUS_NOT_SUPPORT_INTEGER = -1021, ++ gcvSTATUS_UNIFORM_TYPE_MISMATCH = -1022, ++ gcvSTATUS_TOO_MANY_SAMPLER = -1023, ++ ++ /* Compiler errors. */ ++ gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR = -2000, ++ gcvSTATUS_COMPILER_FE_PARSER_ERROR = -2001, ++ ++ /* Recompilation Errors */ ++ gcvSTATUS_RECOMPILER_CONVERT_UNIMPLEMENTED = -3000, ++ ++ gcvSTATUS_WARNING = -9999, ++} ++gceSTATUS; ++ ++/******************************************************************************\ ++********************************* Status Macros ******************************** ++\******************************************************************************/ ++ ++#define gcmIS_ERROR(status) (status < 0) ++#define gcmNO_ERROR(status) (status >= 0) ++#define gcmIS_SUCCESS(status) (status == gcvSTATUS_OK) ++#define gcmIS_WARNING(status) (status == gcvSTATUS_WARNING) ++ ++/******************************************************************************\ ++********************************* Field Macros ********************************* ++\******************************************************************************/ ++ ++#define __gcmSTART(reg_field) \ ++ (0 ? reg_field) ++ ++#define __gcmEND(reg_field) \ ++ (1 ? reg_field) ++ ++#define __gcmGETSIZE(reg_field) \ ++ (__gcmEND(reg_field) - __gcmSTART(reg_field) + 1) ++ ++#define __gcmALIGN(data, reg_field) \ ++ (((gctUINT32) (data)) << __gcmSTART(reg_field)) ++ ++#define __gcmMASK(reg_field) \ ++ ((gctUINT32) ((__gcmGETSIZE(reg_field) == 32) \ ++ ? ~0 \ ++ : (~(~0 << __gcmGETSIZE(reg_field))))) ++ ++/******************************************************************************* ++** ++** gcmFIELDMASK ++** ++** Get aligned field mask. ++** ++** ARGUMENTS: ++** ++** reg Name of register. ++** field Name of field within register. ++*/ ++#define gcmFIELDMASK(reg, field) \ ++( \ ++ __gcmALIGN(__gcmMASK(reg##_##field), reg##_##field) \ ++) ++ ++/******************************************************************************* ++** ++** gcmGETFIELD ++** ++** Extract the value of a field from specified data. ++** ++** ARGUMENTS: ++** ++** data Data value. ++** reg Name of register. ++** field Name of field within register. ++*/ ++#define gcmGETFIELD(data, reg, field) \ ++( \ ++ ((((gctUINT32) (data)) >> __gcmSTART(reg##_##field)) \ ++ & __gcmMASK(reg##_##field)) \ ++) ++ ++/******************************************************************************* ++** ++** gcmSETFIELD ++** ++** Set the value of a field within specified data. ++** ++** ARGUMENTS: ++** ++** data Data value. ++** reg Name of register. ++** field Name of field within register. ++** value Value for field. ++*/ ++#define gcmSETFIELD(data, reg, field, value) \ ++( \ ++ (((gctUINT32) (data)) \ ++ & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ ++ | __gcmALIGN((gctUINT32) (value) \ ++ & __gcmMASK(reg##_##field), reg##_##field) \ ++) ++ ++/******************************************************************************* ++** ++** gcmSETFIELDVALUE ++** ++** Set the value of a field within specified data with a ++** predefined value. ++** ++** ARGUMENTS: ++** ++** data Data value. ++** reg Name of register. ++** field Name of field within register. ++** value Name of the value within the field. ++*/ ++#define gcmSETFIELDVALUE(data, reg, field, value) \ ++( \ ++ (((gctUINT32) (data)) \ ++ & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ ++ | __gcmALIGN(reg##_##field##_##value \ ++ & __gcmMASK(reg##_##field), reg##_##field) \ ++) ++ ++/******************************************************************************* ++** ++** gcmGETMASKEDFIELDMASK ++** ++** Determine field mask of a masked field. ++** ++** ARGUMENTS: ++** ++** reg Name of register. ++** field Name of field within register. ++*/ ++#define gcmGETMASKEDFIELDMASK(reg, field) \ ++( \ ++ gcmSETFIELD(0, reg, field, ~0) | \ ++ gcmSETFIELD(0, reg, MASK_ ## field, ~0) \ ++) ++ ++/******************************************************************************* ++** ++** gcmSETMASKEDFIELD ++** ++** Set the value of a masked field with specified data. ++** ++** ARGUMENTS: ++** ++** reg Name of register. ++** field Name of field within register. ++** value Value for field. ++*/ ++#define gcmSETMASKEDFIELD(reg, field, value) \ ++( \ ++ gcmSETFIELD (~0, reg, field, value) & \ ++ gcmSETFIELDVALUE(~0, reg, MASK_ ## field, ENABLED) \ ++) ++ ++/******************************************************************************* ++** ++** gcmSETMASKEDFIELDVALUE ++** ++** Set the value of a masked field with specified data. ++** ++** ARGUMENTS: ++** ++** reg Name of register. ++** field Name of field within register. ++** value Value for field. ++*/ ++#define gcmSETMASKEDFIELDVALUE(reg, field, value) \ ++( \ ++ gcmSETFIELDVALUE(~0, reg, field, value) & \ ++ gcmSETFIELDVALUE(~0, reg, MASK_ ## field, ENABLED) \ ++) ++ ++/******************************************************************************* ++** ++** gcmVERIFYFIELDVALUE ++** ++** Verify if the value of a field within specified data equals a ++** predefined value. ++** ++** ARGUMENTS: ++** ++** data Data value. ++** reg Name of register. ++** field Name of field within register. ++** value Name of the value within the field. ++*/ ++#define gcmVERIFYFIELDVALUE(data, reg, field, value) \ ++( \ ++ (((gctUINT32) (data)) >> __gcmSTART(reg##_##field) & \ ++ __gcmMASK(reg##_##field)) \ ++ == \ ++ (reg##_##field##_##value & __gcmMASK(reg##_##field)) \ ++) ++ ++/******************************************************************************* ++** Bit field macros. ++*/ ++ ++#define __gcmSTARTBIT(Field) \ ++ ( 1 ? Field ) ++ ++#define __gcmBITSIZE(Field) \ ++ ( 0 ? Field ) ++ ++#define __gcmBITMASK(Field) \ ++( \ ++ (1 << __gcmBITSIZE(Field)) - 1 \ ++) ++ ++#define gcmGETBITS(Value, Type, Field) \ ++( \ ++ ( ((Type) (Value)) >> __gcmSTARTBIT(Field) ) \ ++ & \ ++ __gcmBITMASK(Field) \ ++) ++ ++#define gcmSETBITS(Value, Type, Field, NewValue) \ ++( \ ++ ( ((Type) (Value)) \ ++ & ~(__gcmBITMASK(Field) << __gcmSTARTBIT(Field)) \ ++ ) \ ++ | \ ++ ( ( ((Type) (NewValue)) \ ++ & __gcmBITMASK(Field) \ ++ ) << __gcmSTARTBIT(Field) \ ++ ) \ ++) ++ ++/******************************************************************************* ++** ++** gcmISINREGRANGE ++** ++** Verify whether the specified address is in the register range. ++** ++** ARGUMENTS: ++** ++** Address Address to be verified. ++** Name Name of a register. ++*/ ++ ++#define gcmISINREGRANGE(Address, Name) \ ++( \ ++ ((Address & (~0U << Name ## _LSB)) == (Name ## _Address >> 2)) \ ++) ++ ++/******************************************************************************\ ++******************************** Ceiling Macro ******************************** ++\******************************************************************************/ ++#define gcmCEIL(x) ((x - (gctUINT32)x) == 0 ? (gctUINT32)x : (gctUINT32)x + 1) ++ ++/******************************************************************************\ ++******************************** Min/Max Macros ******************************** ++\******************************************************************************/ ++ ++#define gcmMIN(x, y) (((x) <= (y)) ? (x) : (y)) ++#define gcmMAX(x, y) (((x) >= (y)) ? (x) : (y)) ++#define gcmCLAMP(x, min, max) (((x) < (min)) ? (min) : \ ++ ((x) > (max)) ? (max) : (x)) ++#define gcmABS(x) (((x) < 0) ? -(x) : (x)) ++#define gcmNEG(x) (((x) < 0) ? (x) : -(x)) ++ ++/******************************************************************************\ ++******************************** Bit Macro ******************************** ++\******************************************************************************/ ++#define gcmBITSET(x, y) ((x) & (y)) ++/******************************************************************************* ++** ++** gcmPTR2INT ++** ++** Convert a pointer to an integer value. ++** ++** ARGUMENTS: ++** ++** p Pointer value. ++*/ ++#define gcmPTR2INT(p) \ ++( \ ++ (gctUINTPTR_T) (p) \ ++) ++ ++#define gcmPTR2INT32(p) \ ++( \ ++ (gctUINT32)(gctUINTPTR_T) (p) \ ++) ++ ++/******************************************************************************* ++** ++** gcmINT2PTR ++** ++** Convert an integer value into a pointer. ++** ++** ARGUMENTS: ++** ++** v Integer value. ++*/ ++ ++#define gcmINT2PTR(i) \ ++( \ ++ (gctPOINTER) (gctUINTPTR_T)(i) \ ++) ++ ++/******************************************************************************* ++** ++** gcmOFFSETOF ++** ++** Compute the byte offset of a field inside a structure. ++** ++** ARGUMENTS: ++** ++** s Structure name. ++** field Field name. ++*/ ++#define gcmOFFSETOF(s, field) \ ++( \ ++ gcmPTR2INT32(& (((struct s *) 0)->field)) \ ++) ++ ++/******************************************************************************* ++** ++** gcmSWAB32 ++** ++** Return a value with all bytes in the 32 bit argument swapped. ++*/ ++#define gcmSWAB32(x) ((gctUINT32)( \ ++ (((gctUINT32)(x) & (gctUINT32)0x000000FFUL) << 24) | \ ++ (((gctUINT32)(x) & (gctUINT32)0x0000FF00UL) << 8) | \ ++ (((gctUINT32)(x) & (gctUINT32)0x00FF0000UL) >> 8) | \ ++ (((gctUINT32)(x) & (gctUINT32)0xFF000000UL) >> 24))) ++ ++/******************************************************************************* ++***** Database ****************************************************************/ ++ ++typedef struct _gcsDATABASE_COUNTERS ++{ ++ /* Number of currently allocated bytes. */ ++ gctUINT64 bytes; ++ ++ /* Maximum number of bytes allocated (memory footprint). */ ++ gctUINT64 maxBytes; ++ ++ /* Total number of bytes allocated. */ ++ gctUINT64 totalBytes; ++} ++gcsDATABASE_COUNTERS; ++ ++typedef struct _gcuDATABASE_INFO ++{ ++ /* Counters. */ ++ gcsDATABASE_COUNTERS counters; ++ ++ /* Time value. */ ++ gctUINT64 time; ++} ++gcuDATABASE_INFO; ++ ++/******************************************************************************* ++***** Frame database **********************************************************/ ++ ++/* gcsHAL_FRAME_INFO */ ++typedef struct _gcsHAL_FRAME_INFO ++{ ++ /* Current timer tick. */ ++ OUT gctUINT64 ticks; ++ ++ /* Bandwidth counters. */ ++ OUT gctUINT readBytes8[8]; ++ OUT gctUINT writeBytes8[8]; ++ ++ /* Counters. */ ++ OUT gctUINT cycles[8]; ++ OUT gctUINT idleCycles[8]; ++ OUT gctUINT mcCycles[8]; ++ OUT gctUINT readRequests[8]; ++ OUT gctUINT writeRequests[8]; ++ ++ /* 3D counters. */ ++ OUT gctUINT vertexCount; ++ OUT gctUINT primitiveCount; ++ OUT gctUINT rejectedPrimitives; ++ OUT gctUINT culledPrimitives; ++ OUT gctUINT clippedPrimitives; ++ OUT gctUINT outPrimitives; ++ OUT gctUINT inPrimitives; ++ OUT gctUINT culledQuadCount; ++ OUT gctUINT totalQuadCount; ++ OUT gctUINT quadCount; ++ OUT gctUINT totalPixelCount; ++ ++ /* PE counters. */ ++ OUT gctUINT colorKilled[8]; ++ OUT gctUINT colorDrawn[8]; ++ OUT gctUINT depthKilled[8]; ++ OUT gctUINT depthDrawn[8]; ++ ++ /* Shader counters. */ ++ OUT gctUINT shaderCycles; ++ OUT gctUINT vsInstructionCount; ++ OUT gctUINT vsTextureCount; ++ OUT gctUINT psInstructionCount; ++ OUT gctUINT psTextureCount; ++ ++ /* Texture counters. */ ++ OUT gctUINT bilinearRequests; ++ OUT gctUINT trilinearRequests; ++ OUT gctUINT txBytes8; ++ OUT gctUINT txHitCount; ++ OUT gctUINT txMissCount; ++} ++gcsHAL_FRAME_INFO; ++ ++#if gcdLINK_QUEUE_SIZE ++typedef struct _gckLINKDATA * gckLINKDATA; ++struct _gckLINKDATA ++{ ++ gctUINT32 start; ++ gctUINT32 end; ++ gctUINT32 pid; ++}; ++ ++typedef struct _gckLINKQUEUE * gckLINKQUEUE; ++struct _gckLINKQUEUE ++{ ++ struct _gckLINKDATA data[gcdLINK_QUEUE_SIZE]; ++ gctUINT32 rear; ++ gctUINT32 front; ++ gctUINT32 count; ++}; ++#endif ++ ++#define gcdENTRY_QUEUE_SIZE 256 ++typedef struct _gckENTRYDATA * gckENTRYDATA; ++struct _gckENTRYDATA ++{ ++ gctUINT32 physical; ++ gctUINT32 bytes; ++}; ++ ++typedef struct _gckENTRYQUEUE * gckENTRYQUEUE; ++struct _gckENTRYQUEUE ++{ ++ struct _gckENTRYDATA data[gcdENTRY_QUEUE_SIZE]; ++ gctUINT32 rear; ++ gctUINT32 front; ++ gctUINT32 count; ++}; ++ ++typedef enum _gceTRACEMODE ++{ ++ gcvTRACEMODE_NONE = 0, ++ gcvTRACEMODE_FULL = 1, ++ gcvTRACEMODE_LOGGER = 2, ++ gcvTRACEMODE_PRE = 3, ++ gcvTRACEMODE_POST = 4, ++ gcvTRACEMODE_SYSTRACE = 5, ++ ++} gceTRACEMODE; ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __gc_hal_types_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_version.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_version.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_version.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_version.h 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,39 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_version_h_ ++#define __gc_hal_version_h_ ++ ++#define gcvVERSION_MAJOR 5 ++ ++#define gcvVERSION_MINOR 0 ++ ++#define gcvVERSION_PATCH 11 ++ ++#define gcvVERSION_BUILD 25762 ++ ++#define gcvVERSION_STRING "5.0.11.p4.25762" ++ ++#define gcvVERSION_DATE __DATE__ ++ ++#define gcvVERSION_TIME __TIME__ ++ ++#endif /* __gc_hal_version_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_vg.h linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_vg.h +--- linux-3.14.72.orig/drivers/gpu/galcore/inc/gc_hal_vg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/inc/gc_hal_vg.h 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,863 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#ifndef __gc_hal_vg_h_ ++#define __gc_hal_vg_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++#include "gc_hal_rename.h" ++#include "gc_hal_types.h" ++#include "gc_hal_enum.h" ++#include "gc_hal_base.h" ++ ++#if gcdENABLE_VG ++ ++/* Thread routine type. */ ++typedef gctINT gctTHREADFUNCRESULT; ++typedef gctPOINTER gctTHREADFUNCPARAMETER; ++#define gctTHREADFUNCTYPE ++ ++typedef gctTHREADFUNCRESULT (gctTHREADFUNCTYPE * gctTHREADFUNC) ( ++ gctTHREADFUNCPARAMETER ThreadParameter ++ ); ++ ++ ++#if defined(gcvDEBUG) ++# undef gcvDEBUG ++#endif ++ ++#define gcdFORCE_DEBUG 0 ++#define gcdFORCE_MESSAGES 0 ++ ++ ++#if defined(DEBUG) ++# define gcvDEBUG 1 ++#else ++# define gcvDEBUG 0 ++#endif ++ ++#define _gcmERROR_RETURN(prefix, func) \ ++ status = func; \ ++ if (gcmIS_ERROR(status)) \ ++ { \ ++ prefix##PRINT_VERSION(); \ ++ prefix##TRACE(gcvLEVEL_ERROR, \ ++ #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \ ++ status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ ++ return status; \ ++ } \ ++ do { } while (gcvFALSE) ++ ++#define gcmERROR_RETURN(func) _gcmERROR_RETURN(gcm, func) ++ ++#define gcmLOG_LOCATION() ++ ++#define gcmkIS_ERROR(status) (status < 0) ++ ++#define gcmALIGNDOWN(n, align) \ ++( \ ++ (n) & ~((align) - 1) \ ++) ++ ++#define gcmIS_VALID_INDEX(Index, Array) \ ++ (((gctUINT) (Index)) < gcmCOUNTOF(Array)) ++ ++ ++#define gcmIS_NAN(x) \ ++( \ ++ ((* (gctUINT32_PTR) &(x)) & 0x7FFFFFFF) == 0x7FFFFFFF \ ++) ++ ++#define gcmLERP(v1, v2, w) \ ++ ((v1) * (w) + (v2) * (1.0f - (w))) ++ ++#define gcmINTERSECT(Start1, Start2, Length) \ ++ (gcmABS((Start1) - (Start2)) < (Length)) ++ ++/******************************************************************************* ++** ++** gcmERR_GOTO ++** ++** Prints a message and terminates the current loop on error. ++** ++** ASSUMPTIONS: ++** ++** 'status' variable of gceSTATUS type must be defined. ++** ++** ARGUMENTS: ++** ++** Function ++** Function to evaluate. ++*/ ++ ++#define gcmERR_GOTO(Function) \ ++ status = Function; \ ++ if (gcmIS_ERROR(status)) \ ++ { \ ++ gcmTRACE( \ ++ gcvLEVEL_ERROR, \ ++ "gcmERR_GOTO: status=%d @ line=%d in function %s.\n", \ ++ status, __LINE__, __FUNCTION__ \ ++ ); \ ++ goto ErrorHandler; \ ++ } ++ ++#if gcvDEBUG || gcdFORCE_MESSAGES ++# define gcmVERIFY_BOOLEAN(Expression) \ ++ gcmASSERT( \ ++ ( (Expression) == gcvFALSE ) || \ ++ ( (Expression) == gcvTRUE ) \ ++ ) ++#else ++# define gcmVERIFY_BOOLEAN(Expression) ++#endif ++ ++/******************************************************************************* ++** ++** gcmVERIFYFIELDFIT ++** ++** Verify whether the value fits in the field. ++** ++** ARGUMENTS: ++** ++** data Data value. ++** reg Name of register. ++** field Name of field within register. ++** value Value for field. ++*/ ++#define gcmVERIFYFIELDFIT(reg, field, value) \ ++ gcmASSERT( \ ++ (value) <= gcmFIELDMAX(reg, field) \ ++ ) ++/******************************************************************************* ++** ++** gcmFIELDMAX ++** ++** Get field maximum value. ++** ++** ARGUMENTS: ++** ++** reg Name of register. ++** field Name of field within register. ++*/ ++#define gcmFIELDMAX(reg, field) \ ++( \ ++ (gctUINT32) \ ++ ( \ ++ (__gcmGETSIZE(reg##_##field) == 32) \ ++ ? ~0 \ ++ : (~(~0 << __gcmGETSIZE(reg##_##field))) \ ++ ) \ ++) ++ ++ ++/* ANSI C does not have the 'f' functions, define replacements here. */ ++#define gcmSINF(x) ((gctFLOAT) sin(x)) ++#define gcmCOSF(x) ((gctFLOAT) cos(x)) ++#define gcmASINF(x) ((gctFLOAT) asin(x)) ++#define gcmACOSF(x) ((gctFLOAT) acos(x)) ++#define gcmSQRTF(x) ((gctFLOAT) sqrt(x)) ++#define gcmFABSF(x) ((gctFLOAT) fabs(x)) ++#define gcmFMODF(x, y) ((gctFLOAT) fmod((x), (y))) ++#define gcmCEILF(x) ((gctFLOAT) ceil(x)) ++#define gcmFLOORF(x) ((gctFLOAT) floor(x)) ++ ++ ++ ++/* Fixed point constants. */ ++#define gcvZERO_X ((gctFIXED_POINT) 0x00000000) ++#define gcvHALF_X ((gctFIXED_POINT) 0x00008000) ++#define gcvONE_X ((gctFIXED_POINT) 0x00010000) ++#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000) ++#define gcvTWO_X ((gctFIXED_POINT) 0x00020000) ++ ++/* Integer constants. */ ++#define gcvMAX_POS_INT ((gctINT) 0x7FFFFFFF) ++#define gcvMAX_NEG_INT ((gctINT) 0x80000000) ++ ++/* Float constants. */ ++#define gcvMAX_POS_FLOAT ((gctFLOAT) 3.4028235e+038) ++#define gcvMAX_NEG_FLOAT ((gctFLOAT) -3.4028235e+038) ++ ++/******************************************************************************\ ++***************************** Miscellaneous Macro ****************************** ++\******************************************************************************/ ++ ++#define gcmKB2BYTES(Kilobyte) \ ++( \ ++ (Kilobyte) << 10 \ ++) ++ ++#define gcmMB2BYTES(Megabyte) \ ++( \ ++ (Megabyte) << 20 \ ++) ++ ++#define gcmMAT(Matrix, Row, Column) \ ++( \ ++ (Matrix) [(Row) * 3 + (Column)] \ ++) ++ ++#define gcmMAKE2CHAR(Char1, Char2) \ ++( \ ++ ((gctUINT16) (gctUINT8) (Char1) << 0) | \ ++ ((gctUINT16) (gctUINT8) (Char2) << 8) \ ++) ++ ++#define gcmMAKE4CHAR(Char1, Char2, Char3, Char4) \ ++( \ ++ ((gctUINT32)(gctUINT8) (Char1) << 0) | \ ++ ((gctUINT32)(gctUINT8) (Char2) << 8) | \ ++ ((gctUINT32)(gctUINT8) (Char3) << 16) | \ ++ ((gctUINT32)(gctUINT8) (Char4) << 24) \ ++) ++ ++/* some platforms need to fix the physical address for HW to access*/ ++#define gcmFIXADDRESS(address) \ ++(\ ++ (address)\ ++) ++ ++#define gcmkFIXADDRESS(address) \ ++(\ ++ (address)\ ++) ++ ++/******************************************************************************\ ++****************************** Kernel Debug Macro ****************************** ++\******************************************************************************/ ++ ++/* Set signal to signaled state for specified process. */ ++gceSTATUS ++gckOS_SetSignal( ++ IN gckOS Os, ++ IN gctHANDLE Process, ++ IN gctSIGNAL Signal ++ ); ++ ++/* Return the kernel logical pointer for the given physical one. */ ++gceSTATUS ++gckOS_GetKernelLogical( ++ IN gckOS Os, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * KernelPointer ++ ); ++ ++/* Return the kernel logical pointer for the given physical one. */ ++gceSTATUS ++gckOS_GetKernelLogicalEx( ++ IN gckOS Os, ++ IN gceCORE Core, ++ IN gctUINT32 Address, ++ OUT gctPOINTER * KernelPointer ++ ); ++ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------- Semaphore Object -----------------------------*/ ++ ++/* Increment the value of a semaphore. */ ++gceSTATUS ++gckOS_IncrementSemaphore( ++ IN gckOS Os, ++ IN gctSEMAPHORE Semaphore ++ ); ++ ++/* Decrement the value of a semaphore (waiting might occur). */ ++gceSTATUS ++gckOS_DecrementSemaphore( ++ IN gckOS Os, ++ IN gctSEMAPHORE Semaphore ++ ); ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*------------------------------- Thread Object ------------------------------*/ ++ ++/* Start a thread. */ ++gceSTATUS ++gckOS_StartThread( ++ IN gckOS Os, ++ IN gctTHREADFUNC ThreadFunction, ++ IN gctPOINTER ThreadParameter, ++ OUT gctTHREAD * Thread ++ ); ++ ++/* Stop a thread. */ ++gceSTATUS ++gckOS_StopThread( ++ IN gckOS Os, ++ IN gctTHREAD Thread ++ ); ++ ++/* Verify whether the thread is still running. */ ++gceSTATUS ++gckOS_VerifyThread( ++ IN gckOS Os, ++ IN gctTHREAD Thread ++ ); ++ ++ ++/* Construct a new gckVGKERNEL object. */ ++gceSTATUS ++gckVGKERNEL_Construct( ++ IN gckOS Os, ++ IN gctPOINTER Context, ++ IN gckKERNEL inKernel, ++ OUT gckVGKERNEL * Kernel ++ ); ++ ++/* Destroy an gckVGKERNEL object. */ ++gceSTATUS ++gckVGKERNEL_Destroy( ++ IN gckVGKERNEL Kernel ++ ); ++ ++/* Allocate linear video memory. */ ++gceSTATUS ++gckVGKERNEL_AllocateLinearMemory( ++ IN gckKERNEL Kernel, ++ IN OUT gcePOOL * Pool, ++ IN gctSIZE_T Bytes, ++ IN gctUINT32 Alignment, ++ IN gceSURF_TYPE Type, ++ OUT gcuVIDMEM_NODE_PTR * Node ++ ); ++ ++/* Unmap memory. */ ++gceSTATUS ++gckKERNEL_UnmapMemory( ++ IN gckKERNEL Kernel, ++ IN gctPHYS_ADDR Physical, ++ IN gctSIZE_T Bytes, ++ IN gctPOINTER Logical ++ ); ++ ++/* Dispatch a user-level command. */ ++gceSTATUS ++gckVGKERNEL_Dispatch( ++ IN gckKERNEL Kernel, ++ IN gctBOOL FromUser, ++ IN OUT struct _gcsHAL_INTERFACE * Interface ++ ); ++ ++/* Query command buffer requirements. */ ++gceSTATUS ++gckKERNEL_QueryCommandBuffer( ++ IN gckKERNEL Kernel, ++ OUT gcsCOMMAND_BUFFER_INFO_PTR Information ++ ); ++ ++/******************************************************************************\ ++******************************* gckVGHARDWARE Object ****************************** ++\******************************************************************************/ ++ ++/* Construct a new gckVGHARDWARE object. */ ++gceSTATUS ++gckVGHARDWARE_Construct( ++ IN gckOS Os, ++ OUT gckVGHARDWARE * Hardware ++ ); ++ ++/* Destroy an gckVGHARDWARE object. */ ++gceSTATUS ++gckVGHARDWARE_Destroy( ++ IN gckVGHARDWARE Hardware ++ ); ++ ++/* Query system memory requirements. */ ++gceSTATUS ++gckVGHARDWARE_QuerySystemMemory( ++ IN gckVGHARDWARE Hardware, ++ OUT gctSIZE_T * SystemSize, ++ OUT gctUINT32 * SystemBaseAddress ++ ); ++ ++/* Build virtual address. */ ++gceSTATUS ++gckVGHARDWARE_BuildVirtualAddress( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Index, ++ IN gctUINT32 Offset, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Kickstart the command processor. */ ++gceSTATUS ++gckVGHARDWARE_Execute( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Address, ++ IN gctUINT32 Count ++ ); ++ ++/* Query the available memory. */ ++gceSTATUS ++gckVGHARDWARE_QueryMemory( ++ IN gckVGHARDWARE Hardware, ++ OUT gctSIZE_T * InternalSize, ++ OUT gctUINT32 * InternalBaseAddress, ++ OUT gctUINT32 * InternalAlignment, ++ OUT gctSIZE_T * ExternalSize, ++ OUT gctUINT32 * ExternalBaseAddress, ++ OUT gctUINT32 * ExternalAlignment, ++ OUT gctUINT32 * HorizontalTileSize, ++ OUT gctUINT32 * VerticalTileSize ++ ); ++ ++/* Query the identity of the hardware. */ ++gceSTATUS ++gckVGHARDWARE_QueryChipIdentity( ++ IN gckVGHARDWARE Hardware, ++ OUT gceCHIPMODEL* ChipModel, ++ OUT gctUINT32* ChipRevision, ++ OUT gctUINT32* ChipFeatures, ++ OUT gctUINT32* ChipMinorFeatures, ++ OUT gctUINT32* ChipMinorFeatures1 ++ ); ++ ++/* Convert an API format. */ ++gceSTATUS ++gckVGHARDWARE_ConvertFormat( ++ IN gckVGHARDWARE Hardware, ++ IN gceSURF_FORMAT Format, ++ OUT gctUINT32 * BitsPerPixel, ++ OUT gctUINT32 * BytesPerTile ++ ); ++ ++/* Split a harwdare specific address into API stuff. */ ++gceSTATUS ++gckVGHARDWARE_SplitMemory( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Address, ++ OUT gcePOOL * Pool, ++ OUT gctUINT32 * Offset ++ ); ++ ++/* Align size to tile boundary. */ ++gceSTATUS ++gckVGHARDWARE_AlignToTile( ++ IN gckVGHARDWARE Hardware, ++ IN gceSURF_TYPE Type, ++ IN OUT gctUINT32_PTR Width, ++ IN OUT gctUINT32_PTR Height ++ ); ++ ++/* Convert logical address to hardware specific address. */ ++gceSTATUS ++gckVGHARDWARE_ConvertLogical( ++ IN gckVGHARDWARE Hardware, ++ IN gctPOINTER Logical, ++ IN gctBOOL InUserSpace, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Program MMU. */ ++gceSTATUS ++gckVGHARDWARE_SetMMU( ++ IN gckVGHARDWARE Hardware, ++ IN gctPOINTER Logical ++ ); ++ ++/* Flush the MMU. */ ++gceSTATUS ++gckVGHARDWARE_FlushMMU( ++ IN gckVGHARDWARE Hardware ++ ); ++ ++/* Get idle register. */ ++gceSTATUS ++gckVGHARDWARE_GetIdle( ++ IN gckVGHARDWARE Hardware, ++ OUT gctUINT32 * Data ++ ); ++ ++/* Flush the caches. */ ++gceSTATUS ++gckVGHARDWARE_Flush( ++ IN gckVGHARDWARE Hardware, ++ IN gceKERNEL_FLUSH Flush, ++ IN gctPOINTER Logical, ++ IN OUT gctSIZE_T * Bytes ++ ); ++ ++/* Enable/disable fast clear. */ ++gceSTATUS ++gckVGHARDWARE_SetFastClear( ++ IN gckVGHARDWARE Hardware, ++ IN gctINT Enable ++ ); ++ ++gceSTATUS ++gckVGHARDWARE_ReadInterrupt( ++ IN gckVGHARDWARE Hardware, ++ OUT gctUINT32_PTR IDs ++ ); ++ ++/* Power management. */ ++gceSTATUS ++gckVGHARDWARE_SetPowerManagementState( ++ IN gckVGHARDWARE Hardware, ++ IN gceCHIPPOWERSTATE State ++ ); ++ ++gceSTATUS ++gckVGHARDWARE_QueryPowerManagementState( ++ IN gckVGHARDWARE Hardware, ++ OUT gceCHIPPOWERSTATE* State ++ ); ++ ++gceSTATUS ++gckVGHARDWARE_SetPowerManagement( ++ IN gckVGHARDWARE Hardware, ++ IN gctBOOL PowerManagement ++ ); ++ ++gceSTATUS ++gckVGHARDWARE_SetPowerOffTimeout( ++ IN gckVGHARDWARE Hardware, ++ IN gctUINT32 Timeout ++ ); ++ ++gceSTATUS ++gckVGHARDWARE_QueryPowerOffTimeout( ++ IN gckVGHARDWARE Hardware, ++ OUT gctUINT32* Timeout ++ ); ++ ++gceSTATUS ++gckVGHARDWARE_QueryIdle( ++ IN gckVGHARDWARE Hardware, ++ OUT gctBOOL_PTR IsIdle ++ ); ++/******************************************************************************\ ++*************************** Command Buffer Structures ************************** ++\******************************************************************************/ ++ ++/* Vacant command buffer marker. */ ++#define gcvVACANT_BUFFER ((gcsCOMPLETION_SIGNAL_PTR) ((gctSIZE_T)1)) ++ ++/* Command buffer header. */ ++typedef struct _gcsCMDBUFFER * gcsCMDBUFFER_PTR; ++typedef struct _gcsCMDBUFFER ++{ ++ /* Pointer to the completion signal. */ ++ gcsCOMPLETION_SIGNAL_PTR completion; ++ ++ /* The user sets this to the node of the container buffer whitin which ++ this particular command buffer resides. The kernel sets this to the ++ node of the internally allocated buffer. */ ++ gcuVIDMEM_NODE_PTR node; ++ ++ /* Command buffer hardware address. */ ++ gctUINT32 address; ++ ++ /* The offset of the buffer from the beginning of the header. */ ++ gctUINT32 bufferOffset; ++ ++ /* Size of the area allocated for the data portion of this particular ++ command buffer (headers and tail reserves are excluded). */ ++ gctUINT32 size; ++ ++ /* Offset into the buffer [0..size]; reflects exactly how much data has ++ been put into the command buffer. */ ++ gctUINT offset; ++ ++ /* The number of command units in the buffer for the hardware to ++ execute. */ ++ gctUINT32 dataCount; ++ ++ /* MANAGED BY : user HAL (gcoBUFFER object). ++ USED BY : user HAL (gcoBUFFER object). ++ Points to the immediate next allocated command buffer. */ ++ gcsCMDBUFFER_PTR nextAllocated; ++ ++ /* MANAGED BY : user layers (HAL and drivers). ++ USED BY : kernel HAL (gcoBUFFER object). ++ Points to the next subbuffer if any. A family of subbuffers are chained ++ together and are meant to be executed inseparably as a unit. Meaning ++ that context switching cannot occur while a chain of subbuffers is being ++ executed. */ ++ gcsCMDBUFFER_PTR nextSubBuffer; ++} ++gcsCMDBUFFER; ++ ++/* Command queue element. */ ++typedef struct _gcsVGCMDQUEUE ++{ ++ /* Pointer to the command buffer header. */ ++ gcsCMDBUFFER_PTR commandBuffer; ++ ++ /* Dynamic vs. static command buffer state. */ ++ gctBOOL dynamic; ++} ++gcsVGCMDQUEUE; ++ ++/* Context map entry. */ ++typedef struct _gcsVGCONTEXT_MAP ++{ ++ /* State index. */ ++ gctUINT32 index; ++ ++ /* New state value. */ ++ gctUINT32 data; ++ ++ /* Points to the next entry in the mod list. */ ++ gcsVGCONTEXT_MAP_PTR next; ++} ++gcsVGCONTEXT_MAP; ++ ++/* gcsVGCONTEXT structure that holds the current context. */ ++typedef struct _gcsVGCONTEXT ++{ ++ /* Context ID. */ ++ gctUINT64 id; ++ ++ /* State caching ebable flag. */ ++ gctBOOL stateCachingEnabled; ++ ++ /* Current pipe. */ ++ gctUINT32 currentPipe; ++ ++ /* State map/mod buffer. */ ++ gctUINT32 mapFirst; ++ gctUINT32 mapLast; ++ gcsVGCONTEXT_MAP_PTR mapContainer; ++ gcsVGCONTEXT_MAP_PTR mapPrev; ++ gcsVGCONTEXT_MAP_PTR mapCurr; ++ gcsVGCONTEXT_MAP_PTR firstPrevMap; ++ gcsVGCONTEXT_MAP_PTR firstCurrMap; ++ ++ /* Main context buffer. */ ++ gcsCMDBUFFER_PTR header; ++ gctUINT32_PTR buffer; ++ ++ /* Completion signal. */ ++ gctHANDLE process; ++ gctSIGNAL signal; ++} ++gcsVGCONTEXT; ++ ++/* User space task header. */ ++typedef struct _gcsTASK * gcsTASK_PTR; ++typedef struct _gcsTASK ++{ ++ /* Pointer to the next task for the same interrupt in user space. */ ++ gcsTASK_PTR next; ++ ++ /* Size of the task data that immediately follows the structure. */ ++ gctUINT size; ++ ++ /* Task data starts here. */ ++ /* ... */ ++} ++gcsTASK; ++ ++/* User space task master table entry. */ ++typedef struct _gcsTASK_MASTER_ENTRY * gcsTASK_MASTER_ENTRY_PTR; ++typedef struct _gcsTASK_MASTER_ENTRY ++{ ++ /* Pointers to the head and to the tail of the task chain. */ ++ gcsTASK_PTR head; ++ gcsTASK_PTR tail; ++} ++gcsTASK_MASTER_ENTRY; ++ ++/* User space task master table entry. */ ++typedef struct _gcsTASK_MASTER_TABLE ++{ ++ /* Table with one entry per block. */ ++ gcsTASK_MASTER_ENTRY table[gcvBLOCK_COUNT]; ++ ++ /* The total number of tasks sckeduled. */ ++ gctUINT count; ++ ++ /* The total size of event data in bytes. */ ++ gctUINT size; ++} ++gcsTASK_MASTER_TABLE; ++ ++/******************************************************************************\ ++***************************** gckVGINTERRUPT Object ****************************** ++\******************************************************************************/ ++ ++typedef struct _gckVGINTERRUPT * gckVGINTERRUPT; ++ ++typedef gceSTATUS (* gctINTERRUPT_HANDLER)( ++ IN gckVGKERNEL Kernel ++ ); ++ ++gceSTATUS ++gckVGINTERRUPT_Construct( ++ IN gckVGKERNEL Kernel, ++ OUT gckVGINTERRUPT * Interrupt ++ ); ++ ++gceSTATUS ++gckVGINTERRUPT_Destroy( ++ IN gckVGINTERRUPT Interrupt ++ ); ++ ++gceSTATUS ++gckVGINTERRUPT_Enable( ++ IN gckVGINTERRUPT Interrupt, ++ IN OUT gctINT32_PTR Id, ++ IN gctINTERRUPT_HANDLER Handler ++ ); ++ ++gceSTATUS ++gckVGINTERRUPT_Disable( ++ IN gckVGINTERRUPT Interrupt, ++ IN gctINT32 Id ++ ); ++ ++gceSTATUS ++gckVGINTERRUPT_Enque( ++ IN gckVGINTERRUPT Interrupt ++ ); ++ ++gceSTATUS ++gckVGINTERRUPT_DumpState( ++ IN gckVGINTERRUPT Interrupt ++ ); ++ ++ ++/******************************************************************************\ ++******************************* gckVGCOMMAND Object ******************************* ++\******************************************************************************/ ++ ++typedef struct _gckVGCOMMAND * gckVGCOMMAND; ++ ++/* Construct a new gckVGCOMMAND object. */ ++gceSTATUS ++gckVGCOMMAND_Construct( ++ IN gckVGKERNEL Kernel, ++ IN gctUINT TaskGranularity, ++ IN gctUINT QueueSize, ++ OUT gckVGCOMMAND * Command ++ ); ++ ++/* Destroy an gckVGCOMMAND object. */ ++gceSTATUS ++gckVGCOMMAND_Destroy( ++ IN gckVGCOMMAND Command ++ ); ++ ++/* Query command buffer attributes. */ ++gceSTATUS ++gckVGCOMMAND_QueryCommandBuffer( ++ IN gckVGCOMMAND Command, ++ OUT gcsCOMMAND_BUFFER_INFO_PTR Information ++ ); ++ ++/* Allocate a command queue. */ ++gceSTATUS ++gckVGCOMMAND_Allocate( ++ IN gckVGCOMMAND Command, ++ IN gctSIZE_T Size, ++ OUT gcsCMDBUFFER_PTR * CommandBuffer, ++ OUT gctPOINTER * Data ++ ); ++ ++/* Release memory held by the command queue. */ ++gceSTATUS ++gckVGCOMMAND_Free( ++ IN gckVGCOMMAND Command, ++ IN gcsCMDBUFFER_PTR CommandBuffer ++ ); ++ ++/* Schedule the command queue for execution. */ ++gceSTATUS ++gckVGCOMMAND_Execute( ++ IN gckVGCOMMAND Command, ++ IN gcsCMDBUFFER_PTR CommandBuffer ++ ); ++ ++/* Commit a buffer to the command queue. */ ++gceSTATUS ++gckVGCOMMAND_Commit( ++ IN gckVGCOMMAND Command, ++ IN gcsVGCONTEXT_PTR Context, ++ IN gcsVGCMDQUEUE_PTR Queue, ++ IN gctUINT EntryCount, ++ IN gcsTASK_MASTER_TABLE_PTR TaskTable ++ ); ++ ++/******************************************************************************\ ++********************************* gckVGMMU Object ******************************** ++\******************************************************************************/ ++ ++typedef struct _gckVGMMU * gckVGMMU; ++ ++/* Construct a new gckVGMMU object. */ ++gceSTATUS ++gckVGMMU_Construct( ++ IN gckVGKERNEL Kernel, ++ IN gctUINT32 MmuSize, ++ OUT gckVGMMU * Mmu ++ ); ++ ++/* Destroy an gckVGMMU object. */ ++gceSTATUS ++gckVGMMU_Destroy( ++ IN gckVGMMU Mmu ++ ); ++ ++/* Allocate pages inside the MMU. */ ++gceSTATUS ++gckVGMMU_AllocatePages( ++ IN gckVGMMU Mmu, ++ IN gctSIZE_T PageCount, ++ OUT gctPOINTER * PageTable, ++ OUT gctUINT32 * Address ++ ); ++ ++/* Remove a page table from the MMU. */ ++gceSTATUS ++gckVGMMU_FreePages( ++ IN gckVGMMU Mmu, ++ IN gctPOINTER PageTable, ++ IN gctSIZE_T PageCount ++ ); ++ ++/* Set the MMU page with info. */ ++gceSTATUS ++gckVGMMU_SetPage( ++ IN gckVGMMU Mmu, ++ IN gctUINT32 PageAddress, ++ IN gctUINT32 *PageEntry ++ ); ++ ++/* Flush MMU */ ++gceSTATUS ++gckVGMMU_Flush( ++ IN gckVGMMU Mmu ++ ); ++ ++#endif /* gcdENABLE_VG */ ++ ++#ifdef __cplusplus ++} /* extern "C" */ ++#endif ++ ++#endif /* __gc_hal_h_ */ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/Kbuild linux-3.14.72/drivers/gpu/galcore/Kbuild +--- linux-3.14.72.orig/drivers/gpu/galcore/Kbuild 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/Kbuild 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,233 @@ ++############################################################################## ++# ++# Copyright (C) 2005 - 2014 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. ++# ++############################################################################## ++ ++ ++# ++# Linux build file for kernel HAL driver. ++# ++ ++AQROOT := $(srctree)/drivers/gpu/galcore ++ ++include $(AQROOT)/config ++ ++KERNEL_DIR ?= $(TOOL_DIR)/kernel ++ ++# Check and include platform config. ++ifneq ($(PLATFORM),) ++ ++# Get platform config path. ++PLATFORM_CONFIG ?= $(AQROOT)/platform/$(PLATFORM).config ++ ++# Check whether it exists. ++PLATFORM_CONFIG := $(wildcard $(PLATFORM_CONFIG)) ++ ++# Include it if exists. ++ifneq ($(PLATFORM_CONFIG),) ++include $(PLATFORM_CONFIG) ++endif ++ ++endif ++ ++MODULE_NAME ?= galcore ++CUSTOMER_ALLOCATOR_OBJS ?= ++ALLOCATOR_ARRAY_H_LOCATION ?= allocator/default/ ++ ++#EXTRA_CFLAGS += -Werror ++ ++OBJS := gc_hal_kernel_device.o \ ++ gc_hal_kernel_linux.o \ ++ gc_hal_kernel_math.o \ ++ gc_hal_kernel_os.o \ ++ gc_hal_kernel_debugfs.o \ ++ gc_hal_kernel_allocator.o \ ++ ++ifneq ($(CONFIG_IOMMU_SUPPORT),) ++OBJS += gc_hal_kernel_iommu.o ++endif ++ ++OBJS += gc_hal_kernel_probe.o ++ifneq ($(PLATFORM),) ++OBJS += platform/$(PLATFORM).o ++endif ++ ++OBJS += gc_hal_kernel.o \ ++ gc_hal_kernel_command.o \ ++ gc_hal_kernel_db.o \ ++ gc_hal_kernel_debug.o \ ++ gc_hal_kernel_event.o \ ++ gc_hal_kernel_mmu.o \ ++ gc_hal_kernel_video_memory.o \ ++ gc_hal_kernel_power.o \ ++ ++OBJS += arch/gc_hal_kernel_context.o \ ++ arch/gc_hal_kernel_hardware.o ++ ++ifeq ($(VIVANTE_ENABLE_3D), 1) ++OBJS += arch/gc_hal_kernel_recorder.o ++endif ++ ++ifeq ($(VIVANTE_ENABLE_VG), 1) ++OBJS +=\ ++ gc_hal_kernel_vg.o \ ++ gc_hal_kernel_command_vg.o \ ++ gc_hal_kernel_interrupt_vg.o \ ++ gc_hal_kernel_mmu_vg.o \ ++ archvg/gc_hal_kernel_hardware_command_vg.o \ ++ archvg/gc_hal_kernel_hardware_vg.o ++endif ++ ++ifneq ($(CONFIG_SYNC),) ++EXTRA_CFLAGS += -Idrivers/staging/android ++ ++OBJS += gc_hal_kernel_sync.o ++endif ++ ++ifneq ($(CUSTOMER_ALLOCATOR_OBJS),) ++OBJS += $(CUSTOMER_ALLOCATOR_OBJS) ++endif ++ ++ifeq ($(KERNELRELEASE), ) ++ ++.PHONY: all clean install ++ ++# Define targets. ++all: ++ @make V=$(V) ARCH=$(ARCH_TYPE) -C $(KERNEL_DIR) SUBDIRS=`pwd` modules ++ ++clean: ++ @rm -rf $(OBJS) ++ @rm -rf modules.order Module.symvers ++ @find $(AQROOT) -name ".gc_*.cmd" | xargs rm -f ++ ++install: all ++ @mkdir -p $(SDK_DIR)/drivers ++ ++else ++ ++ ++EXTRA_CFLAGS += -DLINUX -DDRIVER ++ ++ifeq ($(DEBUG), 1) ++EXTRA_CFLAGS += -DDEBUG=1 ++else ++EXTRA_CFLAGS += -DDEBUG=0 ++endif ++ ++ifeq ($(NO_DMA_COHERENT), 1) ++EXTRA_CFLAGS += -DNO_DMA_COHERENT ++endif ++ ++ifneq ($(USE_PLATFORM_DRIVER), 0) ++EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=1 ++else ++EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=0 ++endif ++ ++EXTRA_CFLAGS += -DVIVANTE_PROFILER=1 ++EXTRA_CFLAGS += -DVIVANTE_PROFILER_CONTEXT=1 ++ ++ifeq ($(ENABLE_GPU_CLOCK_BY_DRIVER), 1) ++EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=1 ++else ++EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=0 ++endif ++ ++ifeq ($(FORCE_ALL_VIDEO_MEMORY_CACHED), 1) ++EXTRA_CFLAGS += -DgcdPAGED_MEMORY_CACHEABLE=1 ++else ++EXTRA_CFLAGS += -DgcdPAGED_MEMORY_CACHEABLE=0 ++endif ++ ++ifeq ($(NONPAGED_MEMORY_CACHEABLE), 1) ++EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_CACHEABLE=1 ++else ++EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_CACHEABLE=0 ++endif ++ ++ifeq ($(NONPAGED_MEMORY_BUFFERABLE), 1) ++EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_BUFFERABLE=1 ++else ++EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_BUFFERABLE=0 ++endif ++ ++ifeq ($(CACHE_FUNCTION_UNIMPLEMENTED), 1) ++EXTRA_CFLAGS += -DgcdCACHE_FUNCTION_UNIMPLEMENTED=1 ++else ++EXTRA_CFLAGS += -DgcdCACHE_FUNCTION_UNIMPLEMENTED=0 ++endif ++ ++ifeq ($(CONFIG_SMP), y) ++EXTRA_CFLAGS += -DgcdSMP=1 ++else ++EXTRA_CFLAGS += -DgcdSMP=0 ++endif ++ ++ifeq ($(VIVANTE_ENABLE_3D),0) ++EXTRA_CFLAGS += -DgcdENABLE_3D=0 ++else ++EXTRA_CFLAGS += -DgcdENABLE_3D=1 ++endif ++ ++ifeq ($(VIVANTE_ENABLE_2D),0) ++EXTRA_CFLAGS += -DgcdENABLE_2D=0 ++else ++EXTRA_CFLAGS += -DgcdENABLE_2D=1 ++endif ++ ++ifeq ($(VIVANTE_ENABLE_VG),0) ++EXTRA_CFLAGS += -DgcdENABLE_VG=0 ++else ++EXTRA_CFLAGS += -DgcdENABLE_VG=1 ++endif ++ ++ifeq ($(USE_BANK_ALIGNMENT), 1) ++ EXTRA_CFLAGS += -DgcdENABLE_BANK_ALIGNMENT=1 ++ ifneq ($(BANK_BIT_START), 0) ++ ifneq ($(BANK_BIT_END), 0) ++ EXTRA_CFLAGS += -DgcdBANK_BIT_START=$(BANK_BIT_START) ++ EXTRA_CFLAGS += -DgcdBANK_BIT_END=$(BANK_BIT_END) ++ endif ++ endif ++ ++ ifneq ($(BANK_CHANNEL_BIT), 0) ++ EXTRA_CFLAGS += -DgcdBANK_CHANNEL_BIT=$(BANK_CHANNEL_BIT) ++ endif ++endif ++ ++ifeq ($(gcdFPGA_BUILD), 1) ++EXTRA_CFLAGS += -DgcdFPGA_BUILD=1 ++else ++EXTRA_CFLAGS += -DgcdFPGA_BUILD=0 ++endif ++ ++EXTRA_CFLAGS += -I$(AQROOT) ++EXTRA_CFLAGS += -I$(AQROOT)/arch ++EXTRA_CFLAGS += -I$(AQROOT)/inc ++EXTRA_CFLAGS += -I$(AQROOT)/$(ALLOCATOR_ARRAY_H_LOCATION) ++ ++ifeq ($(VIVANTE_ENABLE_VG), 1) ++EXTRA_CFLAGS += -I$(AQROOT)/archvg ++endif ++ ++obj-$(CONFIG_VIVANTE_GALCORE) += galcore.o ++ ++galcore-objs := $(OBJS) ++ ++endif +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/Kconfig linux-3.14.72/drivers/gpu/galcore/Kconfig +--- linux-3.14.72.orig/drivers/gpu/galcore/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/Kconfig 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,8 @@ ++menu "Vivante GPU support" ++ ++config VIVANTE_GALCORE ++ tristate "Vivante GPU support" ++ ---help--- ++ Say Y to get the GPU driver support. ++ ++endmenu +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c linux-3.14.72/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c +--- linux-3.14.72.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,692 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2014 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. ++* ++*****************************************************************************/ ++ ++ ++#include "gc_hal_kernel_linux.h" ++#include "gc_hal_kernel_platform.h" ++#include "gc_hal_kernel_device.h" ++#include "gc_hal_driver.h" ++#include ++ ++#if USE_PLATFORM_DRIVER ++# include ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef CONFIG_DEVICE_THERMAL ++#include ++#define REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a); ++#define UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a); ++#else ++#define REG_THERMAL_NOTIFIER(a); ++#define UNREG_THERMAL_NOTIFIER(a); ++#endif ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++static int initgpu3DMinClock = 1; ++module_param(initgpu3DMinClock, int, 0644); ++#endif ++ ++struct platform_device *pdevice; ++ ++#ifdef CONFIG_GPU_LOW_MEMORY_KILLER ++# include ++# include ++# include ++# include ++ ++struct task_struct *lowmem_deathpending; ++ ++static int ++task_notify_func(struct notifier_block *self, unsigned long val, void *data); ++ ++static struct notifier_block task_nb = { ++ .notifier_call = task_notify_func, ++}; ++ ++static int ++task_notify_func(struct notifier_block *self, unsigned long val, void *data) ++{ ++ struct task_struct *task = data; ++ ++ if (task == lowmem_deathpending) ++ lowmem_deathpending = NULL; ++ ++ return NOTIFY_OK; ++} ++ ++extern struct task_struct *lowmem_deathpending; ++static unsigned long lowmem_deathpending_timeout; ++ ++static int force_contiguous_lowmem_shrink(IN gckKERNEL Kernel) ++{ ++ struct task_struct *p; ++ struct task_struct *selected = NULL; ++ int tasksize; ++ int ret = -1; ++ int min_adj = 0; ++ int selected_tasksize = 0; ++ int selected_oom_adj; ++ /* ++ * If we already have a death outstanding, then ++ * bail out right away; indicating to vmscan ++ * that we have nothing further to offer on ++ * this pass. ++ * ++ */ ++ if (lowmem_deathpending && ++ time_before_eq(jiffies, lowmem_deathpending_timeout)) ++ return 0; ++ selected_oom_adj = min_adj; ++ ++ rcu_read_lock(); ++ for_each_process(p) { ++ struct mm_struct *mm; ++ struct signal_struct *sig; ++ gcuDATABASE_INFO info; ++ int oom_adj; ++ ++ task_lock(p); ++ mm = p->mm; ++ sig = p->signal; ++ if (!mm || !sig) { ++ task_unlock(p); ++ continue; ++ } ++ oom_adj = sig->oom_score_adj; ++ if (oom_adj < min_adj) { ++ task_unlock(p); ++ continue; ++ } ++ ++ tasksize = 0; ++ task_unlock(p); ++ rcu_read_unlock(); ++ ++ if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_VIDEO_MEMORY, &info) == gcvSTATUS_OK){ ++ tasksize += info.counters.bytes / PAGE_SIZE; ++ } ++ if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_CONTIGUOUS, &info) == gcvSTATUS_OK){ ++ tasksize += info.counters.bytes / PAGE_SIZE; ++ } ++ ++ rcu_read_lock(); ++ ++ if (tasksize <= 0) ++ continue; ++ ++ gckOS_Print(" pid %d (%s), adj %d, size %d \n", p->pid, p->comm, oom_adj, tasksize); ++ ++ if (selected) { ++ if (oom_adj < selected_oom_adj) ++ continue; ++ if (oom_adj == selected_oom_adj && ++ tasksize <= selected_tasksize) ++ continue; ++ } ++ selected = p; ++ selected_tasksize = tasksize; ++ selected_oom_adj = oom_adj; ++ } ++ if (selected) { ++ gckOS_Print(" send sigkill to %d (%s), adj %d, size %d\n", ++ selected->pid, selected->comm, ++ selected_oom_adj, selected_tasksize); ++ lowmem_deathpending = selected; ++ lowmem_deathpending_timeout = jiffies + HZ; ++ force_sig(SIGKILL, selected); ++ ret = 0; ++ } ++ rcu_read_unlock(); ++ return ret; ++} ++ ++ ++gceSTATUS ++_ShrinkMemory( ++ IN gckPLATFORM Platform ++ ) ++{ ++ struct platform_device *pdev; ++ gckGALDEVICE galDevice; ++ gckKERNEL kernel; ++ ++ pdev = Platform->device; ++ ++ galDevice = platform_get_drvdata(pdev); ++ ++ kernel = galDevice->kernels[gcvCORE_MAJOR]; ++ ++ if (kernel != gcvNULL) ++ { ++ force_contiguous_lowmem_shrink(kernel); ++ } ++ else ++ { ++ gcmkPRINT("%s(%d) can't find kernel! ", __FUNCTION__, __LINE__); ++ } ++ ++ return gcvSTATUS_OK; ++} ++#endif ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++#ifdef CONFIG_DEVICE_THERMAL ++static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event, ++ void *dummy) ++{ ++ static gctUINT orgFscale, minFscale, maxFscale; ++ static gctBOOL critical; ++ gckHARDWARE hardware; ++ gckGALDEVICE galDevice; ++ ++ galDevice = platform_get_drvdata(pdevice); ++ if (!galDevice) ++ { ++ /* GPU is not ready, so it is meaningless to change GPU freq. */ ++ return NOTIFY_OK; ++ } ++ ++ if (!galDevice->kernels[gcvCORE_MAJOR]) ++ { ++ return NOTIFY_OK; ++ } ++ ++ hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware; ++ ++ if (!hardware) ++ { ++ return NOTIFY_OK; ++ } ++ ++ if (event > 4) { ++ critical = gcvTRUE; ++ gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale); ++ gckHARDWARE_SetFscaleValue(hardware, minFscale); ++ gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale); ++ } else if (event > 1) { ++ gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale); ++ gckHARDWARE_SetFscaleValue(hardware, maxFscale - (8 * event)); ++ } else if (orgFscale) { ++ gckHARDWARE_SetFscaleValue(hardware, orgFscale); ++ if (critical) { ++ gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale); ++ critical = gcvFALSE; ++ } ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block thermal_hot_pm_notifier = { ++ .notifier_call = thermal_hot_pm_notify, ++ }; ++#endif ++ ++static ssize_t show_gpu3DMinClock(struct device_driver *dev, char *buf) ++{ ++ gctUINT currentf,minf,maxf; ++ gckGALDEVICE galDevice; ++ ++ galDevice = platform_get_drvdata(pdevice); ++ if(galDevice->kernels[gcvCORE_MAJOR]) ++ { ++ gckHARDWARE_GetFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware, ++ ¤tf, &minf, &maxf); ++ } ++ snprintf(buf, PAGE_SIZE, "%d\n", minf); ++ return strlen(buf); ++} ++ ++static ssize_t update_gpu3DMinClock(struct device_driver *dev, const char *buf, size_t count) ++{ ++ ++ gctINT fields; ++ gctUINT MinFscaleValue; ++ gckGALDEVICE galDevice; ++ ++ galDevice = platform_get_drvdata(pdevice); ++ if(galDevice->kernels[gcvCORE_MAJOR]) ++ { ++ fields = sscanf(buf, "%d", &MinFscaleValue); ++ if (fields < 1) ++ return -EINVAL; ++ ++ gckHARDWARE_SetMinFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware,MinFscaleValue); ++ } ++ ++ return count; ++} ++ ++static DRIVER_ATTR(gpu3DMinClock, S_IRUGO | S_IWUSR, show_gpu3DMinClock, update_gpu3DMinClock); ++#endif ++ ++ ++ ++ ++static const struct of_device_id mxs_gpu_dt_ids[] = { ++ { .compatible = "fsl,imx6q-gpu", }, ++ { .compatible = "fsl,imx-gpu-subsystem", }, ++ {/* sentinel */} ++}; ++MODULE_DEVICE_TABLE(of, mxs_gpu_dt_ids); ++ ++ ++struct contiguous_mem_pool { ++ struct dma_attrs attrs; ++ dma_addr_t phys; ++ void *virt; ++ size_t size; ++}; ++ ++struct imx_priv { ++ /* Clock management.*/ ++ struct clk *clk_3d_core; ++ struct clk *clk_3d_shader; ++ struct clk *clk_3d_axi; ++ struct clk *clk_2d_core; ++ struct clk *clk_2d_axi; ++ struct clk *clk_vg_axi; ++ ++ /*Run time pm*/ ++ struct device *pmdev; ++ struct contiguous_mem_pool *pool; ++ struct reset_control *rstc[gcdMAX_GPU_COUNT]; ++}; ++ ++static struct imx_priv imxPriv; ++ ++gceSTATUS ++gckPLATFORM_AdjustParam( ++ IN gckPLATFORM Platform, ++ OUT gcsMODULE_PARAMETERS *Args ++ ) ++{ ++ struct resource* res; ++ struct platform_device* pdev = Platform->device; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr"); ++ if (res) ++ Args->baseAddress = res->start; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d"); ++ if (res) ++ Args->irqLine = res->start; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d"); ++ if (res) ++ { ++ Args->registerMemBase = res->start; ++ Args->registerMemSize = res->end - res->start + 1; ++ } ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d"); ++ if (res) ++ Args->irqLine2D = res->start; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d"); ++ if (res) ++ { ++ Args->registerMemBase2D = res->start; ++ Args->registerMemSize2D = res->end - res->start + 1; ++ } ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg"); ++ if (res) ++ Args->irqLineVG = res->start; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg"); ++ if (res) ++ { ++ Args->registerMemBaseVG = res->start; ++ Args->registerMemSizeVG = res->end - res->start + 1; ++ } ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ Args->gpu3DMinClock = initgpu3DMinClock; ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_AllocPriv( ++ IN gckPLATFORM Platform ++ ) ++{ ++ Platform->priv = &imxPriv; ++ ++#ifdef CONFIG_GPU_LOW_MEMORY_KILLER ++ task_free_register(&task_nb); ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_FreePriv( ++ IN gckPLATFORM Platform ++ ) ++{ ++#ifdef CONFIG_GPU_LOW_MEMORY_KILLER ++ task_free_unregister(&task_nb); ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_GetPower( ++ IN gckPLATFORM Platform ++ ) ++{ ++ struct device* pdev = &Platform->device->dev; ++ struct imx_priv *priv = Platform->priv; ++ struct reset_control *rstc; ++ ++#ifdef CONFIG_PM ++ /*Init runtime pm for gpu*/ ++ pm_runtime_use_autosuspend(pdev); ++ pm_runtime_set_autosuspend_delay(pdev, 200); ++ pm_runtime_enable(pdev); ++ priv->pmdev = pdev; ++#endif ++ ++ ++ rstc = devm_reset_control_get(pdev, "gpu3d"); ++ priv->rstc[gcvCORE_MAJOR] = IS_ERR(rstc) ? NULL : rstc; ++ rstc = devm_reset_control_get(pdev, "gpu2d"); ++ priv->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc; ++ rstc = devm_reset_control_get(pdev, "gpuvg"); ++ priv->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc; ++ ++ /*Initialize the clock structure*/ ++ priv->clk_3d_core = clk_get(pdev, "gpu3d_clk"); ++ if (!IS_ERR(priv->clk_3d_core)) { ++ priv->clk_3d_axi = clk_get(pdev, "gpu3d_axi_clk"); ++ priv->clk_3d_shader = clk_get(pdev, "gpu3d_shader_clk"); ++ if (IS_ERR(priv->clk_3d_shader)) { ++ clk_put(priv->clk_3d_core); ++ priv->clk_3d_core = NULL; ++ priv->clk_3d_shader = NULL; ++ gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n"); ++ } ++ } else { ++ priv->clk_3d_core = NULL; ++ gckOS_Print("galcore: clk_get gpu3d_clk failed, disable 3d!\n"); ++ } ++ ++ priv->clk_2d_core = clk_get(pdev, "gpu2d_clk"); ++ if (IS_ERR(priv->clk_2d_core)) { ++ priv->clk_2d_core = NULL; ++ gckOS_Print("galcore: clk_get 2d core clock failed, disable 2d/vg!\n"); ++ } else { ++ priv->clk_2d_axi = clk_get(pdev, "gpu2d_axi_clk"); ++ if (IS_ERR(priv->clk_2d_axi)) { ++ priv->clk_2d_axi = NULL; ++ gckOS_Print("galcore: clk_get 2d axi clock failed, disable 2d\n"); ++ } ++ ++ priv->clk_vg_axi = clk_get(pdev, "openvg_axi_clk"); ++ if (IS_ERR(priv->clk_vg_axi)) { ++ priv->clk_vg_axi = NULL; ++ gckOS_Print("galcore: clk_get vg clock failed, disable vg!\n"); ++ } ++ } ++ ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ pdevice = Platform->device; ++ REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier); ++ { ++ int ret = 0; ++ ret = driver_create_file(pdevice->dev.driver, &driver_attr_gpu3DMinClock); ++ if(ret) ++ dev_err(&pdevice->dev, "create gpu3DMinClock attr failed (%d)\n", ret); ++ } ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_PutPower( ++ IN gckPLATFORM Platform ++ ) ++{ ++ struct imx_priv *priv = Platform->priv; ++ ++ /*Disable clock*/ ++ if (priv->clk_3d_axi) { ++ clk_put(priv->clk_3d_axi); ++ priv->clk_3d_axi = NULL; ++ } ++ if (priv->clk_3d_core) { ++ clk_put(priv->clk_3d_core); ++ priv->clk_3d_core = NULL; ++ } ++ if (priv->clk_3d_shader) { ++ clk_put(priv->clk_3d_shader); ++ priv->clk_3d_shader = NULL; ++ } ++ if (priv->clk_2d_core) { ++ clk_put(priv->clk_2d_core); ++ priv->clk_2d_core = NULL; ++ } ++ if (priv->clk_2d_axi) { ++ clk_put(priv->clk_2d_axi); ++ priv->clk_2d_axi = NULL; ++ } ++ if (priv->clk_vg_axi) { ++ clk_put(priv->clk_vg_axi); ++ priv->clk_vg_axi = NULL; ++ } ++ ++#ifdef CONFIG_PM ++ if(priv->pmdev) ++ pm_runtime_disable(priv->pmdev); ++#endif ++ ++#if gcdENABLE_FSCALE_VAL_ADJUST ++ UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier); ++ ++ driver_remove_file(pdevice->dev.driver, &driver_attr_gpu3DMinClock); ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_SetPower( ++ IN gckPLATFORM Platform, ++ IN gceCORE GPU, ++ IN gctBOOL Enable ++ ) ++{ ++ struct imx_priv* priv = Platform->priv; ++ ++ if (Enable) ++ { ++#ifdef CONFIG_PM ++ pm_runtime_get_sync(priv->pmdev); ++#endif ++ } ++ else ++ { ++#ifdef CONFIG_PM ++ pm_runtime_put_sync(priv->pmdev); ++#endif ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_SetClock( ++ IN gckPLATFORM Platform, ++ IN gceCORE GPU, ++ IN gctBOOL Enable ++ ) ++{ ++ struct imx_priv* priv = Platform->priv; ++ struct clk *clk_3dcore = priv->clk_3d_core; ++ struct clk *clk_3dshader = priv->clk_3d_shader; ++ struct clk *clk_3d_axi = priv->clk_3d_axi; ++ struct clk *clk_2dcore = priv->clk_2d_core; ++ struct clk *clk_2d_axi = priv->clk_2d_axi; ++ struct clk *clk_vg_axi = priv->clk_vg_axi; ++ ++ ++ if (Enable) { ++ switch (GPU) { ++ case gcvCORE_MAJOR: ++ clk_prepare(clk_3dcore); ++ clk_enable(clk_3dcore); ++ clk_prepare(clk_3dshader); ++ clk_enable(clk_3dshader); ++ clk_prepare(clk_3d_axi); ++ clk_enable(clk_3d_axi); ++ break; ++ case gcvCORE_2D: ++ clk_prepare(clk_2dcore); ++ clk_enable(clk_2dcore); ++ clk_prepare(clk_2d_axi); ++ clk_enable(clk_2d_axi); ++ break; ++ case gcvCORE_VG: ++ clk_prepare(clk_2dcore); ++ clk_enable(clk_2dcore); ++ clk_prepare(clk_vg_axi); ++ clk_enable(clk_vg_axi); ++ break; ++ default: ++ break; ++ } ++ } else { ++ switch (GPU) { ++ case gcvCORE_MAJOR: ++ clk_disable(clk_3dshader); ++ clk_unprepare(clk_3dshader); ++ clk_disable(clk_3dcore); ++ clk_unprepare(clk_3dcore); ++ clk_disable(clk_3d_axi); ++ clk_unprepare(clk_3d_axi); ++ break; ++ case gcvCORE_2D: ++ clk_disable(clk_2dcore); ++ clk_unprepare(clk_2dcore); ++ clk_disable(clk_2d_axi); ++ clk_unprepare(clk_2d_axi); ++ break; ++ case gcvCORE_VG: ++ clk_disable(clk_2dcore); ++ clk_unprepare(clk_2dcore); ++ clk_disable(clk_vg_axi); ++ clk_unprepare(clk_vg_axi); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return gcvSTATUS_OK; ++} ++ ++#ifdef CONFIG_PM ++static int gpu_runtime_suspend(struct device *dev) ++{ ++ release_bus_freq(BUS_FREQ_HIGH); ++ return 0; ++} ++ ++static int gpu_runtime_resume(struct device *dev) ++{ ++ request_bus_freq(BUS_FREQ_HIGH); ++ return 0; ++} ++ ++static struct dev_pm_ops gpu_pm_ops; ++#endif ++ ++gceSTATUS ++_AdjustDriver( ++ IN gckPLATFORM Platform ++ ) ++{ ++ struct platform_driver * driver = Platform->driver; ++ driver->driver.of_match_table = mxs_gpu_dt_ids; ++ ++ /* Fill local structure with original value. */ ++ memcpy(&gpu_pm_ops, driver->driver.pm, sizeof(struct dev_pm_ops)); ++ ++ /* Add runtime PM callback. */ ++#ifdef CONFIG_PM ++ gpu_pm_ops.runtime_suspend = gpu_runtime_suspend; ++ gpu_pm_ops.runtime_resume = gpu_runtime_resume; ++ gpu_pm_ops.runtime_idle = NULL; ++ ++ /* Replace callbacks. */ ++ driver->driver.pm = &gpu_pm_ops; ++#endif ++ ++ return gcvSTATUS_OK; ++} ++ ++gceSTATUS ++_Reset( ++ IN gckPLATFORM Platform, ++ gceCORE GPU ++ ) ++{ ++ struct imx_priv* priv = Platform->priv; ++ struct reset_control *rstc = priv->rstc[GPU]; ++ if (rstc) ++ reset_control_reset(rstc); ++ return gcvSTATUS_OK; ++} ++ ++gcsPLATFORM_OPERATIONS platformOperations = { ++ .adjustParam = gckPLATFORM_AdjustParam, ++ .allocPriv = _AllocPriv, ++ .freePriv = _FreePriv, ++ .getPower = _GetPower, ++ .putPower = _PutPower, ++ .setPower = _SetPower, ++ .setClock = _SetClock, ++ .adjustDriver = _AdjustDriver, ++ .reset = _Reset, ++#ifdef CONFIG_GPU_LOW_MEMORY_KILLER ++ .shrinkMemory = _ShrinkMemory, ++#endif ++}; ++ ++void ++gckPLATFORM_QueryOperations( ++ IN gcsPLATFORM_OPERATIONS ** Operations ++ ) ++{ ++ *Operations = &platformOperations; ++} ++ +diff -Nur linux-3.14.72.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config linux-3.14.72/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config +--- linux-3.14.72.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,15 @@ ++EXTRA_CFLAGS += -DgcdDEFAULT_CONTIGUOUS_SIZE=134217728 ++ ++ifneq ($(CONFIG_ANDROID),) ++# build for android ++EXTRA_CFLAGS += -DgcdANDROID_NATIVE_FENCE_SYNC=3 ++ ++ifeq ($(CONFIG_SYNC),) ++$(warn CONFIG_SYNC is not set in kernel config) ++$(warn Android native fence sync needs CONFIG_SYNC) ++endif ++endif ++ ++EXTRA_CFLAGS += -DLINUX_CMA_FSL=1 ++ALLOCATOR_ARRAY_H_LOCATION := $(OS_KERNEL_DIR)/allocator/freescale ++CUSTOMER_ALLOCATOR_OBJS := $(ALLOCATOR_ARRAY_H_LOCATION)/gc_hal_kernel_allocator_cma.o +diff -Nur linux-3.14.72.orig/drivers/gpu/Makefile linux-3.14.72/drivers/gpu/Makefile +--- linux-3.14.72.orig/drivers/gpu/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/gpu/Makefile 2016-06-19 22:11:55.161149455 +0200 +@@ -1,2 +1,3 @@ + obj-y += drm/ vga/ + obj-$(CONFIG_TEGRA_HOST1X) += host1x/ ++obj-$(CONFIG_VIVANTE_GALCORE) += galcore/ +diff -Nur linux-3.14.72.orig/drivers/hwmon/Kconfig linux-3.14.72/drivers/hwmon/Kconfig +--- linux-3.14.72.orig/drivers/hwmon/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/hwmon/Kconfig 2016-06-19 22:11:55.161149455 +0200 +@@ -894,6 +894,15 @@ + This driver can also be built as a module. If so, the module + will be called max1668. + ++config SENSORS_MAX17135 ++ tristate "Maxim MAX17135 EPD temperature sensor" ++ depends on I2C ++ help ++ If you say yes here you get support for MAX17135 PMIC sensor. ++ ++ This driver can also be built as a module. If so, the module ++ will be called max17135_sensor. ++ + config SENSORS_MAX197 + tristate "Maxim MAX197 and compatibles" + help +@@ -1584,4 +1593,18 @@ + + endif # ACPI + ++config SENSORS_MAG3110 ++ tristate "Freescale MAG3110 e-compass sensor" ++ depends on I2C && SYSFS ++ help ++ If you say yes here you get support for the Freescale MAG3110 ++ e-compass sensor. ++ This driver can also be built as a module. If so, the module ++ will be called mag3110. ++ ++config MXC_MMA8451 ++ tristate "MMA8451 device driver" ++ depends on I2C ++ default y ++ + endif # HWMON +diff -Nur linux-3.14.72.orig/drivers/hwmon/mag3110.c linux-3.14.72/drivers/hwmon/mag3110.c +--- linux-3.14.72.orig/drivers/hwmon/mag3110.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/hwmon/mag3110.c 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,644 @@ ++/* ++ * ++ * 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., ++ * 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_IRQ_USED (1) ++#define MAG3110_AC_MASK (0x01) ++#define MAG3110_AC_OFFSET (0) ++#define MAG3110_DR_MODE_MASK (0x7 << 5) ++#define MAG3110_DR_MODE_OFFSET (5) ++ ++#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; ++static DEFINE_MUTEX(mag3110_lock); ++ ++/* ++ * This function do one mag3110 register read. ++ */ ++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; ++ u8 tmp_data[MAG3110_XYZ_DATA_LEN]; ++#if !MAG3110_IRQ_USED ++ int retry = 3; ++ int result; ++#endif ++ 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; ++ ++ while (i2c_smbus_read_byte_data(data->client, MAG3110_DR_STATUS)) { ++ 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) ++{ ++ int result; ++ u8 tmp_data[MAG3110_XYZ_DATA_LEN]; ++ result = i2c_smbus_read_byte_data(mag3110_pdata->client, ++ MAG3110_DR_STATUS); ++ if (!(result & MAG3110_STATUS_ZYXDR)) ++ return IRQ_NONE; ++ ++ mag3110_pdata->data_ready = 1; ++ ++ if (mag3110_pdata->active == MAG_STANDBY) ++ /* ++ * Since the mode will be changed, sometimes irq will ++ * be handled in StandBy mode because of interrupt latency. ++ * So just clear the interrutp flag via reading block data. ++ */ ++ mag3110_read_block_data(mag3110_pdata->client, ++ MAG3110_OUT_X_MSB, ++ MAG3110_XYZ_DATA_LEN, tmp_data); ++ else ++ 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; ++ } ++ ++ /* Read out MSB data to clear interrupt flag */ ++ msleep(100); ++ mag3110_read_block_data(mag3110_pdata->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; ++#if MAG3110_IRQ_USED ++ struct irq_data *irq_data = irq_get_irq_data(client->irq); ++ u32 irq_flag; ++ bool shared_irq = of_property_read_bool(of_node, "shared-interrupt"); ++#endif ++ 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; ++ } ++ ++#if MAG3110_IRQ_USED ++ irq_flag = irqd_get_trigger_type(irq_data); ++ irq_flag |= IRQF_ONESHOT; ++ if (shared_irq) ++ irq_flag |= IRQF_SHARED; ++ ret = request_threaded_irq(client->irq, NULL, mag3110_irq_handler, ++ irq_flag, 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.72.orig/drivers/hwmon/Makefile linux-3.14.72/drivers/hwmon/Makefile +--- linux-3.14.72.orig/drivers/hwmon/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/hwmon/Makefile 2016-06-19 22:11:55.161149455 +0200 +@@ -103,6 +103,7 @@ + obj-$(CONFIG_SENSORS_MAX16065) += max16065.o + obj-$(CONFIG_SENSORS_MAX1619) += max1619.o + obj-$(CONFIG_SENSORS_MAX1668) += max1668.o ++obj-$(CONFIG_SENSORS_MAX17135) += max17135-hwmon.o + obj-$(CONFIG_SENSORS_MAX197) += max197.o + obj-$(CONFIG_SENSORS_MAX6639) += max6639.o + obj-$(CONFIG_SENSORS_MAX6642) += max6642.o +@@ -142,6 +143,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.72.orig/drivers/hwmon/max17135-hwmon.c linux-3.14.72/drivers/hwmon/max17135-hwmon.c +--- linux-3.14.72.orig/drivers/hwmon/max17135-hwmon.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/hwmon/max17135-hwmon.c 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,176 @@ ++/* ++ * Copyright (C) 2010-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 ++ * ++ */ ++/* ++ * max17135.c ++ * ++ * Based on the MAX1619 driver. ++ * Copyright (C) 2003-2004 Alexey Fisher ++ * Jean Delvare ++ * ++ * The MAX17135 is a sensor chip made by Maxim. ++ * It reports up to two temperatures (its own plus up to ++ * one external one). ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Conversions ++ */ ++static int temp_from_reg(int val) ++{ ++ return val >> 8; ++} ++ ++/* ++ * Functions declaration ++ */ ++static int max17135_sensor_probe(struct platform_device *pdev); ++static int max17135_sensor_remove(struct platform_device *pdev); ++ ++static const struct platform_device_id max17135_sns_id[] = { ++ { "max17135-sns", 0}, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(platform, max17135_sns_id); ++ ++/* ++ * Driver data (common to all clients) ++ */ ++static struct platform_driver max17135_sensor_driver = { ++ .probe = max17135_sensor_probe, ++ .remove = max17135_sensor_remove, ++ .id_table = max17135_sns_id, ++ .driver = { ++ .name = "max17135_sensor", ++ }, ++}; ++ ++/* ++ * Client data (each client gets its own) ++ */ ++struct max17135_data { ++ struct device *hwmon_dev; ++}; ++ ++/* ++ * Sysfs stuff ++ */ ++static ssize_t show_temp_input1(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned int reg_val; ++ max17135_reg_read(REG_MAX17135_INT_TEMP, ®_val); ++ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val)); ++} ++ ++static ssize_t show_temp_input2(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned int reg_val; ++ max17135_reg_read(REG_MAX17135_EXT_TEMP, ®_val); ++ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val)); ++} ++ ++static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); ++static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); ++ ++static struct attribute *max17135_attributes[] = { ++ &dev_attr_temp1_input.attr, ++ &dev_attr_temp2_input.attr, ++ NULL ++}; ++ ++static const struct attribute_group max17135_group = { ++ .attrs = max17135_attributes, ++}; ++ ++/* ++ * Real code ++ */ ++static int max17135_sensor_probe(struct platform_device *pdev) ++{ ++ struct max17135_data *data; ++ int err; ++ ++ data = kzalloc(sizeof(struct max17135_data), GFP_KERNEL); ++ if (!data) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ /* Register sysfs hooks */ ++ err = sysfs_create_group(&pdev->dev.kobj, &max17135_group); ++ if (err) ++ goto exit_free; ++ ++ data->hwmon_dev = hwmon_device_register(&pdev->dev); ++ if (IS_ERR(data->hwmon_dev)) { ++ err = PTR_ERR(data->hwmon_dev); ++ goto exit_remove_files; ++ } ++ ++ platform_set_drvdata(pdev, data); ++ ++ return 0; ++ ++exit_remove_files: ++ sysfs_remove_group(&pdev->dev.kobj, &max17135_group); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int max17135_sensor_remove(struct platform_device *pdev) ++{ ++ struct max17135_data *data = platform_get_drvdata(pdev); ++ ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&pdev->dev.kobj, &max17135_group); ++ ++ kfree(data); ++ return 0; ++} ++ ++static int __init sensors_max17135_init(void) ++{ ++ return platform_driver_register(&max17135_sensor_driver); ++} ++module_init(sensors_max17135_init); ++ ++static void __exit sensors_max17135_exit(void) ++{ ++ platform_driver_unregister(&max17135_sensor_driver); ++} ++module_exit(sensors_max17135_exit); ++ ++MODULE_DESCRIPTION("MAX17135 sensor driver"); ++MODULE_LICENSE("GPL"); ++ +diff -Nur linux-3.14.72.orig/drivers/hwmon/mxc_mma8451.c linux-3.14.72/drivers/hwmon/mxc_mma8451.c +--- linux-3.14.72.orig/drivers/hwmon/mxc_mma8451.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/hwmon/mxc_mma8451.c 2016-06-19 22:11:55.161149455 +0200 +@@ -0,0 +1,730 @@ ++/* ++ * mma8451.c - Linux kernel modules for 3-Axis Orientation/Motion ++ * Detection Sensor ++ * ++ * 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., 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 FXOS8700_ID 0xC7 ++ ++#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, ++ ++ FXOS8700_M_DR_STATUS, ++ FXOS8700_M_OUT_X_MSB, ++ FXOS8700_M_OUT_X_LSB, ++ FXOS8700_M_OUT_Y_MSB, ++ FXOS8700_M_OUT_Y_LSB, ++ FXOS8700_M_OUT_Z_MSB, ++ FXOS8700_M_OUT_Z_LSB, ++ ++ FXOS8700_M_CTRL_REG1 = 0x5B, ++ ++ 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, ++}; ++ ++enum { ++ FXOS_ACCEL_ONLY = 0, ++ FXOS_MAG_ONLY, ++ FXOS_NONE, ++ FXOS_HYBRID, ++}; ++ ++/* mma8451 status */ ++struct mma8451_status { ++ u8 mode; ++ u8 ctl_reg1; ++ int active; ++ int position; ++ int hybrid_mode; ++}; ++ ++static struct mma8451_status mma_status; ++static struct input_polled_dev *mma8451_idev; ++static struct input_polled_dev *fxos8700_m_idev; ++static struct device *hwmon_dev; ++static struct i2c_client *mma8451_i2c_client; ++static int client_id; ++ ++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; ++ ++ if (client_id == FXOS8700_ID) { ++ mma_status.hybrid_mode = FXOS_HYBRID; ++ result = i2c_smbus_write_byte_data(client, FXOS8700_M_CTRL_REG1, FXOS_HYBRID); ++ if (result < 0) ++ goto out; ++ } ++ ++ mma_status.mode = mode; ++ 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(struct input_polled_dev *idev, ++ short *x, short *y, short *z) ++{ ++ u8 tmp_data[MMA8451_BUF_SIZE]; ++ char reg = (idev == mma8451_idev)?MMA8451_OUT_X_MSB:FXOS8700_M_OUT_X_MSB; ++ int ret; ++ ++ ret = i2c_smbus_read_i2c_block_data(mma8451_i2c_client, ++ reg, 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(struct input_polled_dev *idev) ++{ ++ short x, y, z; ++ int result; ++ int retry = 3; ++ char reg = (idev == mma8451_idev)?MMA8451_STATUS:FXOS8700_M_DR_STATUS; ++ ++ 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, reg); ++ retry--; ++ msleep(1); ++ } while (!(result & MMA8451_STATUS_ZYXDR) && retry > 0); ++ if (retry == 0) ++ goto out; ++ if (mma8451_read_data(idev, &x, &y, &z) != 0) ++ goto out; ++ mma8451_adjust_position(&x, &y, &z); ++ input_report_abs(idev->input, ABS_X, x); ++ input_report_abs(idev->input, ABS_Y, y); ++ input_report_abs(idev->input, ABS_Z, z); ++ input_sync(idev->input); ++out: ++ mutex_unlock(&mma8451_lock); ++} ++ ++static void mma8451_dev_poll(struct input_polled_dev *dev) ++{ ++ report_abs(dev); ++} ++ ++static ssize_t mma8451_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct input_polled_dev *idev = dev_get_drvdata(dev); ++ struct i2c_client *client; ++ u8 val; ++ int enable = 0; ++ ++ 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) { ++ if (client_id == FXOS8700_ID) { ++ if (mma_status.hybrid_mode == FXOS_HYBRID) ++ enable = 1; ++ else if (mma_status.hybrid_mode == FXOS_ACCEL_ONLY ++ && idev == mma8451_idev) ++ enable = 1; ++ else if (mma_status.hybrid_mode == FXOS_MAG_ONLY) ++ enable = 1; ++ } ++ else ++ enable = 1; ++ } ++ 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 input_polled_dev *idev = dev_get_drvdata(dev); ++ 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 (client_id == FXOS8700_ID) { ++ val = mma_status.hybrid_mode; ++ if (idev == mma8451_idev) { ++ if (enable) { ++ if (val == FXOS_NONE) ++ val = FXOS_ACCEL_ONLY; ++ else if (val == FXOS_MAG_ONLY) ++ val = FXOS_HYBRID; ++ } else { ++ if (val == FXOS_HYBRID) ++ val = FXOS_MAG_ONLY; ++ else if (val == FXOS_ACCEL_ONLY) ++ val = FXOS_NONE; ++ } ++ } else { ++ if (enable) { ++ if (val == FXOS_NONE) ++ val = FXOS_MAG_ONLY; ++ else if (val == FXOS_ACCEL_ONLY) ++ val = FXOS_HYBRID; ++ } else { ++ if (val == FXOS_HYBRID) ++ val = FXOS_ACCEL_ONLY; ++ else if (val == FXOS_MAG_ONLY) ++ val = FXOS_NONE; ++ } ++ } ++/* ++ if (val != FXOS_NONE) { ++ ret = i2c_smbus_write_byte_data(client, ++ FXOS8700_M_CTRL_REG1, val & 0x03); ++ } ++*/ ++ mma_status.hybrid_mode = val; ++ if (mma_status.hybrid_mode == FXOS_NONE) ++ enable = 0; ++ else ++ enable = 1; ++ } ++ 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; ++ 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 && client_id != FXOS8700_ID) { ++ dev_err(&client->dev, ++ "read chip ID 0x%x is not equal to 0x%x,0x%x,0x%x!\n", ++ result, MMA8451_ID, MMA8452_ID, FXOS8700_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; ++ } ++ ++ /* create a polled input device for accelerometer */ ++ mma8451_idev = input_allocate_polled_device(); ++ if (!mma8451_idev) { ++ result = -ENOMEM; ++ dev_err(&client->dev, "alloc poll device failed!\n"); ++ goto err_register_polled_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; ++ if (client_id == FXOS8700_ID) ++ idev->name = "mma845x_a"; ++ else ++ 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; ++ } ++ ++ /* create a polled input device for magnetometer */ ++ if (client_id == FXOS8700_ID) { ++ fxos8700_m_idev = input_allocate_polled_device(); ++ if (!fxos8700_m_idev) { ++ result = -ENOMEM; ++ dev_err(&client->dev, "alloc poll device failed!\n"); ++ goto err_alloc_poll_device; ++ } ++ fxos8700_m_idev->poll = mma8451_dev_poll; ++ fxos8700_m_idev->poll_interval = POLL_INTERVAL; ++ fxos8700_m_idev->poll_interval_min = POLL_INTERVAL_MIN; ++ fxos8700_m_idev->poll_interval_max = POLL_INTERVAL_MAX; ++ idev = fxos8700_m_idev->input; ++ idev->name = "fxos8700_m"; ++ 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(fxos8700_m_idev); ++ if (result) { ++ dev_err(&client->dev, "register poll device failed!\n"); ++ goto err_register_polled_device1; ++ } ++ 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_create_sysfs1; ++ } ++ } ++ ++ result = of_property_read_u32(of_node, "position", &pos); ++ if (result) ++ pos = DEFAULT_POSITION; ++ mma_status.position = (int)pos; ++ ++ return 0; ++ ++err_create_sysfs1: ++ input_unregister_polled_device(fxos8700_m_idev); ++err_register_polled_device1: ++ input_free_polled_device(fxos8700_m_idev); ++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); ++ ++ if (client_id == FXOS8700_ID) { ++ input_unregister_polled_device(fxos8700_m_idev); ++ input_free_polled_device(fxos8700_m_idev); ++ } ++ input_unregister_polled_device(mma8451_idev); ++ input_free_polled_device(mma8451_idev); ++ 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.72.orig/drivers/i2c/busses/i2c-imx.c linux-3.14.72/drivers/i2c/busses/i2c-imx.c +--- linux-3.14.72.orig/drivers/i2c/busses/i2c-imx.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/i2c/busses/i2c-imx.c 2016-06-19 22:11:55.161149455 +0200 +@@ -261,15 +261,34 @@ + { + unsigned long orig_jiffies = jiffies; + unsigned int temp; ++ int successes = 0; + + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); + + while (1) { + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); +- if (for_busy && (temp & I2SR_IBB)) +- break; +- if (!for_busy && !(temp & I2SR_IBB)) +- break; ++ ++ /* check for arbitration lost */ ++ if (temp & I2SR_IAL) { ++ temp &= ~I2SR_IAL; ++ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); ++ return -EAGAIN; ++ } ++ ++ if (for_busy) { ++ if (temp & I2SR_IBB) { ++ if (successes++ > 2) ++ break; ++ } else ++ successes = 0 ; ++ } ++ if (!for_busy) { ++ if (!(temp & I2SR_IBB)) { ++ if (successes++ > 2) ++ break; ++ } else ++ successes = 0 ; ++ } + if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { + dev_dbg(&i2c_imx->adapter.dev, + "<%s> I2C bus is busy\n", __func__); +@@ -458,7 +477,7 @@ + return 0; + } + +-static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) ++static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) + { + int i, result; + unsigned int temp; +@@ -494,15 +513,30 @@ + if (result) + return result; + if (i == (msgs->len - 1)) { +- /* It must generate STOP before read I2DR to prevent +- controller from generating another clock cycle */ +- dev_dbg(&i2c_imx->adapter.dev, +- "<%s> clear MSTA\n", __func__); +- temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); +- temp &= ~(I2CR_MSTA | I2CR_MTX); +- imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); +- i2c_imx_bus_busy(i2c_imx, 0); +- i2c_imx->stopped = 1; ++ if (is_lastmsg) { ++ /* ++ * It must generate STOP before read I2DR to prevent ++ * controller from generating another clock cycle ++ */ ++ dev_dbg(&i2c_imx->adapter.dev, ++ "<%s> clear MSTA\n", __func__); ++ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); ++ temp &= ~(I2CR_MSTA | I2CR_MTX); ++ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); ++ i2c_imx_bus_busy(i2c_imx, 0); ++ i2c_imx->stopped = 1; ++ } else { ++ /* ++ * For i2c master receiver repeat restart operation like: ++ * read -> repeat MSTA -> read/write ++ * The controller must set MTX before read the last byte in ++ * the first read operation, otherwise the first read cost ++ * one extra clock cycle. ++ */ ++ temp = readb(i2c_imx->base + IMX_I2C_I2CR); ++ temp |= I2CR_MTX; ++ writeb(temp, i2c_imx->base + IMX_I2C_I2CR); ++ } + } else if (i == (msgs->len - 2)) { + dev_dbg(&i2c_imx->adapter.dev, + "<%s> set TXAK\n", __func__); +@@ -523,6 +557,7 @@ + { + unsigned int i, temp; + int result; ++ bool is_lastmsg = false; + struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); + + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); +@@ -534,6 +569,9 @@ + + /* read/write data */ + for (i = 0; i < num; i++) { ++ if (i == num - 1) ++ is_lastmsg = true; ++ + if (i) { + dev_dbg(&i2c_imx->adapter.dev, + "<%s> repeated start\n", __func__); +@@ -564,7 +602,7 @@ + (temp & I2SR_RXAK ? 1 : 0)); + #endif + if (msgs[i].flags & I2C_M_RD) +- result = i2c_imx_read(i2c_imx, &msgs[i]); ++ result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); + else + result = i2c_imx_write(i2c_imx, &msgs[i]); + if (result) +@@ -634,6 +672,8 @@ + i2c_imx->adapter.algo = &i2c_imx_algo; + i2c_imx->adapter.dev.parent = &pdev->dev; + i2c_imx->adapter.nr = pdev->id; ++ i2c_imx->adapter.retries = 500; ++ i2c_imx->adapter.timeout = msecs_to_jiffies(2000); + i2c_imx->adapter.dev.of_node = pdev->dev.of_node; + i2c_imx->base = base; + +diff -Nur linux-3.14.72.orig/drivers/i2c/i2c-core.c linux-3.14.72/drivers/i2c/i2c-core.c +--- linux-3.14.72.orig/drivers/i2c/i2c-core.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/i2c/i2c-core.c 2016-06-19 22:11:55.161149455 +0200 +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -262,6 +263,10 @@ + client->flags & I2C_CLIENT_WAKE); + dev_dbg(dev, "probe\n"); + ++ status = of_clk_set_defaults(dev->of_node, false); ++ if (status < 0) ++ return status; ++ + acpi_dev_pm_attach(&client->dev, true); + status = driver->probe(client, i2c_match_id(driver->id_table, client)); + if (status) +diff -Nur linux-3.14.72.orig/drivers/iio/adc/Kconfig linux-3.14.72/drivers/iio/adc/Kconfig +--- linux-3.14.72.orig/drivers/iio/adc/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/iio/adc/Kconfig 2016-06-19 22:11:55.161149455 +0200 +@@ -196,6 +196,15 @@ + + This driver can also be built as a module. If so, the module will be + called twl6030-gpadc. ++config VF610_ADC ++ tristate "Freescale vf610 ADC driver" ++ depends on OF ++ help ++ Say yes here to support for Vybrid board analog-to-digital converter. ++ Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX. ++ ++ This driver can also be built as a module. If so, the module will be ++ called vf610_adc. + + config VIPERBOARD_ADC + tristate "Viperboard ADC support" +diff -Nur linux-3.14.72.orig/drivers/iio/adc/Makefile linux-3.14.72/drivers/iio/adc/Makefile +--- linux-3.14.72.orig/drivers/iio/adc/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/iio/adc/Makefile 2016-06-19 22:11:55.161149455 +0200 +@@ -21,4 +21,5 @@ + obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o + obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o + obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o ++obj-$(CONFIG_VF610_ADC) += vf610_adc.o + obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o +diff -Nur linux-3.14.72.orig/drivers/iio/adc/vf610_adc.c linux-3.14.72/drivers/iio/adc/vf610_adc.c +--- linux-3.14.72.orig/drivers/iio/adc/vf610_adc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/iio/adc/vf610_adc.c 2016-06-19 22:11:55.165149193 +0200 +@@ -0,0 +1,717 @@ ++/* ++ * Freescale Vybrid vf610 ADC driver ++ * ++ * Copyright 2013-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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* This will be the driver name the kernel reports */ ++#define DRIVER_NAME "vf610-adc" ++ ++/* Vybrid/IMX ADC registers */ ++#define VF610_REG_ADC_HC0 0x00 ++#define VF610_REG_ADC_HC1 0x04 ++#define VF610_REG_ADC_HS 0x08 ++#define VF610_REG_ADC_R0 0x0c ++#define VF610_REG_ADC_R1 0x10 ++#define VF610_REG_ADC_CFG 0x14 ++#define VF610_REG_ADC_GC 0x18 ++#define VF610_REG_ADC_GS 0x1c ++#define VF610_REG_ADC_CV 0x20 ++#define VF610_REG_ADC_OFS 0x24 ++#define VF610_REG_ADC_CAL 0x28 ++#define VF610_REG_ADC_PCTL 0x30 ++ ++/* Configuration register field define */ ++#define VF610_ADC_MODE_BIT8 0x00 ++#define VF610_ADC_MODE_BIT10 0x04 ++#define VF610_ADC_MODE_BIT12 0x08 ++#define VF610_ADC_MODE_MASK 0x0c ++#define VF610_ADC_BUSCLK2_SEL 0x01 ++#define VF610_ADC_ALTCLK_SEL 0x02 ++#define VF610_ADC_ADACK_SEL 0x03 ++#define VF610_ADC_ADCCLK_MASK 0x03 ++#define VF610_ADC_CLK_DIV2 0x20 ++#define VF610_ADC_CLK_DIV4 0x40 ++#define VF610_ADC_CLK_DIV8 0x60 ++#define VF610_ADC_CLK_MASK 0x60 ++#define VF610_ADC_ADLSMP_LONG 0x10 ++#define VF610_ADC_ADSTS_MASK 0x300 ++#define VF610_ADC_ADLPC_EN 0x80 ++#define VF610_ADC_ADHSC_EN 0x400 ++#define VF610_ADC_REFSEL_VALT 0x100 ++#define VF610_ADC_REFSEL_VBG 0x1000 ++#define VF610_ADC_ADTRG_HARD 0x2000 ++#define VF610_ADC_AVGS_8 0x4000 ++#define VF610_ADC_AVGS_16 0x8000 ++#define VF610_ADC_AVGS_32 0xC000 ++#define VF610_ADC_AVGS_MASK 0xC000 ++#define VF610_ADC_OVWREN 0x10000 ++ ++/* General control register field define */ ++#define VF610_ADC_ADACKEN 0x1 ++#define VF610_ADC_DMAEN 0x2 ++#define VF610_ADC_ACREN 0x4 ++#define VF610_ADC_ACFGT 0x8 ++#define VF610_ADC_ACFE 0x10 ++#define VF610_ADC_AVGEN 0x20 ++#define VF610_ADC_ADCON 0x40 ++#define VF610_ADC_CAL 0x80 ++ ++/* Other field define */ ++#define VF610_ADC_ADCHC(x) ((x) & 0xF) ++#define VF610_ADC_AIEN (0x1 << 7) ++#define VF610_ADC_CONV_DISABLE 0x1F ++#define VF610_ADC_HS_COCO0 0x1 ++#define VF610_ADC_CALF 0x2 ++#define VF610_ADC_TIMEOUT msecs_to_jiffies(100) ++ ++enum clk_sel { ++ VF610_ADCIOC_BUSCLK_SET, ++ VF610_ADCIOC_ALTCLK_SET, ++ VF610_ADCIOC_ADACK_SET, ++}; ++ ++enum vol_ref { ++ VF610_ADCIOC_VR_VREF_SET, ++ VF610_ADCIOC_VR_VALT_SET, ++ VF610_ADCIOC_VR_VBG_SET, ++}; ++ ++enum average_sel { ++ VF610_ADC_SAMPLE_1, ++ VF610_ADC_SAMPLE_4, ++ VF610_ADC_SAMPLE_8, ++ VF610_ADC_SAMPLE_16, ++ VF610_ADC_SAMPLE_32, ++}; ++ ++struct vf610_adc_feature { ++ enum clk_sel clk_sel; ++ enum vol_ref vol_ref; ++ ++ int clk_div; ++ int sample_rate; ++ int res_mode; ++ ++ bool lpm; ++ bool calibration; ++ bool ovwren; ++}; ++ ++struct vf610_adc { ++ struct device *dev; ++ void __iomem *regs; ++ struct clk *clk; ++ ++ u32 vref_uv; ++ u32 value; ++ struct regulator *vref; ++ struct vf610_adc_feature adc_feature; ++ ++ struct completion completion; ++}; ++ ++#define VF610_ADC_CHAN(_idx, _chan_type) { \ ++ .type = (_chan_type), \ ++ .indexed = 1, \ ++ .channel = (_idx), \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ ++} ++ ++static const struct iio_chan_spec vf610_adc_iio_channels[] = { ++ VF610_ADC_CHAN(0, IIO_VOLTAGE), ++ VF610_ADC_CHAN(1, IIO_VOLTAGE), ++ VF610_ADC_CHAN(2, IIO_VOLTAGE), ++ VF610_ADC_CHAN(3, IIO_VOLTAGE), ++ VF610_ADC_CHAN(4, IIO_VOLTAGE), ++ VF610_ADC_CHAN(5, IIO_VOLTAGE), ++ VF610_ADC_CHAN(6, IIO_VOLTAGE), ++ VF610_ADC_CHAN(7, IIO_VOLTAGE), ++ VF610_ADC_CHAN(8, IIO_VOLTAGE), ++ VF610_ADC_CHAN(9, IIO_VOLTAGE), ++ VF610_ADC_CHAN(10, IIO_VOLTAGE), ++ VF610_ADC_CHAN(11, IIO_VOLTAGE), ++ VF610_ADC_CHAN(12, IIO_VOLTAGE), ++ VF610_ADC_CHAN(13, IIO_VOLTAGE), ++ VF610_ADC_CHAN(14, IIO_VOLTAGE), ++ VF610_ADC_CHAN(15, IIO_VOLTAGE), ++ /* sentinel */ ++}; ++ ++/* ++ * ADC sample frequency, unit is ADCK cycles. ++ * ADC clk source is ipg clock, which is the same as bus clock. ++ * ++ * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder) ++ * SFCAdder: fixed to 6 ADCK cycles ++ * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. ++ * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode ++ * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles ++ * ++ * By default, enable 12 bit resolution mode, clock source ++ * set to ipg clock, So get below frequency group: ++ */ ++static const u32 vf610_sample_freq_avail[5] = ++{1941176, 559332, 286957, 145374, 73171}; ++ ++static inline void vf610_adc_cfg_init(struct vf610_adc *info) ++{ ++ /* set default Configuration for ADC controller */ ++ info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET; ++ info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET; ++ ++ info->adc_feature.calibration = true; ++ info->adc_feature.ovwren = true; ++ ++ info->adc_feature.clk_div = 1; ++ info->adc_feature.res_mode = 12; ++ info->adc_feature.sample_rate = 1; ++ info->adc_feature.lpm = true; ++} ++ ++static void vf610_adc_cfg_post_set(struct vf610_adc *info) ++{ ++ struct vf610_adc_feature *adc_feature = &info->adc_feature; ++ int cfg_data = 0; ++ int gc_data = 0; ++ ++ switch (adc_feature->clk_sel) { ++ case VF610_ADCIOC_ALTCLK_SET: ++ cfg_data |= VF610_ADC_ALTCLK_SEL; ++ break; ++ case VF610_ADCIOC_ADACK_SET: ++ cfg_data |= VF610_ADC_ADACK_SEL; ++ break; ++ default: ++ break; ++ } ++ ++ /* low power set for calibration */ ++ cfg_data |= VF610_ADC_ADLPC_EN; ++ ++ /* enable high speed for calibration */ ++ cfg_data |= VF610_ADC_ADHSC_EN; ++ ++ /* voltage reference */ ++ switch (adc_feature->vol_ref) { ++ case VF610_ADCIOC_VR_VREF_SET: ++ break; ++ case VF610_ADCIOC_VR_VALT_SET: ++ cfg_data |= VF610_ADC_REFSEL_VALT; ++ break; ++ case VF610_ADCIOC_VR_VBG_SET: ++ cfg_data |= VF610_ADC_REFSEL_VBG; ++ break; ++ default: ++ dev_err(info->dev, "error voltage reference\n"); ++ } ++ ++ /* data overwrite enable */ ++ if (adc_feature->ovwren) ++ cfg_data |= VF610_ADC_OVWREN; ++ ++ writel(cfg_data, info->regs + VF610_REG_ADC_CFG); ++ writel(gc_data, info->regs + VF610_REG_ADC_GC); ++} ++ ++static void vf610_adc_calibration(struct vf610_adc *info) ++{ ++ int adc_gc, hc_cfg; ++ int timeout; ++ ++ if (!info->adc_feature.calibration) ++ return; ++ ++ /* enable calibration interrupt */ ++ hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE; ++ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); ++ ++ adc_gc = readl(info->regs + VF610_REG_ADC_GC); ++ writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC); ++ ++ timeout = wait_for_completion_timeout ++ (&info->completion, VF610_ADC_TIMEOUT); ++ if (timeout == 0) ++ dev_err(info->dev, "Timeout for adc calibration\n"); ++ ++ adc_gc = readl(info->regs + VF610_REG_ADC_GS); ++ if (adc_gc & VF610_ADC_CALF) ++ dev_err(info->dev, "ADC calibration failed\n"); ++ ++ info->adc_feature.calibration = false; ++} ++ ++static void vf610_adc_cfg_set(struct vf610_adc *info) ++{ ++ struct vf610_adc_feature *adc_feature = &(info->adc_feature); ++ int cfg_data; ++ ++ cfg_data = readl(info->regs + VF610_REG_ADC_CFG); ++ ++ /* low power configuration */ ++ cfg_data &= ~VF610_ADC_ADLPC_EN; ++ if (adc_feature->lpm) ++ cfg_data |= VF610_ADC_ADLPC_EN; ++ ++ /* disable high speed */ ++ cfg_data &= ~VF610_ADC_ADHSC_EN; ++ ++ writel(cfg_data, info->regs + VF610_REG_ADC_CFG); ++} ++ ++static void vf610_adc_sample_set(struct vf610_adc *info) ++{ ++ struct vf610_adc_feature *adc_feature = &(info->adc_feature); ++ int cfg_data, gc_data; ++ ++ cfg_data = readl(info->regs + VF610_REG_ADC_CFG); ++ gc_data = readl(info->regs + VF610_REG_ADC_GC); ++ ++ /* resolution mode */ ++ cfg_data &= ~VF610_ADC_MODE_MASK; ++ switch (adc_feature->res_mode) { ++ case 8: ++ cfg_data |= VF610_ADC_MODE_BIT8; ++ break; ++ case 10: ++ cfg_data |= VF610_ADC_MODE_BIT10; ++ break; ++ case 12: ++ cfg_data |= VF610_ADC_MODE_BIT12; ++ break; ++ default: ++ dev_err(info->dev, "error resolution mode\n"); ++ break; ++ } ++ ++ /* clock select and clock divider */ ++ cfg_data &= ~(VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK); ++ switch (adc_feature->clk_div) { ++ case 1: ++ break; ++ case 2: ++ cfg_data |= VF610_ADC_CLK_DIV2; ++ break; ++ case 4: ++ cfg_data |= VF610_ADC_CLK_DIV4; ++ break; ++ case 8: ++ cfg_data |= VF610_ADC_CLK_DIV8; ++ break; ++ case 16: ++ switch (adc_feature->clk_sel) { ++ case VF610_ADCIOC_BUSCLK_SET: ++ cfg_data |= VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8; ++ break; ++ default: ++ dev_err(info->dev, "error clk divider\n"); ++ break; ++ } ++ break; ++ } ++ ++ /* Use the short sample mode */ ++ cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK); ++ ++ /* update hardware average selection */ ++ cfg_data &= ~VF610_ADC_AVGS_MASK; ++ gc_data &= ~VF610_ADC_AVGEN; ++ switch (adc_feature->sample_rate) { ++ case VF610_ADC_SAMPLE_1: ++ break; ++ case VF610_ADC_SAMPLE_4: ++ gc_data |= VF610_ADC_AVGEN; ++ break; ++ case VF610_ADC_SAMPLE_8: ++ gc_data |= VF610_ADC_AVGEN; ++ cfg_data |= VF610_ADC_AVGS_8; ++ break; ++ case VF610_ADC_SAMPLE_16: ++ gc_data |= VF610_ADC_AVGEN; ++ cfg_data |= VF610_ADC_AVGS_16; ++ break; ++ case VF610_ADC_SAMPLE_32: ++ gc_data |= VF610_ADC_AVGEN; ++ cfg_data |= VF610_ADC_AVGS_32; ++ break; ++ default: ++ dev_err(info->dev, ++ "error hardware sample average select\n"); ++ } ++ ++ writel(cfg_data, info->regs + VF610_REG_ADC_CFG); ++ writel(gc_data, info->regs + VF610_REG_ADC_GC); ++} ++ ++static void vf610_adc_hw_init(struct vf610_adc *info) ++{ ++ /* CFG: Feature set */ ++ vf610_adc_cfg_post_set(info); ++ vf610_adc_sample_set(info); ++ ++ /* adc calibration */ ++ vf610_adc_calibration(info); ++ ++ /* CFG: power and speed set */ ++ vf610_adc_cfg_set(info); ++} ++ ++static int vf610_adc_read_data(struct vf610_adc *info) ++{ ++ int result; ++ ++ result = readl(info->regs + VF610_REG_ADC_R0); ++ ++ switch (info->adc_feature.res_mode) { ++ case 8: ++ result &= 0xFF; ++ break; ++ case 10: ++ result &= 0x3FF; ++ break; ++ case 12: ++ result &= 0xFFF; ++ break; ++ default: ++ break; ++ } ++ ++ return result; ++} ++ ++static irqreturn_t vf610_adc_isr(int irq, void *dev_id) ++{ ++ struct vf610_adc *info = (struct vf610_adc *)dev_id; ++ int coco; ++ ++ coco = readl(info->regs + VF610_REG_ADC_HS); ++ if (coco & VF610_ADC_HS_COCO0) { ++ info->value = vf610_adc_read_data(info); ++ complete(&info->completion); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171"); ++ ++static struct attribute *vf610_attributes[] = { ++ &iio_const_attr_sampling_frequency_available.dev_attr.attr, ++ NULL ++}; ++ ++static const struct attribute_group vf610_attribute_group = { ++ .attrs = vf610_attributes, ++}; ++ ++static int vf610_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int *val, ++ int *val2, ++ long mask) ++{ ++ struct vf610_adc *info = iio_priv(indio_dev); ++ unsigned int hc_cfg; ++ unsigned long ret; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_RAW: ++ mutex_lock(&indio_dev->mlock); ++ reinit_completion(&info->completion); ++ ++ hc_cfg = VF610_ADC_ADCHC(chan->channel); ++ hc_cfg |= VF610_ADC_AIEN; ++ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); ++ ret = wait_for_completion_interruptible_timeout ++ (&info->completion, VF610_ADC_TIMEOUT); ++ if (ret == 0) { ++ mutex_unlock(&indio_dev->mlock); ++ return -ETIMEDOUT; ++ } ++ if (ret < 0) { ++ mutex_unlock(&indio_dev->mlock); ++ return ret; ++ } ++ ++ *val = info->value; ++ mutex_unlock(&indio_dev->mlock); ++ return IIO_VAL_INT; ++ ++ case IIO_CHAN_INFO_SCALE: ++ *val = info->vref_uv / 1000; ++ *val2 = info->adc_feature.res_mode; ++ return IIO_VAL_FRACTIONAL_LOG2; ++ ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ *val = vf610_sample_freq_avail[info->adc_feature.sample_rate]; ++ *val2 = 0; ++ return IIO_VAL_INT; ++ ++ default: ++ break; ++ } ++ ++ return -EINVAL; ++} ++ ++static int vf610_write_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int val, ++ int val2, ++ long mask) ++{ ++ struct vf610_adc *info = iio_priv(indio_dev); ++ int i; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ for (i = 0; ++ i < ARRAY_SIZE(vf610_sample_freq_avail); ++ i++) ++ if (val == vf610_sample_freq_avail[i]) { ++ info->adc_feature.sample_rate = i; ++ vf610_adc_sample_set(info); ++ return 0; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return -EINVAL; ++} ++ ++static int vf610_adc_reg_access(struct iio_dev *indio_dev, ++ unsigned reg, unsigned writeval, ++ unsigned *readval) ++{ ++ struct vf610_adc *info = iio_priv(indio_dev); ++ ++ if ((readval == NULL) || ++ (!(reg % 4) || (reg > VF610_REG_ADC_PCTL))) ++ return -EINVAL; ++ ++ *readval = readl(info->regs + reg); ++ ++ return 0; ++} ++ ++static const struct iio_info vf610_adc_iio_info = { ++ .driver_module = THIS_MODULE, ++ .read_raw = &vf610_read_raw, ++ .write_raw = &vf610_write_raw, ++ .debugfs_reg_access = &vf610_adc_reg_access, ++ .attrs = &vf610_attribute_group, ++}; ++ ++static const struct of_device_id vf610_adc_match[] = { ++ { .compatible = "fsl,vf610-adc", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, vf610_adc_match); ++ ++static int vf610_adc_probe(struct platform_device *pdev) ++{ ++ struct vf610_adc *info; ++ struct iio_dev *indio_dev; ++ struct resource *mem; ++ int irq; ++ int ret; ++ u32 channels; ++ ++ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc)); ++ if (!indio_dev) { ++ dev_err(&pdev->dev, "Failed allocating iio device\n"); ++ return -ENOMEM; ++ } ++ ++ info = iio_priv(indio_dev); ++ info->dev = &pdev->dev; ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ info->regs = devm_ioremap_resource(&pdev->dev, mem); ++ if (IS_ERR(info->regs)) ++ return PTR_ERR(info->regs); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq <= 0) { ++ dev_err(&pdev->dev, "no irq resource?\n"); ++ return -EINVAL; ++ } ++ ++ ret = devm_request_irq(info->dev, irq, ++ vf610_adc_isr, 0, ++ dev_name(&pdev->dev), info); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq); ++ return ret; ++ } ++ ++ info->clk = devm_clk_get(&pdev->dev, "adc"); ++ if (IS_ERR(info->clk)) { ++ dev_err(&pdev->dev, "failed getting clock, err = %ld\n", ++ PTR_ERR(info->clk)); ++ ret = PTR_ERR(info->clk); ++ return ret; ++ } ++ ++ info->vref = devm_regulator_get(&pdev->dev, "vref"); ++ if (IS_ERR(info->vref)) ++ return PTR_ERR(info->vref); ++ ++ ret = regulator_enable(info->vref); ++ if (ret) ++ return ret; ++ ++ info->vref_uv = regulator_get_voltage(info->vref); ++ ++ platform_set_drvdata(pdev, indio_dev); ++ ++ init_completion(&info->completion); ++ ++ ret = of_property_read_u32(pdev->dev.of_node, ++ "num-channels", &channels); ++ if (ret) ++ channels = ARRAY_SIZE(vf610_adc_iio_channels); ++ ++ indio_dev->name = dev_name(&pdev->dev); ++ indio_dev->dev.parent = &pdev->dev; ++ indio_dev->dev.of_node = pdev->dev.of_node; ++ indio_dev->info = &vf610_adc_iio_info; ++ indio_dev->modes = INDIO_DIRECT_MODE; ++ indio_dev->channels = vf610_adc_iio_channels; ++ indio_dev->num_channels = (int)channels; ++ ++ ret = clk_prepare_enable(info->clk); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "Could not prepare or enable the clock.\n"); ++ goto error_adc_clk_enable; ++ } ++ ++ vf610_adc_cfg_init(info); ++ vf610_adc_hw_init(info); ++ ++ ret = iio_device_register(indio_dev); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't register the device.\n"); ++ goto error_iio_device_register; ++ } ++ ++ return 0; ++ ++ ++error_iio_device_register: ++ clk_disable_unprepare(info->clk); ++error_adc_clk_enable: ++ regulator_disable(info->vref); ++ ++ return ret; ++} ++ ++static int vf610_adc_remove(struct platform_device *pdev) ++{ ++ struct iio_dev *indio_dev = platform_get_drvdata(pdev); ++ struct vf610_adc *info = iio_priv(indio_dev); ++ ++ iio_device_unregister(indio_dev); ++ regulator_disable(info->vref); ++ clk_disable_unprepare(info->clk); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int vf610_adc_suspend(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct vf610_adc *info = iio_priv(indio_dev); ++ int hc_cfg; ++ ++ /* ADC controller enters to stop mode */ ++ hc_cfg = readl(info->regs + VF610_REG_ADC_HC0); ++ hc_cfg |= VF610_ADC_CONV_DISABLE; ++ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); ++ ++ clk_disable_unprepare(info->clk); ++ regulator_disable(info->vref); ++ ++ return 0; ++} ++ ++static int vf610_adc_resume(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct vf610_adc *info = iio_priv(indio_dev); ++ int ret; ++ ++ ret = regulator_enable(info->vref); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(info->clk); ++ if (ret) ++ return ret; ++ ++ vf610_adc_hw_init(info); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, ++ vf610_adc_suspend, ++ vf610_adc_resume); ++ ++static struct platform_driver vf610_adc_driver = { ++ .probe = vf610_adc_probe, ++ .remove = vf610_adc_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = vf610_adc_match, ++ .pm = &vf610_adc_pm_ops, ++ }, ++}; ++ ++module_platform_driver(vf610_adc_driver); ++ ++MODULE_AUTHOR("Fugang Duan "); ++MODULE_DESCRIPTION("Freescale VF610 ADC driver"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.14.72.orig/drivers/iio/gyro/Kconfig linux-3.14.72/drivers/iio/gyro/Kconfig +--- linux-3.14.72.orig/drivers/iio/gyro/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/iio/gyro/Kconfig 2016-06-19 22:11:55.165149193 +0200 +@@ -93,7 +93,8 @@ + config ITG3200 + tristate "InvenSense ITG3200 Digital 3-Axis Gyroscope I2C driver" + depends on I2C +- select IIO_TRIGGERED_BUFFER if IIO_BUFFER ++ select IIO_BUFFER ++ select IIO_TRIGGERED_BUFFER + help + Say yes here to add support for the InvenSense ITG3200 digital + 3-axis gyroscope sensor. +diff -Nur linux-3.14.72.orig/drivers/input/keyboard/gpio_keys.c linux-3.14.72/drivers/input/keyboard/gpio_keys.c +--- linux-3.14.72.orig/drivers/input/keyboard/gpio_keys.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/keyboard/gpio_keys.c 2016-06-19 22:11:55.165149193 +0200 +@@ -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.72.orig/drivers/input/keyboard/imx_keypad.c linux-3.14.72/drivers/input/keyboard/imx_keypad.c +--- linux-3.14.72.orig/drivers/input/keyboard/imx_keypad.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/keyboard/imx_keypad.c 2016-06-19 22:11:55.165149193 +0200 +@@ -1,6 +1,7 @@ + /* + * Driver for the IMX keypad port. + * Copyright (C) 2009 Alberto Panizzo ++ * Copyright (C) 2015 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 +@@ -269,6 +270,7 @@ + reg_val |= KBD_STAT_KDIE; + reg_val &= ~KBD_STAT_KRIE; + writew(reg_val, keypad->mmio_base + KPSR); ++ pm_relax(keypad->input_dev->dev.parent); + } else { + /* + * Some keys are still pressed. Schedule a rescan in +@@ -282,11 +284,6 @@ + reg_val = readw(keypad->mmio_base + KPSR); + reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS; + writew(reg_val, keypad->mmio_base + KPSR); +- +- reg_val = readw(keypad->mmio_base + KPSR); +- reg_val |= KBD_STAT_KRIE; +- reg_val &= ~KBD_STAT_KDIE; +- writew(reg_val, keypad->mmio_base + KPSR); + } + } + +@@ -304,6 +301,7 @@ + writew(reg_val, keypad->mmio_base + KPSR); + + if (keypad->enabled) { ++ pm_stay_awake(keypad->input_dev->dev.parent); + /* The matrix is supposed to be changed */ + keypad->stable_count = 0; + +@@ -537,6 +535,7 @@ + struct platform_device *pdev = to_platform_device(dev); + struct imx_keypad *kbd = platform_get_drvdata(pdev); + struct input_dev *input_dev = kbd->input_dev; ++ unsigned short reg_val = readw(kbd->mmio_base + KPSR); + + /* imx kbd can wake up system even clock is disabled */ + mutex_lock(&input_dev->mutex); +@@ -546,8 +545,15 @@ + + mutex_unlock(&input_dev->mutex); + +- if (device_may_wakeup(&pdev->dev)) ++ if (device_may_wakeup(&pdev->dev)) { ++ if (reg_val & KBD_STAT_KPKD) ++ reg_val |= KBD_STAT_KRIE; ++ if (reg_val & KBD_STAT_KPKR) ++ reg_val |= KBD_STAT_KDIE; ++ writew(reg_val, kbd->mmio_base + KPSR); ++ + enable_irq_wake(kbd->irq); ++ } + + return 0; + } +diff -Nur linux-3.14.72.orig/drivers/input/keyboard/Kconfig linux-3.14.72/drivers/input/keyboard/Kconfig +--- linux-3.14.72.orig/drivers/input/keyboard/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/keyboard/Kconfig 2016-06-19 22:11:55.165149193 +0200 +@@ -388,6 +388,13 @@ + To compile this driver as a module, choose M here: the + module will be called mpr121_touchkey. + ++config KEYBOARD_SNVS_PWRKEY ++ tristate "IMX6SX SNVS Power Key Driver" ++ depends on SOC_IMX6SX ++ help ++ This is the snvs powerkey driver for the Freescale i.MX6SX application ++ processors. ++ + config KEYBOARD_IMX + tristate "IMX keypad support" + depends on ARCH_MXC +diff -Nur linux-3.14.72.orig/drivers/input/keyboard/Makefile linux-3.14.72/drivers/input/keyboard/Makefile +--- linux-3.14.72.orig/drivers/input/keyboard/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/keyboard/Makefile 2016-06-19 22:11:55.165149193 +0200 +@@ -47,6 +47,7 @@ + obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o + obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o + obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o ++obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o + obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o + obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o + obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o +diff -Nur linux-3.14.72.orig/drivers/input/keyboard/snvs_pwrkey.c linux-3.14.72/drivers/input/keyboard/snvs_pwrkey.c +--- linux-3.14.72.orig/drivers/input/keyboard/snvs_pwrkey.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/input/keyboard/snvs_pwrkey.c 2016-06-19 22:11:55.165149193 +0200 +@@ -0,0 +1,224 @@ ++/* ++ * Copyright (C) 2011-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 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SNVS_LPSR_REG 0x4C /* LP Status Register */ ++#define SNVS_LPCR_REG 0x38 /* LP Control Register */ ++#define SNVS_HPSR_REG 0x14 ++#define SNVS_HPSR_BTN (0x1 << 6) ++#define SNVS_LPSR_SPO (0x1 << 18) ++#define SNVS_LPCR_DEP_EN (0x1 << 5) ++ ++struct pwrkey_drv_data { ++ void __iomem *ioaddr; ++ int irq; ++ int keycode; ++ int keystate; /* 1:pressed */ ++ int wakeup; ++ struct timer_list check_timer; ++ struct input_dev *input; ++}; ++ ++static void imx_imx_snvs_check_for_events(unsigned long data) ++{ ++ struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data; ++ struct input_dev *input = pdata->input; ++ void __iomem *ioaddr = pdata->ioaddr; ++ u32 state; ++ ++ state = ((readl_relaxed(ioaddr + SNVS_HPSR_REG) & SNVS_HPSR_BTN) ? ++ 1 : 0); ++ ++ /* only report new event if status changed */ ++ if (state ^ pdata->keystate) { ++ pdata->keystate = state; ++ input_event(input, EV_KEY, pdata->keycode, state); ++ input_sync(input); ++ } ++ ++ /* repeat check if pressed long */ ++ if (state) { ++ mod_timer(&pdata->check_timer, ++ jiffies + msecs_to_jiffies(60)); ++ } ++} ++ ++static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) ++{ ++ struct platform_device *pdev = dev_id; ++ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); ++ void __iomem *ioaddr = pdata->ioaddr; ++ u32 lp_status; ++ ++ lp_status = readl_relaxed(ioaddr + SNVS_LPSR_REG); ++ if (lp_status & SNVS_LPSR_SPO) ++ mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(2)); ++ ++ /* clear SPO status */ ++ writel_relaxed(lp_status, ioaddr + SNVS_LPSR_REG); ++ ++ return IRQ_HANDLED; ++} ++ ++static int imx_snvs_pwrkey_probe(struct platform_device *pdev) ++{ ++ struct pwrkey_drv_data *pdata = NULL; ++ struct input_dev *input = NULL; ++ struct device_node *np; ++ void __iomem *ioaddr; ++ u32 val; ++ int ret = 0; ++ ++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) ++ return -ENOMEM; ++ ++ /* Get SNVS register Page */ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-snvs-pwrkey"); ++ if (!np) ++ return -ENODEV; ++ pdata->ioaddr = of_iomap(np, 0); ++ if (IS_ERR(pdata->ioaddr)) ++ return PTR_ERR(pdata->ioaddr); ++ ++ if (of_property_read_u32(np, "fsl,keycode", &pdata->keycode)) { ++ pdata->keycode = KEY_POWER; ++ dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); ++ } ++ ++ pdata->wakeup = !!of_get_property(np, "fsl,wakeup", NULL); ++ ++ pdata->irq = platform_get_irq(pdev, 0); ++ if (pdata->irq < 0) { ++ dev_err(&pdev->dev, "no irq defined in platform data\n"); ++ return -EINVAL; ++ } ++ ++ ioaddr = pdata->ioaddr; ++ val = readl_relaxed(ioaddr + SNVS_LPCR_REG); ++ val |= SNVS_LPCR_DEP_EN, ++ writel_relaxed(val, ioaddr + SNVS_LPCR_REG); ++ /* clear the unexpected interrupt before driver ready */ ++ val = readl_relaxed(ioaddr + SNVS_LPSR_REG); ++ if (val & SNVS_LPSR_SPO) ++ writel_relaxed(val | SNVS_LPSR_SPO, ioaddr + SNVS_LPSR_REG); ++ ++ setup_timer(&pdata->check_timer, ++ imx_imx_snvs_check_for_events, (unsigned long) pdata); ++ ++ if (pdata->irq >= 0) { ++ ret = devm_request_irq(&pdev->dev, pdata->irq, ++ imx_snvs_pwrkey_interrupt, ++ IRQF_TRIGGER_HIGH, pdev->name, pdev); ++ if (ret) { ++ dev_err(&pdev->dev, "interrupt not available.\n"); ++ return ret; ++ } ++ } ++ ++ input = devm_input_allocate_device(&pdev->dev); ++ if (!input) { ++ dev_err(&pdev->dev, "failed to allocate the input device\n"); ++ return -ENOMEM; ++ } ++ ++ input->name = pdev->name; ++ input->phys = "snvs-pwrkey/input0"; ++ input->id.bustype = BUS_HOST; ++ input->evbit[0] = BIT_MASK(EV_KEY); ++ ++ input_set_capability(input, EV_KEY, pdata->keycode); ++ ++ ret = input_register_device(input); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to register input device\n"); ++ input_free_device(input); ++ return ret; ++ } ++ ++ pdata->input = input; ++ platform_set_drvdata(pdev, pdata); ++ ++ device_init_wakeup(&pdev->dev, pdata->wakeup); ++ ++ dev_info(&pdev->dev, "i.MX snvs powerkey probed\n"); ++ ++ return 0; ++} ++ ++static int imx_snvs_pwrkey_remove(struct platform_device *pdev) ++{ ++ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); ++ ++ input_unregister_device(pdata->input); ++ del_timer_sync(&pdata->check_timer); ++ ++ return 0; ++} ++ ++static int imx_snvs_pwrkey_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); ++ ++ if (device_may_wakeup(&pdev->dev)) ++ enable_irq_wake(pdata->irq); ++ ++ return 0; ++} ++ ++static int imx_snvs_pwrkey_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); ++ ++ if (device_may_wakeup(&pdev->dev)) ++ disable_irq_wake(pdata->irq); ++ ++ return 0; ++} ++ ++static const struct of_device_id imx_snvs_pwrkey_ids[] = { ++ { .compatible = "fsl,imx6sx-snvs-pwrkey" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids); ++ ++static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend, ++ imx_snvs_pwrkey_resume); ++ ++static struct platform_driver imx_snvs_pwrkey_driver = { ++ .driver = { ++ .name = "snvs_pwrkey", ++ .owner = THIS_MODULE, ++ .pm = &imx_snvs_pwrkey_pm_ops, ++ .of_match_table = imx_snvs_pwrkey_ids, ++ }, ++ .probe = imx_snvs_pwrkey_probe, ++ .remove = imx_snvs_pwrkey_remove, ++}; ++module_platform_driver(imx_snvs_pwrkey_driver); ++ ++MODULE_AUTHOR("Freescale Semiconductor"); ++MODULE_DESCRIPTION("i.MX snvs power key Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/input/misc/isl29023.c linux-3.14.72/drivers/input/misc/isl29023.c +--- linux-3.14.72.orig/drivers/input/misc/isl29023.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/input/misc/isl29023.c 2016-06-19 22:11:55.165149193 +0200 +@@ -0,0 +1,1076 @@ ++/* ++ * Copyright (C) 2011-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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ISL29023_DRV_NAME "isl29023" ++#define DRIVER_VERSION "1.0" ++ ++#define ISL29023_COMMAND1 (0x00) ++#define ISL29023_MODE_SHIFT (5) ++#define ISL29023_MODE_MASK (0x7 << ISL29023_MODE_SHIFT) ++#define ISL29023_INT_FLAG_SHIFT (2) ++#define ISL29023_INT_FLAG_MASK (0x1 << ISL29023_INT_FLAG_SHIFT) ++#define ISL29023_INT_PERSISTS_SHIFT (0) ++#define ISL29023_INT_PERSISTS_MASK (0x3 << ISL29023_INT_PERSISTS_SHIFT) ++ ++#define ISL29023_COMMAND2 (0x01) ++#define ISL29023_RES_SHIFT (2) ++#define ISL29023_RES_MASK (0x3 << ISL29023_RES_SHIFT) ++#define ISL29023_RANGE_SHIFT (0) ++#define ISL29023_RANGE_MASK (0x3 << ISL29023_RANGE_SHIFT) ++ ++#define ISL29023_REG_LSB_SENSOR (0x02) ++#define ISL29023_REG_MSB_SENSOR (0x03) ++#define ISL29023_REG_IRQ_TH_LO_LSB (0x04) ++#define ISL29023_REG_IRQ_TH_LO_MSB (0x05) ++#define ISL29023_REG_IRQ_TH_HI_LSB (0x06) ++#define ISL29023_REG_IRQ_TH_HI_MSB (0x07) ++ ++#define ISL29023_NUM_CACHABLE_REGS 8 ++#define DEF_RANGE 2 ++#define DEFAULT_REGISTOR_VAL 499 ++ ++struct isl29023_data { ++ struct i2c_client *client; ++ struct mutex lock; ++ struct input_dev *input; ++ struct work_struct work; ++ struct workqueue_struct *workqueue; ++ char phys[32]; ++ u8 reg_cache[ISL29023_NUM_CACHABLE_REGS]; ++ u8 mode_before_suspend; ++ u8 mode_before_interrupt; ++ u16 rext; ++}; ++ ++static int gain_range[] = { ++ 1000, 4000, 16000, 64000 ++}; ++ ++/* ++ * register access helpers ++ */ ++static int __isl29023_read_reg(struct i2c_client *client, ++ u32 reg, u8 mask, u8 shift) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ return (data->reg_cache[reg] & mask) >> shift; ++} ++ ++static int __isl29023_write_reg(struct i2c_client *client, ++ u32 reg, u8 mask, u8 shift, u8 val) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int ret = 0; ++ u8 tmp; ++ ++ if (reg >= ISL29023_NUM_CACHABLE_REGS) ++ return -EINVAL; ++ ++ mutex_lock(&data->lock); ++ ++ tmp = data->reg_cache[reg]; ++ tmp &= ~mask; ++ tmp |= val << shift; ++ ++ ret = i2c_smbus_write_byte_data(client, reg, tmp); ++ if (!ret) ++ data->reg_cache[reg] = tmp; ++ ++ mutex_unlock(&data->lock); ++ return ret; ++} ++ ++/* ++ * internally used functions ++ */ ++static int isl29023_get_int_persists(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_PERSISTS_MASK, ISL29023_INT_PERSISTS_SHIFT); ++} ++ ++static int isl29023_set_int_persists(struct i2c_client *client, ++ int int_persists) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_PERSISTS_MASK, ISL29023_INT_PERSISTS_SHIFT, ++ int_persists); ++} ++ ++/* ++ * interrupt flag ++ */ ++static int isl29023_get_int_flag(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_FLAG_MASK, ISL29023_INT_FLAG_SHIFT); ++} ++ ++static int isl29023_set_int_flag(struct i2c_client *client, int flag) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_FLAG_MASK, ISL29023_INT_FLAG_SHIFT, flag); ++} ++ ++/* ++ * interrupt lt ++ */ ++static int isl29023_get_int_lt(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, lt; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ lt = ((msb << 8) | lsb); ++ ++ return lt; ++} ++ ++static int isl29023_set_int_lt(struct i2c_client *client, int lt) ++{ ++ int ret = 0; ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB, ++ lt & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB, ++ (lt >> 8) & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_MSB] = (lt >> 8) & 0xff; ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_LSB] = lt & 0xff; ++ mutex_unlock(&data->lock); ++ ++ return ret; ++} ++ ++/* ++ * interrupt ht ++ */ ++static int isl29023_get_int_ht(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, ht; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ ht = ((msb << 8) | lsb); ++ ++ return ht; ++} ++ ++static int isl29023_set_int_ht(struct i2c_client *client, int ht) ++{ ++ int ret = 0; ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB, ++ ht & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB, ++ (ht >> 8) & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_MSB] = (ht >> 8) & 0xff; ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_LSB] = ht & 0xff; ++ mutex_unlock(&data->lock); ++ ++ return ret; ++} ++ ++/* ++ * range ++ */ ++static int isl29023_get_range(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND2, ++ ISL29023_RANGE_MASK, ISL29023_RANGE_SHIFT); ++} ++ ++static int isl29023_set_range(struct i2c_client *client, int range) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND2, ++ ISL29023_RANGE_MASK, ISL29023_RANGE_SHIFT, range); ++} ++ ++/* ++ * resolution ++ */ ++static int isl29023_get_resolution(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND2, ++ ISL29023_RES_MASK, ISL29023_RES_SHIFT); ++} ++ ++static int isl29023_set_resolution(struct i2c_client *client, int res) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND2, ++ ISL29023_RES_MASK, ISL29023_RES_SHIFT, res); ++} ++ ++/* ++ * mode ++ */ ++static int isl29023_get_mode(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND1, ++ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT); ++} ++ ++static int isl29023_set_mode(struct i2c_client *client, int mode) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT, mode); ++} ++ ++/* ++ * power_state ++ */ ++static int isl29023_set_power_state(struct i2c_client *client, int state) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT, ++ state ? ++ ISL29023_ALS_ONCE_MODE : ISL29023_PD_MODE); ++} ++ ++static int isl29023_get_power_state(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ u8 cmdreg = data->reg_cache[ISL29023_COMMAND1]; ++ ++ if (cmdreg & ISL29023_MODE_MASK) ++ return 1; ++ else ++ return 0; ++} ++ ++static int isl29023_get_adc_value(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, range, bitdepth; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_LSB_SENSOR); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_MSB_SENSOR); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext)) ++ >> bitdepth; ++} ++ ++static int isl29023_get_int_lt_value(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, range, bitdepth; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext)) ++ >> bitdepth; ++} ++ ++static int isl29023_get_int_ht_value(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, range, bitdepth; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext)) ++ >> bitdepth; ++} ++ ++/* ++ * sysfs layer ++ */ ++ ++/* ++ * interrupt persists ++ */ ++static ssize_t isl29023_show_int_persists(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_persists(client)); ++} ++ ++static ssize_t isl29023_store_int_persists(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || ++ (val > ISL29023_INT_PERSISTS_16)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_persists(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_persists, S_IWUSR | S_IRUGO, ++ isl29023_show_int_persists, isl29023_store_int_persists); ++ ++/* ++ *interrupt flag ++ */ ++static ssize_t isl29023_show_int_flag(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_flag(client)); ++} ++ ++static ssize_t isl29023_store_int_flag(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_flag(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_flag, S_IWUSR | S_IRUGO, ++ isl29023_show_int_flag, isl29023_store_int_flag); ++ ++/* ++ * interrupt lt ++ */ ++static ssize_t isl29023_show_int_lt(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_lt(client)); ++} ++ ++static ssize_t isl29023_store_int_lt(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 16, &val) < 0) || (val > 0xffff)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_lt(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_lt, S_IWUSR | S_IRUGO, ++ isl29023_show_int_lt, isl29023_store_int_lt); ++ ++/* ++ *interrupt ht ++ */ ++static ssize_t isl29023_show_int_ht(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_ht(client)); ++} ++ ++static ssize_t isl29023_store_int_ht(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 16, &val) < 0) || (val > 0xffff)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_ht(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_ht, S_IWUSR | S_IRUGO, ++ isl29023_show_int_ht, isl29023_store_int_ht); ++ ++/* ++ * range ++ */ ++static ssize_t isl29023_show_range(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_range(client)); ++} ++ ++static ssize_t isl29023_store_range(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > ISL29023_RANGE_64K)) ++ return -EINVAL; ++ ++ ret = isl29023_set_range(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, ++ isl29023_show_range, isl29023_store_range); ++ ++ ++/* ++ * resolution ++ */ ++static ssize_t isl29023_show_resolution(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", isl29023_get_resolution(client)); ++} ++ ++static ssize_t isl29023_store_resolution(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > ISL29023_RES_4)) ++ return -EINVAL; ++ ++ ret = isl29023_set_resolution(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO, ++ isl29023_show_resolution, isl29023_store_resolution); ++ ++/* ++ *mode ++ */ ++static ssize_t isl29023_show_mode(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", isl29023_get_mode(client)); ++} ++ ++static ssize_t isl29023_store_mode(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || ++ (val > ISL29023_IR_CONT_MODE)) ++ return -EINVAL; ++ ++ /* clear the interrupt flag */ ++ i2c_smbus_read_byte_data(client, ISL29023_COMMAND1); ++ ret = isl29023_set_mode(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, ++ isl29023_show_mode, isl29023_store_mode); ++ ++ ++/* ++ *power state ++ */ ++static ssize_t isl29023_show_power_state(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", isl29023_get_power_state(client)); ++} ++ ++static ssize_t isl29023_store_power_state(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1)) ++ return -EINVAL; ++ ++ ret = isl29023_set_power_state(client, val); ++ return ret ? ret : count; ++} ++ ++static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, ++ isl29023_show_power_state, isl29023_store_power_state); ++ ++/* ++ * lux ++ */ ++static ssize_t isl29023_show_lux(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ /* No LUX data if not operational */ ++ if (!isl29023_get_power_state(client)) ++ return -EBUSY; ++ ++ return sprintf(buf, "%d\n", isl29023_get_adc_value(client)); ++} ++ ++static DEVICE_ATTR(lux, S_IRUGO, isl29023_show_lux, NULL); ++ ++/* ++ * lux interrupt low threshold ++ */ ++static ssize_t isl29023_show_int_lt_lux(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ return sprintf(buf, "%d\n", isl29023_get_int_lt_value(client)); ++} ++ ++static ssize_t isl29023_store_int_lt_lux(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ unsigned long val, lux_data; ++ int range, bitdepth, ret; ++ u8 lsb, msb; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0)) ++ return -EINVAL; ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ if (val > (gain_range[isl29023_get_range(client)]*499/data->rext)) ++ return -EINVAL; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ lux_data = ((unsigned long)(val << bitdepth)) / ++ ((gain_range[range] * 499) / data->rext); ++ lux_data &= 0xffff; ++ ++ msb = lux_data >> 8; ++ lsb = lux_data & 0xff; ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB, ++ lsb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB, ++ msb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_MSB] = msb; ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_LSB] = lsb; ++ mutex_unlock(&data->lock); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_lt_lux, S_IWUSR | S_IRUGO, ++ isl29023_show_int_lt_lux, isl29023_store_int_lt_lux); ++ ++/* ++ * lux interrupt high threshold ++ */ ++static ssize_t isl29023_show_int_ht_lux(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ return sprintf(buf, "%d\n", isl29023_get_int_ht_value(client)); ++} ++ ++static ssize_t isl29023_store_int_ht_lux(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ unsigned long val, lux_data; ++ int range, bitdepth, ret; ++ u8 lsb, msb; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0)) ++ return -EINVAL; ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ if (val > (gain_range[isl29023_get_range(client)]*499/data->rext)) ++ return -EINVAL; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ lux_data = ((unsigned long)(val << bitdepth)) / ++ ((gain_range[range] * 499) / data->rext); ++ lux_data &= 0xffff; ++ ++ msb = lux_data >> 8; ++ lsb = lux_data & 0xff; ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB, ++ lsb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB, ++ msb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_MSB] = msb; ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_LSB] = lsb; ++ mutex_unlock(&data->lock); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_ht_lux, S_IWUSR | S_IRUGO, ++ isl29023_show_int_ht_lux, isl29023_store_int_ht_lux); ++ ++static struct attribute *isl29023_attributes[] = { ++ &dev_attr_int_persists.attr, ++ &dev_attr_range.attr, ++ &dev_attr_resolution.attr, ++ &dev_attr_mode.attr, ++ &dev_attr_power_state.attr, ++ &dev_attr_lux.attr, ++ &dev_attr_int_lt_lux.attr, ++ &dev_attr_int_ht_lux.attr, ++ &dev_attr_int_lt.attr, ++ &dev_attr_int_ht.attr, ++ &dev_attr_int_flag.attr, ++ NULL ++}; ++ ++static const struct attribute_group isl29023_attr_group = { ++ .attrs = isl29023_attributes, ++}; ++ ++static int isl29023_init_client(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ /* read all the registers once to fill the cache. ++ * if one of the reads fails, we consider the init failed */ ++ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) { ++ int v = i2c_smbus_read_byte_data(client, i); ++ if (v < 0) ++ return -ENODEV; ++ ++ data->reg_cache[i] = v; ++ } ++ ++ /* set defaults */ ++ isl29023_set_int_persists(client, ISL29023_INT_PERSISTS_8); ++ isl29023_set_int_ht(client, 0xffff); ++ isl29023_set_int_lt(client, 0x0); ++ isl29023_set_range(client, ISL29023_RANGE_16K); ++ isl29023_set_resolution(client, ISL29023_RES_16); ++ isl29023_set_mode(client, ISL29023_ALS_ONCE_MODE); ++ isl29023_set_int_flag(client, 0); ++ isl29023_set_power_state(client, 0); ++ ++ return 0; ++} ++ ++static void isl29023_work(struct work_struct *work) ++{ ++ struct isl29023_data *data = ++ container_of(work, struct isl29023_data, work); ++ struct i2c_client *client = data->client; ++ int lux; ++ ++ /* Clear interrupt flag */ ++ isl29023_set_int_flag(client, 0); ++ ++ data->mode_before_interrupt = isl29023_get_mode(client); ++ lux = isl29023_get_adc_value(client); ++ ++ /* To clear the interrpt status */ ++ isl29023_set_power_state(client, ISL29023_PD_MODE); ++ isl29023_set_mode(client, data->mode_before_interrupt); ++ ++ msleep(100); ++ ++ input_report_abs(data->input, ABS_MISC, lux); ++ input_sync(data->input); ++} ++ ++static irqreturn_t isl29023_irq_handler(int irq, void *handle) ++{ ++ struct isl29023_data *data = handle; ++ int cmd_1; ++ cmd_1 = i2c_smbus_read_byte_data(data->client, ISL29023_COMMAND1); ++ if (!(cmd_1 & ISL29023_INT_FLAG_MASK)) ++ return IRQ_NONE; ++ ++ queue_work(data->workqueue, &data->work); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * I2C layer ++ */ ++static int isl29023_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ struct isl29023_data *data; ++ struct input_dev *input_dev; ++ int err = 0; ++ struct regulator *vdd = NULL; ++ u32 rext = 0; ++ struct device_node *of_node = client->dev.of_node; ++ struct irq_data *irq_data = irq_get_irq_data(client->irq); ++ u32 irq_flag; ++ bool shared_irq; ++ ++ vdd = devm_regulator_get(&client->dev, "vdd"); ++ if (!IS_ERR(vdd)) { ++ err = regulator_enable(vdd); ++ if (err) { ++ dev_err(&client->dev, "vdd set voltage error\n"); ++ return err; ++ } ++ } ++ ++ err = of_property_read_u32(of_node, "rext", &rext); ++ if (err) ++ rext = DEFAULT_REGISTOR_VAL; ++ shared_irq = of_property_read_bool(of_node, "shared-interrupt"); ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) ++ return -EIO; ++ ++ data = kzalloc(sizeof(struct isl29023_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ data->rext = (u16)rext; ++ snprintf(data->phys, sizeof(data->phys), ++ "%s", dev_name(&client->dev)); ++ i2c_set_clientdata(client, data); ++ mutex_init(&data->lock); ++ ++ /* initialize the ISL29023 chip */ ++ err = isl29023_init_client(client); ++ if (err) ++ goto exit_kfree; ++ ++ /* register sysfs hooks */ ++ err = sysfs_create_group(&client->dev.kobj, &isl29023_attr_group); ++ if (err) ++ goto exit_kfree; ++ ++ input_dev = input_allocate_device(); ++ if (!input_dev) { ++ err = -ENOMEM; ++ goto exit_kfree; ++ } ++ ++ data->input = input_dev; ++ input_dev->name = "isl29023 light sensor"; ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->phys = data->phys; ++ ++ __set_bit(EV_ABS, input_dev->evbit); ++ input_set_abs_params(input_dev, ABS_MISC, 0, ++ gain_range[DEF_RANGE]*499/data->rext, 0, 0); ++ ++ err = input_register_device(input_dev); ++ if (err) ++ goto exit_free_input; ++ ++ irq_flag = irqd_get_trigger_type(irq_data); ++ irq_flag |= IRQF_ONESHOT; ++ if (shared_irq) ++ irq_flag |= IRQF_SHARED; ++ err = request_threaded_irq(client->irq, NULL, ++ isl29023_irq_handler, irq_flag, ++ client->dev.driver->name, data); ++ if (err < 0) { ++ dev_err(&client->dev, "failed to register irq %d!\n", ++ client->irq); ++ goto exit_free_input; ++ } ++ ++ data->workqueue = create_singlethread_workqueue("isl29023"); ++ INIT_WORK(&data->work, isl29023_work); ++ if (data->workqueue == NULL) { ++ dev_err(&client->dev, "couldn't create workqueue\n"); ++ err = -ENOMEM; ++ goto exit_free_interrupt; ++ } ++ ++ dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION); ++ return 0; ++ ++exit_free_interrupt: ++ free_irq(client->irq, data); ++exit_free_input: ++ input_free_device(input_dev); ++exit_kfree: ++ kfree(data); ++ return err; ++} ++ ++static int isl29023_remove(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ cancel_work_sync(&data->work); ++ destroy_workqueue(data->workqueue); ++ free_irq(client->irq, data); ++ input_unregister_device(data->input); ++ input_free_device(data->input); ++ sysfs_remove_group(&client->dev.kobj, &isl29023_attr_group); ++ isl29023_set_power_state(client, 0); ++ kfree(i2c_get_clientdata(client)); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int isl29023_suspend(struct i2c_client *client, pm_message_t mesg) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ data->mode_before_suspend = isl29023_get_mode(client); ++ return isl29023_set_power_state(client, ISL29023_PD_MODE); ++} ++ ++static int isl29023_resume(struct i2c_client *client) ++{ ++ int i; ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ /* restore registers from cache */ ++ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) ++ if (i2c_smbus_write_byte_data(client, i, data->reg_cache[i])) ++ return -EIO; ++ ++ return isl29023_set_mode(client, data->mode_before_suspend); ++} ++ ++#else ++#define isl29023_suspend NULL ++#define isl29023_resume NULL ++#endif /* CONFIG_PM */ ++ ++static const struct i2c_device_id isl29023_id[] = { ++ { ISL29023_DRV_NAME, 0 }, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, isl29023_id); ++ ++static struct i2c_driver isl29023_driver = { ++ .driver = { ++ .name = ISL29023_DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .suspend = isl29023_suspend, ++ .resume = isl29023_resume, ++ .probe = isl29023_probe, ++ .remove = isl29023_remove, ++ .id_table = isl29023_id, ++}; ++ ++static int __init isl29023_init(void) ++{ ++ return i2c_add_driver(&isl29023_driver); ++} ++ ++static void __exit isl29023_exit(void) ++{ ++ i2c_del_driver(&isl29023_driver); ++} ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("ISL29023 ambient light sensor driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRIVER_VERSION); ++ ++module_init(isl29023_init); ++module_exit(isl29023_exit); +diff -Nur linux-3.14.72.orig/drivers/input/misc/Kconfig linux-3.14.72/drivers/input/misc/Kconfig +--- linux-3.14.72.orig/drivers/input/misc/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/misc/Kconfig 2016-06-19 22:11:55.165149193 +0200 +@@ -666,4 +666,14 @@ + To compile this driver as a module, choose M here: the + module will be called ideapad_slidebar. + ++config INPUT_ISL29023 ++ tristate "Intersil ISL29023 ambient light sensor" ++ depends on I2C && SYSFS ++ help ++ If you say yes here you get support for the Intersil ISL29023 ++ ambient light sensor. ++ ++ This driver can also be built as a module. If so, the module ++ will be called isl29023. ++ + endif +diff -Nur linux-3.14.72.orig/drivers/input/misc/Makefile linux-3.14.72/drivers/input/misc/Makefile +--- linux-3.14.72.orig/drivers/input/misc/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/misc/Makefile 2016-06-19 22:11:55.165149193 +0200 +@@ -63,3 +63,4 @@ + obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o + obj-$(CONFIG_INPUT_YEALINK) += yealink.o + obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o ++obj-$(CONFIG_INPUT_ISL29023) += isl29023.o +diff -Nur linux-3.14.72.orig/drivers/input/misc/mma8450.c linux-3.14.72/drivers/input/misc/mma8450.c +--- linux-3.14.72.orig/drivers/input/misc/mma8450.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/misc/mma8450.c 2016-06-19 22:11:55.165149193 +0200 +@@ -1,7 +1,7 @@ + /* + * Driver for Freescale's 3-Axis Accelerometer MMA8450 + * +- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2011-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 +@@ -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); +@@ -204,13 +310,32 @@ + goto err_free_mem; + } + +- 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 +344,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.72.orig/drivers/input/touchscreen/edt-ft5x06.c linux-3.14.72/drivers/input/touchscreen/edt-ft5x06.c +--- linux-3.14.72.orig/drivers/input/touchscreen/edt-ft5x06.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/touchscreen/edt-ft5x06.c 2016-06-19 22:11:55.165149193 +0200 +@@ -1,5 +1,7 @@ + /* + * Copyright (C) 2012 Simon Budig, ++ * Daniel Wagener (M09 firmware support) ++ * Lothar Waßmann (DT support) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and +@@ -33,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -45,6 +48,14 @@ + #define WORK_REGISTER_NUM_X 0x33 + #define WORK_REGISTER_NUM_Y 0x34 + ++#define M09_REGISTER_THRESHOLD 0x80 ++#define M09_REGISTER_GAIN 0x92 ++#define M09_REGISTER_OFFSET 0x93 ++#define M09_REGISTER_NUM_X 0x94 ++#define M09_REGISTER_NUM_Y 0x95 ++ ++#define NO_REGISTER 0xff ++ + #define WORK_REGISTER_OPMODE 0x3c + #define FACTORY_REGISTER_OPMODE 0x01 + +@@ -59,12 +70,30 @@ + #define EDT_RAW_DATA_RETRIES 100 + #define EDT_RAW_DATA_DELAY 1 /* msec */ + ++enum edt_ver { ++ M06, ++ M09, ++}; ++ ++struct edt_reg_addr { ++ int reg_threshold; ++ int reg_report_rate; ++ int reg_gain; ++ int reg_offset; ++ int reg_num_x; ++ int reg_num_y; ++}; ++ + struct edt_ft5x06_ts_data { + struct i2c_client *client; + struct input_dev *input; + u16 num_x; + u16 num_y; + ++ int reset_pin; ++ int irq_pin; ++ int wake_pin; ++ + #if defined(CONFIG_DEBUG_FS) + struct dentry *debug_dir; + u8 *raw_buffer; +@@ -79,6 +108,13 @@ + int report_rate; + + char name[EDT_NAME_LEN]; ++ ++ struct edt_reg_addr reg_addr; ++ enum edt_ver version; ++ ++ bool invert; ++ int screen_x; ++ int screen_y; + }; + + static int edt_ft5x06_ts_readwrite(struct i2c_client *client, +@@ -136,33 +172,58 @@ + { + struct edt_ft5x06_ts_data *tsdata = dev_id; + struct device *dev = &tsdata->client->dev; +- u8 cmd = 0xf9; +- u8 rdbuf[26]; ++ u8 cmd; ++ u8 rdbuf[29]; + int i, type, x, y, id; ++ int offset, tplen, datalen; + int error; + ++ switch (tsdata->version) { ++ case M06: ++ cmd = 0xf9; /* tell the controller to send touch data */ ++ offset = 5; /* where the actual touch data starts */ ++ tplen = 4; /* data comes in so called frames */ ++ datalen = 26; /* how much bytes to listen for */ ++ break; ++ ++ case M09: ++ cmd = 0x02; ++ offset = 1; ++ tplen = 6; ++ datalen = 29; ++ break; ++ ++ default: ++ goto out; ++ } ++ + memset(rdbuf, 0, sizeof(rdbuf)); + + error = edt_ft5x06_ts_readwrite(tsdata->client, + sizeof(cmd), &cmd, +- sizeof(rdbuf), rdbuf); ++ datalen, rdbuf); + if (error) { + dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", + error); + goto out; + } + +- if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) { +- dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n", +- rdbuf[0], rdbuf[1], rdbuf[2]); +- goto out; +- } ++ /* M09 does not send header or CRC */ ++ if (tsdata->version == M06) { ++ if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || ++ rdbuf[2] != datalen) { ++ dev_err_ratelimited(dev, ++ "Unexpected header: %02x%02x%02x!\n", ++ rdbuf[0], rdbuf[1], rdbuf[2]); ++ goto out; ++ } + +- if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26)) +- goto out; ++ if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) ++ goto out; ++ } + + for (i = 0; i < MAX_SUPPORT_POINTS; i++) { +- u8 *buf = &rdbuf[i * 4 + 5]; ++ u8 *buf = &rdbuf[i * tplen + offset]; + bool down; + + type = buf[0] >> 6; +@@ -170,11 +231,22 @@ + if (type == TOUCH_EVENT_RESERVED) + continue; + ++ /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ ++ if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) ++ continue; ++ + x = ((buf[0] << 8) | buf[1]) & 0x0fff; + y = ((buf[2] << 8) | buf[3]) & 0x0fff; + id = (buf[2] >> 4) & 0x0f; + down = (type != TOUCH_EVENT_UP); + ++ /* invert axis */ ++ if (tsdata->invert) { ++ x = tsdata->screen_x - x; ++ y = tsdata->screen_y - y; ++ } ++ dev_dbg(dev, "%d: %dx%d %s\n", id, x, y, down ? "UP" : "DOWN"); ++ + input_mt_slot(tsdata->input, id); + input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); + +@@ -197,12 +269,25 @@ + { + u8 wrbuf[4]; + +- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; +- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +- wrbuf[2] = value; +- wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; ++ switch (tsdata->version) { ++ case M06: ++ wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; ++ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; ++ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; ++ wrbuf[2] = value; ++ wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; ++ return edt_ft5x06_ts_readwrite(tsdata->client, 4, ++ wrbuf, 0, NULL); ++ case M09: ++ wrbuf[0] = addr; ++ wrbuf[1] = value; + +- return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); ++ return edt_ft5x06_ts_readwrite(tsdata->client, 2, ++ wrbuf, 0, NULL); ++ ++ default: ++ return -EINVAL; ++ } + } + + static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, +@@ -211,19 +296,36 @@ + u8 wrbuf[2], rdbuf[2]; + int error; + +- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; +- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +- wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; ++ switch (tsdata->version) { ++ case M06: ++ wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; ++ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; ++ wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; + +- error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf); +- if (error) +- return error; ++ error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, ++ rdbuf); ++ if (error) ++ return error; + +- if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { +- dev_err(&tsdata->client->dev, +- "crc error: 0x%02x expected, got 0x%02x\n", +- wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]); +- return -EIO; ++ if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { ++ dev_err(&tsdata->client->dev, ++ "crc error: 0x%02x expected, got 0x%02x\n", ++ wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], ++ rdbuf[1]); ++ return -EIO; ++ } ++ break; ++ ++ case M09: ++ wrbuf[0] = addr; ++ error = edt_ft5x06_ts_readwrite(tsdata->client, 1, ++ wrbuf, 1, rdbuf); ++ if (error) ++ return error; ++ break; ++ ++ default: ++ return -EINVAL; + } + + return rdbuf[0]; +@@ -234,19 +336,21 @@ + size_t field_offset; + u8 limit_low; + u8 limit_high; +- u8 addr; ++ u8 addr_m06; ++ u8 addr_m09; + }; + +-#define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high) \ ++#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \ ++ _limit_low, _limit_high) \ + struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ + .dattr = __ATTR(_field, _mode, \ + edt_ft5x06_setting_show, \ + edt_ft5x06_setting_store), \ +- .field_offset = \ +- offsetof(struct edt_ft5x06_ts_data, _field), \ ++ .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ ++ .addr_m06 = _addr_m06, \ ++ .addr_m09 = _addr_m09, \ + .limit_low = _limit_low, \ + .limit_high = _limit_high, \ +- .addr = _addr, \ + } + + static ssize_t edt_ft5x06_setting_show(struct device *dev, +@@ -261,6 +365,7 @@ + int val; + size_t count = 0; + int error = 0; ++ u8 addr; + + mutex_lock(&tsdata->mutex); + +@@ -269,15 +374,33 @@ + goto out; + } + +- val = edt_ft5x06_register_read(tsdata, attr->addr); +- if (val < 0) { +- error = val; +- dev_err(&tsdata->client->dev, +- "Failed to fetch attribute %s, error %d\n", +- dattr->attr.name, error); ++ switch (tsdata->version) { ++ case M06: ++ addr = attr->addr_m06; ++ break; ++ ++ case M09: ++ addr = attr->addr_m09; ++ break; ++ ++ default: ++ error = -ENODEV; + goto out; + } + ++ if (addr != NO_REGISTER) { ++ val = edt_ft5x06_register_read(tsdata, addr); ++ if (val < 0) { ++ error = val; ++ dev_err(&tsdata->client->dev, ++ "Failed to fetch attribute %s, error %d\n", ++ dattr->attr.name, error); ++ goto out; ++ } ++ } else { ++ val = *field; ++ } ++ + if (val != *field) { + dev_warn(&tsdata->client->dev, + "%s: read (%d) and stored value (%d) differ\n", +@@ -302,6 +425,7 @@ + u8 *field = (u8 *)((char *)tsdata + attr->field_offset); + unsigned int val; + int error; ++ u8 addr; + + mutex_lock(&tsdata->mutex); + +@@ -319,14 +443,29 @@ + goto out; + } + +- error = edt_ft5x06_register_write(tsdata, attr->addr, val); +- if (error) { +- dev_err(&tsdata->client->dev, +- "Failed to update attribute %s, error: %d\n", +- dattr->attr.name, error); ++ switch (tsdata->version) { ++ case M06: ++ addr = attr->addr_m06; ++ break; ++ ++ case M09: ++ addr = attr->addr_m09; ++ break; ++ ++ default: ++ error = -ENODEV; + goto out; + } + ++ if (addr != NO_REGISTER) { ++ error = edt_ft5x06_register_write(tsdata, addr, val); ++ if (error) { ++ dev_err(&tsdata->client->dev, ++ "Failed to update attribute %s, error: %d\n", ++ dattr->attr.name, error); ++ goto out; ++ } ++ } + *field = val; + + out: +@@ -334,12 +473,14 @@ + return error ?: count; + } + +-static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31); +-static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31); +-static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, +- WORK_REGISTER_THRESHOLD, 20, 80); +-static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, +- WORK_REGISTER_REPORT_RATE, 3, 14); ++static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, ++ M09_REGISTER_GAIN, 0, 31); ++static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, ++ M09_REGISTER_OFFSET, 0, 31); ++static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, ++ M09_REGISTER_THRESHOLD, 20, 80); ++static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, ++ NO_REGISTER, 3, 14); + + static struct attribute *edt_ft5x06_attrs[] = { + &edt_ft5x06_attr_gain.dattr.attr, +@@ -374,6 +515,9 @@ + } + + /* mode register is 0x3c when in the work mode */ ++ if (tsdata->version == M09) ++ goto m09_out; ++ + error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); + if (error) { + dev_err(&client->dev, +@@ -406,12 +550,18 @@ + enable_irq(client->irq); + + return error; ++ ++m09_out: ++ dev_err(&client->dev, "No factory mode support for M09\n"); ++ return -EINVAL; ++ + } + + static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) + { + struct i2c_client *client = tsdata->client; + int retries = EDT_SWITCH_MODE_RETRIES; ++ struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + int ret; + int error; + +@@ -444,13 +594,14 @@ + tsdata->raw_buffer = NULL; + + /* restore parameters */ +- edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD, ++ edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, + tsdata->threshold); +- edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN, ++ edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, + tsdata->gain); +- edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET, ++ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, + tsdata->offset); +- edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE, ++ if (reg_addr->reg_report_rate) ++ edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, + tsdata->report_rate); + + enable_irq(client->irq); +@@ -617,55 +768,99 @@ + + + static int edt_ft5x06_ts_reset(struct i2c_client *client, +- int reset_pin) ++ struct edt_ft5x06_ts_data *tsdata) + { + int error; + +- if (gpio_is_valid(reset_pin)) { ++ if (gpio_is_valid(tsdata->wake_pin)) { ++ error = devm_gpio_request_one(&client->dev, ++ tsdata->wake_pin, GPIOF_OUT_INIT_LOW, ++ "edt-ft5x06 wake"); ++ if (error) { ++ dev_err(&client->dev, ++ "Failed to request GPIO %d as wake pin, error %d\n", ++ tsdata->wake_pin, error); ++ return error; ++ } ++ ++ msleep(5); ++ gpio_set_value(tsdata->wake_pin, 1); ++ } ++ if (gpio_is_valid(tsdata->reset_pin)) { + /* this pulls reset down, enabling the low active reset */ +- error = devm_gpio_request_one(&client->dev, reset_pin, +- GPIOF_OUT_INIT_LOW, +- "edt-ft5x06 reset"); ++ error = devm_gpio_request_one(&client->dev, ++ tsdata->reset_pin, GPIOF_OUT_INIT_LOW, ++ "edt-ft5x06 reset"); + if (error) { + dev_err(&client->dev, + "Failed to request GPIO %d as reset pin, error %d\n", +- reset_pin, error); ++ tsdata->reset_pin, error); + return error; + } + +- mdelay(50); +- gpio_set_value(reset_pin, 1); +- mdelay(100); ++ msleep(5); ++ gpio_set_value(tsdata->reset_pin, 1); ++ msleep(300); + } + + return 0; + } + + static int edt_ft5x06_ts_identify(struct i2c_client *client, +- char *model_name, +- char *fw_version) ++ struct edt_ft5x06_ts_data *tsdata, ++ char *fw_version) + { + u8 rdbuf[EDT_NAME_LEN]; + char *p; + int error; ++ char *model_name = tsdata->name; + ++ /* see what we find if we assume it is a M06 * ++ * if we get less than EDT_NAME_LEN, we don't want ++ * to have garbage in there ++ */ ++ memset(rdbuf, 0, sizeof(rdbuf)); + error = edt_ft5x06_ts_readwrite(client, 1, "\xbb", + EDT_NAME_LEN - 1, rdbuf); + if (error) + return error; + +- /* remove last '$' end marker */ +- rdbuf[EDT_NAME_LEN - 1] = '\0'; +- if (rdbuf[EDT_NAME_LEN - 2] == '$') +- rdbuf[EDT_NAME_LEN - 2] = '\0'; +- +- /* look for Model/Version separator */ +- p = strchr(rdbuf, '*'); +- if (p) +- *p++ = '\0'; ++ /* if we find something consistent, stay with that assumption ++ * at least M09 won't send 3 bytes here ++ */ ++ if (!(strnicmp(rdbuf + 1, "EP0", 3))) { ++ tsdata->version = M06; ++ ++ /* remove last '$' end marker */ ++ rdbuf[EDT_NAME_LEN - 1] = '\0'; ++ if (rdbuf[EDT_NAME_LEN - 2] == '$') ++ rdbuf[EDT_NAME_LEN - 2] = '\0'; ++ ++ /* look for Model/Version separator */ ++ p = strchr(rdbuf, '*'); ++ if (p) ++ *p++ = '\0'; ++ strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); ++ strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); ++ } else { ++ /* since there are only two versions around (M06, M09) */ ++ tsdata->version = M09; ++ ++ error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", ++ 2, rdbuf); ++ if (error) ++ return error; ++ ++ strlcpy(fw_version, rdbuf, 2); ++ ++ error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", ++ 1, rdbuf); ++ if (error) ++ return error; + +- strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); +- strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); ++ snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", ++ rdbuf[0] >> 4, rdbuf[0] & 0x0F); ++ } + + return 0; + } +@@ -675,32 +870,108 @@ + pdata->name <= edt_ft5x06_attr_##name.limit_high) \ + edt_ft5x06_register_write(tsdata, reg, pdata->name) + ++#define EDT_GET_PROP(name, reg) { \ ++ u32 val; \ ++ if (of_property_read_u32(np, #name, &val) == 0) \ ++ edt_ft5x06_register_write(tsdata, reg, val); \ ++} ++ ++static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, ++ struct edt_ft5x06_ts_data *tsdata) ++{ ++ struct edt_reg_addr *reg_addr = &tsdata->reg_addr; ++ ++ EDT_GET_PROP(threshold, reg_addr->reg_threshold); ++ EDT_GET_PROP(gain, reg_addr->reg_gain); ++ EDT_GET_PROP(offset, reg_addr->reg_offset); ++ ++ if (of_property_read_bool(np, "invert")) ++ tsdata->invert = true; ++ of_property_read_u32(np, "screen-x", &tsdata->screen_x); ++ of_property_read_u32(np, "screen-y", &tsdata->screen_y); ++} ++ + static void + edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, + const struct edt_ft5x06_platform_data *pdata) + { ++ struct edt_reg_addr *reg_addr = &tsdata->reg_addr; ++ + if (!pdata->use_parameters) + return; + + /* pick up defaults from the platform data */ +- EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD); +- EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN); +- EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET); +- EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE); ++ EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold); ++ EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain); ++ EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset); ++ if (reg_addr->reg_report_rate != NO_REGISTER) ++ EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate); + } + + static void + edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) + { ++ struct edt_reg_addr *reg_addr = &tsdata->reg_addr; ++ + tsdata->threshold = edt_ft5x06_register_read(tsdata, +- WORK_REGISTER_THRESHOLD); +- tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN); +- tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET); +- tsdata->report_rate = edt_ft5x06_register_read(tsdata, +- WORK_REGISTER_REPORT_RATE); +- tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X); +- tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y); ++ reg_addr->reg_threshold); ++ tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); ++ tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); ++ if (reg_addr->reg_report_rate != NO_REGISTER) ++ tsdata->report_rate = edt_ft5x06_register_read(tsdata, ++ reg_addr->reg_report_rate); ++ tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); ++ tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); ++} ++ ++static void ++edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) ++{ ++ struct edt_reg_addr *reg_addr = &tsdata->reg_addr; ++ ++ switch (tsdata->version) { ++ case M06: ++ reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; ++ reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; ++ reg_addr->reg_gain = WORK_REGISTER_GAIN; ++ reg_addr->reg_offset = WORK_REGISTER_OFFSET; ++ reg_addr->reg_num_x = WORK_REGISTER_NUM_X; ++ reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; ++ break; ++ ++ case M09: ++ reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; ++ reg_addr->reg_gain = M09_REGISTER_GAIN; ++ reg_addr->reg_offset = M09_REGISTER_OFFSET; ++ reg_addr->reg_num_x = M09_REGISTER_NUM_X; ++ reg_addr->reg_num_y = M09_REGISTER_NUM_Y; ++ break; ++ } ++} ++ ++#ifdef CONFIG_OF ++static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, ++ struct edt_ft5x06_ts_data *tsdata) ++{ ++ struct device_node *np = dev->of_node; ++ ++ /* ++ * irq_pin is not needed for DT setup. ++ * irq is associated via 'interrupts' property in DT ++ */ ++ tsdata->irq_pin = -EINVAL; ++ tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); ++ tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0); ++ ++ return 0; ++} ++#else ++static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, ++ struct edt_ft5x06_ts_data *tsdata) ++{ ++ return -ENODEV; + } ++#endif + + static int edt_ft5x06_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +@@ -714,32 +985,40 @@ + + dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); + ++ tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); ++ if (!tsdata) { ++ dev_err(&client->dev, "failed to allocate driver data.\n"); ++ return -ENOMEM; ++ } ++ + if (!pdata) { +- dev_err(&client->dev, "no platform data?\n"); +- return -EINVAL; ++ error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata); ++ if (error) { ++ dev_err(&client->dev, ++ "DT probe failed and no platform data present\n"); ++ return error; ++ } ++ } else { ++ tsdata->reset_pin = pdata->reset_pin; ++ tsdata->irq_pin = pdata->irq_pin; ++ tsdata->wake_pin = -EINVAL; + } + +- error = edt_ft5x06_ts_reset(client, pdata->reset_pin); ++ error = edt_ft5x06_ts_reset(client, tsdata); + if (error) + return error; + +- if (gpio_is_valid(pdata->irq_pin)) { +- error = devm_gpio_request_one(&client->dev, pdata->irq_pin, +- GPIOF_IN, "edt-ft5x06 irq"); ++ if (gpio_is_valid(tsdata->irq_pin)) { ++ error = devm_gpio_request_one(&client->dev, tsdata->irq_pin, ++ GPIOF_IN, "edt-ft5x06 irq"); + if (error) { + dev_err(&client->dev, + "Failed to request GPIO %d, error %d\n", +- pdata->irq_pin, error); ++ tsdata->irq_pin, error); + return error; + } + } + +- tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); +- if (!tsdata) { +- dev_err(&client->dev, "failed to allocate driver data.\n"); +- return -ENOMEM; +- } +- + input = devm_input_allocate_device(&client->dev); + if (!input) { + dev_err(&client->dev, "failed to allocate input device.\n"); +@@ -751,18 +1030,30 @@ + tsdata->input = input; + tsdata->factory_mode = false; + +- error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version); ++ error = edt_ft5x06_ts_identify(client, tsdata, fw_version); + if (error) { + dev_err(&client->dev, "touchscreen probe failed\n"); + return error; + } + +- edt_ft5x06_ts_get_defaults(tsdata, pdata); ++ edt_ft5x06_ts_set_regs(tsdata); ++ ++ if (!pdata) ++ edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); ++ else ++ edt_ft5x06_ts_get_defaults(tsdata, pdata); ++ + edt_ft5x06_ts_get_parameters(tsdata); ++ if (!tsdata->screen_x || !tsdata->screen_y) { ++ tsdata->screen_x = tsdata->num_x * 64 - 1; ++ tsdata->screen_y = tsdata->num_y * 64 - 1; ++ } + + dev_dbg(&client->dev, +- "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", +- tsdata->name, fw_version, tsdata->num_x, tsdata->num_y); ++ "Model \"%s\", Rev. \"%s\", %dx%d sensors (%dx%d) %sinverted\n", ++ tsdata->name, fw_version, tsdata->num_x, tsdata->num_y, ++ tsdata->screen_x, tsdata->screen_y, ++ tsdata->invert ? "" : "non"); + + input->name = tsdata->name; + input->id.bustype = BUS_I2C; +@@ -772,12 +1063,12 @@ + __set_bit(EV_KEY, input->evbit); + __set_bit(EV_ABS, input->evbit); + __set_bit(BTN_TOUCH, input->keybit); +- input_set_abs_params(input, ABS_X, 0, tsdata->num_x * 64 - 1, 0, 0); +- input_set_abs_params(input, ABS_Y, 0, tsdata->num_y * 64 - 1, 0, 0); ++ input_set_abs_params(input, ABS_X, 0, tsdata->screen_x - 1, 0, 0); ++ input_set_abs_params(input, ABS_Y, 0, tsdata->screen_y - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, +- 0, tsdata->num_x * 64 - 1, 0, 0); ++ 0, tsdata->screen_x - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, +- 0, tsdata->num_y * 64 - 1, 0, 0); ++ 0, tsdata->screen_y - 1, 0, 0); + error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0); + if (error) { + dev_err(&client->dev, "Unable to init MT slots.\n"); +@@ -787,10 +1078,10 @@ + input_set_drvdata(input, tsdata); + i2c_set_clientdata(client, tsdata); + +- error = devm_request_threaded_irq(&client->dev, client->irq, +- NULL, edt_ft5x06_ts_isr, +- IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- client->name, tsdata); ++ error = devm_request_threaded_irq(&client->dev, client->irq, NULL, ++ edt_ft5x06_ts_isr, ++ IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ client->name, tsdata); + if (error) { + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); + return error; +@@ -801,19 +1092,21 @@ + return error; + + error = input_register_device(input); +- if (error) { +- sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); +- return error; +- } ++ if (error) ++ goto err_remove_attrs; + + edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); + device_init_wakeup(&client->dev, 1); + + dev_dbg(&client->dev, +- "EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n", +- pdata->irq_pin, pdata->reset_pin); ++ "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", ++ client->irq, tsdata->wake_pin, tsdata->reset_pin); + + return 0; ++ ++err_remove_attrs: ++ sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); ++ return error; + } + + static int edt_ft5x06_ts_remove(struct i2c_client *client) +@@ -857,10 +1150,21 @@ + }; + MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); + ++#ifdef CONFIG_OF ++static const struct of_device_id edt_ft5x06_of_match[] = { ++ { .compatible = "edt,edt-ft5206", }, ++ { .compatible = "edt,edt-ft5306", }, ++ { .compatible = "edt,edt-ft5406", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); ++#endif ++ + static struct i2c_driver edt_ft5x06_ts_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "edt_ft5x06", ++ .of_match_table = of_match_ptr(edt_ft5x06_of_match), + .pm = &edt_ft5x06_ts_pm_ops, + }, + .id_table = edt_ft5x06_ts_id, +diff -Nur linux-3.14.72.orig/drivers/input/touchscreen/elan_ts.c linux-3.14.72/drivers/input/touchscreen/elan_ts.c +--- linux-3.14.72.orig/drivers/input/touchscreen/elan_ts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/input/touchscreen/elan_ts.c 2016-06-19 22:11:55.165149193 +0200 +@@ -0,0 +1,472 @@ ++/* ++ * Copyright (C) 2007-2008 HTC Corporation. ++ * ++ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. ++ * ++ * This driver is adapted from elan8232_i2c.c written by Shan-Fu Chiou ++ * and Jay Tu . ++ * This driver is also adapted from the ELAN Touch Screen driver ++ * written by Stanley Zeng ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const char ELAN_TS_NAME[] = "elan-touch"; ++ ++#define ELAN_TS_X_MAX 1088 ++#define ELAN_TS_Y_MAX 768 ++#define ELAN_USER_X_MAX 800 ++#define ELAN_USER_Y_MAX 600 ++#define IDX_PACKET_SIZE 8 ++ ++enum { ++ hello_packet = 0x55, ++ idx_coordinate_packet = 0x5a, ++}; ++ ++enum { ++ idx_finger_state = 7, ++}; ++ ++static struct workqueue_struct *elan_wq; ++ ++static struct elan_data { ++ int intr_gpio; ++ int use_irq; ++ struct hrtimer timer; ++ struct work_struct work; ++ struct i2c_client *client; ++ struct input_dev *input; ++ wait_queue_head_t wait; ++} elan_touch_data; ++ ++/*--------------------------------------------------------------*/ ++static int elan_touch_detect_int_level(void) ++{ ++ int v; ++ v = gpio_get_value(elan_touch_data.intr_gpio); ++ ++ return v; ++} ++ ++static int __elan_touch_poll(struct i2c_client *client) ++{ ++ int status = 0, retry = 20; ++ ++ do { ++ status = elan_touch_detect_int_level(); ++ retry--; ++ mdelay(20); ++ } while (status == 1 && retry > 0); ++ ++ return (status == 0 ? 0 : -ETIMEDOUT); ++} ++ ++static int elan_touch_poll(struct i2c_client *client) ++{ ++ return __elan_touch_poll(client); ++} ++ ++static int __hello_packet_handler(struct i2c_client *client) ++{ ++ int rc; ++ uint8_t buf_recv[4] = { 0 }; ++ ++ rc = elan_touch_poll(client); ++ ++ if (rc < 0) ++ return -EINVAL; ++ ++ rc = i2c_master_recv(client, buf_recv, 4); ++ ++ if (rc != 4) { ++ return rc; ++ } else { ++ int i; ++ pr_info("hello packet: [0x%02x 0x%02x 0x%02x 0x%02x]\n", ++ buf_recv[0], buf_recv[1], buf_recv[2], buf_recv[3]); ++ ++ for (i = 0; i < 4; i++) ++ if (buf_recv[i] != hello_packet) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static inline int elan_touch_parse_xy(uint8_t *data, uint16_t *x, ++ uint16_t *y) ++{ ++ *x = (data[0] & 0xf0); ++ *x <<= 4; ++ *x |= data[1]; ++ if (*x >= ELAN_TS_X_MAX) ++ *x = ELAN_TS_X_MAX; ++ *x = ((((ELAN_TS_X_MAX - ++ *x) * 1000) / ELAN_TS_X_MAX) * ELAN_USER_X_MAX) / 1000; ++ ++ *y = (data[0] & 0x0f); ++ *y <<= 8; ++ *y |= data[2]; ++ if (*y >= ELAN_TS_Y_MAX) ++ *y = ELAN_TS_Y_MAX; ++ *y = ((((ELAN_TS_Y_MAX - ++ *y) * 1000) / ELAN_TS_Y_MAX) * ELAN_USER_Y_MAX) / 1000; ++ ++ return 0; ++} ++ ++/* __elan_touch_init -- hand shaking with touch panel ++ * ++ * 1.recv hello packet ++ */ ++static int __elan_touch_init(struct i2c_client *client) ++{ ++ int rc; ++ rc = __hello_packet_handler(client); ++ if (rc < 0) ++ goto hand_shake_failed; ++ ++hand_shake_failed: ++ return rc; ++} ++ ++static int elan_touch_recv_data(struct i2c_client *client, uint8_t * buf) ++{ ++ int rc, bytes_to_recv = IDX_PACKET_SIZE; ++ ++ if (buf == NULL) ++ return -EINVAL; ++ ++ memset(buf, 0, bytes_to_recv); ++ rc = i2c_master_recv(client, buf, bytes_to_recv); ++ if (rc != bytes_to_recv) ++ return -EINVAL; ++ ++ return rc; ++} ++ ++static void elan_touch_report_data(struct i2c_client *client, uint8_t * buf) ++{ ++ switch (buf[0]) { ++ case idx_coordinate_packet: ++ { ++ uint16_t x1, x2, y1, y2; ++ uint8_t finger_stat; ++ ++ finger_stat = (buf[idx_finger_state] & 0x06) >> 1; ++ ++ if (finger_stat == 0) { ++ input_report_key(elan_touch_data.input, BTN_TOUCH, 0); ++ input_report_key(elan_touch_data.input, BTN_2, 0); ++ } else if (finger_stat == 1) { ++ elan_touch_parse_xy(&buf[1], &x1, &y1); ++ input_report_abs(elan_touch_data.input, ABS_X, x1); ++ input_report_abs(elan_touch_data.input, ABS_Y, y1); ++ input_report_key(elan_touch_data.input, BTN_TOUCH, 1); ++ input_report_key(elan_touch_data.input, BTN_2, 0); ++ } else if (finger_stat == 2) { ++ elan_touch_parse_xy(&buf[1], &x1, &y1); ++ input_report_abs(elan_touch_data.input, ABS_X, x1); ++ input_report_abs(elan_touch_data.input, ABS_Y, y1); ++ input_report_key(elan_touch_data.input, BTN_TOUCH, 1); ++ elan_touch_parse_xy(&buf[4], &x2, &y2); ++ input_report_abs(elan_touch_data.input, ABS_HAT0X, x2); ++ input_report_abs(elan_touch_data.input, ABS_HAT0Y, y2); ++ input_report_key(elan_touch_data.input, BTN_2, 1); ++ } ++ input_sync(elan_touch_data.input); ++ break; ++ } ++ ++ default: ++ break; ++ } ++} ++ ++static void elan_touch_work_func(struct work_struct *work) ++{ ++ int rc; ++ uint8_t buf[IDX_PACKET_SIZE] = { 0 }; ++ struct i2c_client *client = elan_touch_data.client; ++ ++ if (elan_touch_detect_int_level()) ++ return; ++ ++ rc = elan_touch_recv_data(client, buf); ++ if (rc < 0) ++ return; ++ ++ elan_touch_report_data(client, buf); ++} ++ ++static irqreturn_t elan_touch_ts_interrupt(int irq, void *dev_id) ++{ ++ queue_work(elan_wq, &elan_touch_data.work); ++ ++ return IRQ_HANDLED; ++} ++ ++static enum hrtimer_restart elan_touch_timer_func(struct hrtimer *timer) ++{ ++ queue_work(elan_wq, &elan_touch_data.work); ++ hrtimer_start(&elan_touch_data.timer, ktime_set(0, 12500000), ++ HRTIMER_MODE_REL); ++ ++ return HRTIMER_NORESTART; ++} ++ ++static int elan_touch_register_interrupt(struct i2c_client *client) ++{ ++ int err = 0; ++ ++ if (client->irq) { ++ elan_touch_data.use_irq = 1; ++ err = ++ request_irq(client->irq, elan_touch_ts_interrupt, ++ IRQF_TRIGGER_FALLING, ELAN_TS_NAME, ++ &elan_touch_data); ++ ++ if (err < 0) { ++ pr_info("%s(%s): Can't allocate irq %d\n", __FILE__, ++ __func__, client->irq); ++ elan_touch_data.use_irq = 0; ++ } ++ } ++ ++ if (!elan_touch_data.use_irq) { ++ hrtimer_init(&elan_touch_data.timer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ elan_touch_data.timer.function = elan_touch_timer_func; ++ hrtimer_start(&elan_touch_data.timer, ktime_set(1, 0), ++ HRTIMER_MODE_REL); ++ } ++ ++ pr_info("elan ts starts in %s mode.\n", ++ elan_touch_data.use_irq == 1 ? "interrupt" : "polling"); ++ ++ return 0; ++} ++ ++static int elan_touch_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device_node *np = client->dev.of_node; ++ int gpio_elan_cs, gpio_elan_rst, err = 0; ++ ++ if (!np) ++ return -ENODEV; ++ ++ elan_touch_data.intr_gpio = of_get_named_gpio(np, "gpio_intr", 0); ++ if (!gpio_is_valid(elan_touch_data.intr_gpio)) ++ return -ENODEV; ++ ++ err = devm_gpio_request_one(&client->dev, elan_touch_data.intr_gpio, ++ GPIOF_IN, "gpio_elan_intr"); ++ if (err < 0) { ++ dev_err(&client->dev, ++ "request gpio failed: %d\n", err); ++ return err; ++ } ++ ++ /* elan touch init */ ++ gpio_elan_cs = of_get_named_gpio(np, "gpio_elan_cs", 0); ++ if (!gpio_is_valid(gpio_elan_cs)) ++ return -ENODEV; ++ ++ err = devm_gpio_request_one(&client->dev, gpio_elan_cs, ++ GPIOF_OUT_INIT_HIGH, "gpio_elan_cs"); ++ if (err < 0) { ++ dev_err(&client->dev, ++ "request gpio failed: %d\n", err); ++ return err; ++ } ++ gpio_set_value(gpio_elan_cs, 0); ++ ++ gpio_elan_rst = of_get_named_gpio(np, "gpio_elan_rst", 0); ++ if (!gpio_is_valid(gpio_elan_rst)) ++ return -ENODEV; ++ ++ err = devm_gpio_request_one(&client->dev, gpio_elan_rst, ++ GPIOF_OUT_INIT_HIGH, "gpio_elan_rst"); ++ if (err < 0) { ++ dev_err(&client->dev, ++ "request gpio failed: %d\n", err); ++ return err; ++ } ++ gpio_set_value(gpio_elan_rst, 0); ++ msleep(10); ++ gpio_set_value(gpio_elan_rst, 1); ++ ++ gpio_set_value(gpio_elan_cs, 1); ++ msleep(100); ++ ++ elan_wq = create_singlethread_workqueue("elan_wq"); ++ if (!elan_wq) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ elan_touch_data.client = client; ++ strlcpy(client->name, ELAN_TS_NAME, I2C_NAME_SIZE); ++ ++ INIT_WORK(&elan_touch_data.work, elan_touch_work_func); ++ ++ elan_touch_data.input = input_allocate_device(); ++ if (elan_touch_data.input == NULL) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ err = __elan_touch_init(client); ++ if (err < 0) { ++ dev_err(&client->dev, "elan - Read Hello Packet Failed\n"); ++ goto fail; ++ } ++ ++ elan_touch_data.input->name = ELAN_TS_NAME; ++ elan_touch_data.input->id.bustype = BUS_I2C; ++ ++ set_bit(EV_SYN, elan_touch_data.input->evbit); ++ ++ set_bit(EV_KEY, elan_touch_data.input->evbit); ++ set_bit(BTN_TOUCH, elan_touch_data.input->keybit); ++ set_bit(BTN_2, elan_touch_data.input->keybit); ++ ++ set_bit(EV_ABS, elan_touch_data.input->evbit); ++ set_bit(ABS_X, elan_touch_data.input->absbit); ++ set_bit(ABS_Y, elan_touch_data.input->absbit); ++ set_bit(ABS_HAT0X, elan_touch_data.input->absbit); ++ set_bit(ABS_HAT0Y, elan_touch_data.input->absbit); ++ ++ input_set_abs_params(elan_touch_data.input, ABS_X, 0, ELAN_USER_X_MAX, ++ 0, 0); ++ input_set_abs_params(elan_touch_data.input, ABS_Y, 0, ELAN_USER_Y_MAX, ++ 0, 0); ++ input_set_abs_params(elan_touch_data.input, ABS_HAT0X, 0, ++ ELAN_USER_X_MAX, 0, 0); ++ input_set_abs_params(elan_touch_data.input, ABS_HAT0Y, 0, ++ ELAN_USER_Y_MAX, 0, 0); ++ ++ err = input_register_device(elan_touch_data.input); ++ if (err < 0) ++ goto fail; ++ ++ elan_touch_register_interrupt(elan_touch_data.client); ++ ++ return 0; ++ ++fail: ++ input_free_device(elan_touch_data.input); ++ if (elan_wq) ++ destroy_workqueue(elan_wq); ++ return err; ++} ++ ++static int elan_touch_remove(struct i2c_client *client) ++{ ++ if (elan_wq) ++ destroy_workqueue(elan_wq); ++ ++ input_unregister_device(elan_touch_data.input); ++ ++ if (elan_touch_data.use_irq) ++ free_irq(client->irq, client); ++ else ++ hrtimer_cancel(&elan_touch_data.timer); ++ return 0; ++} ++ ++/* -------------------------------------------------------------------- */ ++static const struct i2c_device_id elan_touch_id[] = { ++ {"elan-touch", 0}, ++ {} ++}; ++ ++static const struct of_device_id elan_dt_ids[] = { ++ { ++ .compatible = "elan,elan-touch", ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, elan_dt_ids); ++ ++static int elan_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int elan_resume(struct device *dev) ++{ ++ uint8_t buf[IDX_PACKET_SIZE] = { 0 }; ++ ++ if (0 == elan_touch_detect_int_level()) { ++ dev_dbg(dev, "Got touch during suspend period.\n"); ++ /* ++ * if touch screen during suspend, recv and drop the ++ * data, then touch interrupt pin will return high after ++ * receving data. ++ */ ++ elan_touch_recv_data(elan_touch_data.client, buf); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops elan_dev_pm_ops = { ++ .suspend = elan_suspend, ++ .resume = elan_resume, ++}; ++ ++static struct i2c_driver elan_touch_driver = { ++ .probe = elan_touch_probe, ++ .remove = elan_touch_remove, ++ .id_table = elan_touch_id, ++ .driver = { ++ .name = "elan-touch", ++ .owner = THIS_MODULE, ++ .of_match_table = elan_dt_ids, ++#ifdef CONFIG_PM ++ .pm = &elan_dev_pm_ops, ++#endif ++ }, ++}; ++ ++static int __init elan_touch_init(void) ++{ ++ return i2c_add_driver(&elan_touch_driver); ++} ++ ++static void __exit elan_touch_exit(void) ++{ ++ i2c_del_driver(&elan_touch_driver); ++} ++ ++module_init(elan_touch_init); ++module_exit(elan_touch_exit); ++ ++MODULE_AUTHOR("Stanley Zeng "); ++MODULE_DESCRIPTION("ELAN Touch Screen driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/input/touchscreen/goodix.c linux-3.14.72/drivers/input/touchscreen/goodix.c +--- linux-3.14.72.orig/drivers/input/touchscreen/goodix.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/input/touchscreen/goodix.c 2016-06-19 22:11:55.165149193 +0200 +@@ -0,0 +1,482 @@ ++/* ++ * Driver for Goodix Touchscreens ++ * ++ * Copyright (c) 2014 Red Hat Inc. ++ * ++ * This code is based on gt9xx.c authored by andrew@goodix.com: ++ * ++ * 2010 - 2012 Goodix Technology. ++ */ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; version 2 of the License. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct goodix_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ int abs_x_max; ++ int abs_y_max; ++ unsigned int max_touch_num; ++ unsigned int int_trigger_type; ++ bool invert; ++ bool rotate; ++}; ++ ++#define GOODIX_MAX_HEIGHT 4096 ++#define GOODIX_MAX_WIDTH 4096 ++#define GOODIX_INT_TRIGGER 1 ++#define GOODIX_CONTACT_SIZE 8 ++#define GOODIX_MAX_CONTACTS 10 ++ ++#define GOODIX_CONFIG_MAX_LENGTH 240 ++ ++/* Register defines */ ++#define GOODIX_READ_COOR_ADDR 0x814E ++#define GOODIX_REG_CONFIG_DATA 0x8047 ++#define GOODIX_REG_VERSION 0x8140 ++ ++#define RESOLUTION_LOC 1 ++#define TRIGGER_LOC 6 ++ ++static const unsigned long goodix_irq_flags[] = { ++ IRQ_TYPE_EDGE_RISING, ++ IRQ_TYPE_EDGE_FALLING, ++ IRQ_TYPE_LEVEL_LOW, ++ IRQ_TYPE_LEVEL_HIGH, ++}; ++ ++/** ++ * goodix_i2c_read - read data from a register of the i2c slave device. ++ * ++ * @client: i2c device. ++ * @reg: the register to read from. ++ * @buf: raw write data buffer. ++ * @len: length of the buffer to write ++ */ ++static int goodix_i2c_read(struct i2c_client *client, ++ u16 reg, u8 *buf, int len) ++{ ++ struct i2c_msg msgs[2]; ++ u16 wbuf = cpu_to_be16(reg); ++ int ret; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = (u8 *) &wbuf; ++ ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0); ++} ++ ++static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) ++{ ++ int touch_num; ++ int error; ++ ++ error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, data, ++ GOODIX_CONTACT_SIZE + 1); ++ if (error) { ++ dev_err(&ts->client->dev, "I2C transfer error: %d\n", error); ++ return error; ++ } ++ ++ touch_num = data[0] & 0x0f; ++ if (touch_num > GOODIX_MAX_CONTACTS) ++ return -EPROTO; ++ ++ if (touch_num > 1) { ++ data += 1 + GOODIX_CONTACT_SIZE; ++ error = goodix_i2c_read(ts->client, ++ GOODIX_READ_COOR_ADDR + ++ 1 + GOODIX_CONTACT_SIZE, ++ data, ++ GOODIX_CONTACT_SIZE * (touch_num - 1)); ++ if (error) ++ return error; ++ } ++ ++ return touch_num; ++} ++ ++static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) ++{ ++ int id = coor_data[0] & 0x0F; ++ int input_x = get_unaligned_le16(&coor_data[1]); ++ int input_y = get_unaligned_le16(&coor_data[3]); ++ int input_w = get_unaligned_le16(&coor_data[5]); ++ ++ input_mt_slot(ts->input_dev, id); ++ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); ++ if (ts->invert) { ++ input_x = ts->abs_x_max - input_x; ++ input_y = ts->abs_y_max - input_y; ++ } ++ if (ts->rotate) { ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_x); ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_y); ++ } else { ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x); ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); ++ } ++ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); ++ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); ++} ++ ++/** ++ * goodix_process_events - Process incoming events ++ * ++ * @ts: our goodix_ts_data pointer ++ * ++ * Called when the IRQ is triggered. Read the current device state, and push ++ * the input events to the user space. ++ */ ++static void goodix_process_events(struct goodix_ts_data *ts) ++{ ++ u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; ++ int touch_num; ++ int i; ++ ++ touch_num = goodix_ts_read_input_report(ts, point_data); ++ if (touch_num < 0) ++ return; ++ ++ for (i = 0; i < touch_num; i++) ++ goodix_ts_report_touch(ts, ++ &point_data[1 + GOODIX_CONTACT_SIZE * i]); ++ ++ input_mt_sync_frame(ts->input_dev); ++ input_sync(ts->input_dev); ++} ++ ++/** ++ * goodix_ts_irq_handler - The IRQ handler ++ * ++ * @irq: interrupt number. ++ * @dev_id: private data pointer. ++ */ ++static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) ++{ ++ static const u8 end_cmd[] = { ++ GOODIX_READ_COOR_ADDR >> 8, ++ GOODIX_READ_COOR_ADDR & 0xff, ++ 0 ++ }; ++ struct goodix_ts_data *ts = dev_id; ++ ++ goodix_process_events(ts); ++ ++ if (i2c_master_send(ts->client, end_cmd, sizeof(end_cmd)) < 0) ++ dev_err(&ts->client->dev, "I2C write end_cmd error\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * goodix_read_config - Read the embedded configuration of the panel ++ * ++ * @ts: our goodix_ts_data pointer ++ * ++ * Must be called during probe ++ */ ++static void goodix_read_config(struct goodix_ts_data *ts) ++{ ++ u8 config[GOODIX_CONFIG_MAX_LENGTH]; ++ int error; ++ ++ error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, ++ config, ++ GOODIX_CONFIG_MAX_LENGTH); ++ if (error) { ++ dev_warn(&ts->client->dev, ++ "Error reading config (%d), using defaults\n", ++ error); ++ ts->abs_x_max = GOODIX_MAX_WIDTH; ++ ts->abs_y_max = GOODIX_MAX_HEIGHT; ++ ts->int_trigger_type = GOODIX_INT_TRIGGER; ++ return; ++ } ++ ++ if (ts->rotate) { ++ ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]); ++ ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC]); ++ } else { ++ ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]); ++ ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]); ++ } ++ ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; ++ if (!ts->abs_x_max || !ts->abs_y_max) { ++ dev_err(&ts->client->dev, ++ "Invalid config, using defaults\n"); ++ ts->abs_x_max = GOODIX_MAX_WIDTH; ++ ts->abs_y_max = GOODIX_MAX_HEIGHT; ++ } ++} ++ ++ ++/** ++ * goodix_read_version - Read goodix touchscreen version ++ * ++ * @client: the i2c client ++ * @version: output buffer containing the version on success ++ */ ++static int goodix_read_version(struct i2c_client *client, u16 *version) ++{ ++ int error; ++ u8 buf[6]; ++ ++ error = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf)); ++ if (error) { ++ dev_err(&client->dev, "read version failed: %d\n", error); ++ return error; ++ } ++ ++ if (version) ++ *version = get_unaligned_le16(&buf[4]); ++ ++ dev_info(&client->dev, "IC VERSION: %6ph\n", buf); ++ ++ return 0; ++} ++ ++/** ++ * goodix_i2c_test - I2C test function to check if the device answers. ++ * ++ * @client: the i2c client ++ */ ++static int goodix_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int error; ++ u8 test; ++ ++ while (retry++ < 2) { ++ error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA, ++ &test, 1); ++ if (!error) ++ return 0; ++ ++ dev_err(&client->dev, "i2c test failed attempt %d: %d\n", ++ retry, error); ++ msleep(20); ++ } ++ ++ return error; ++} ++ ++/** ++ * goodix_request_input_dev - Allocate, populate and register the input device ++ * ++ * @ts: our goodix_ts_data pointer ++ * ++ * Must be called during probe ++ */ ++static int goodix_request_input_dev(struct goodix_ts_data *ts) ++{ ++ int error; ++ ++ ts->input_dev = devm_input_allocate_device(&ts->client->dev); ++ if (!ts->input_dev) { ++ dev_err(&ts->client->dev, "Failed to allocate input device."); ++ return -ENOMEM; ++ } ++ ++ ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | ++ BIT_MASK(EV_KEY) | ++ BIT_MASK(EV_ABS); ++ ++ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ++ ts->abs_x_max, 0, 0); ++ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ++ ts->abs_y_max, 0, 0); ++ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); ++ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); ++ ++ input_mt_init_slots(ts->input_dev, GOODIX_MAX_CONTACTS, ++ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); ++ ++ ts->input_dev->name = "Goodix Capacitive TouchScreen"; ++ ts->input_dev->phys = "input/ts"; ++ ts->input_dev->id.bustype = BUS_I2C; ++ ts->input_dev->id.vendor = 0x0416; ++ ts->input_dev->id.product = 0x1001; ++ ts->input_dev->id.version = 10427; ++ ++ error = input_register_device(ts->input_dev); ++ if (error) { ++ dev_err(&ts->client->dev, ++ "Failed to register input device: %d", error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int goodix_ts_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct goodix_ts_data *ts; ++ unsigned long irq_flags; ++ int error; ++ u16 version_info; ++#ifdef CONFIG_OF ++ int reset_pin; ++ int int_pin; ++ struct device_node *np = client->dev.of_node; ++#endif ++ ++ dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ dev_err(&client->dev, "I2C check functionality failed.\n"); ++ return -ENXIO; ++ } ++ ++ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ ++#ifdef CONFIG_OF ++ /* ++ * The GT9110 requires that INT be driven low by the host for 50ms ++ * after sampling the state of INT to determine its slave address. ++ * If reset-gpio and int-gpio are provided in the device-tree, perform ++ * this init sequence. ++ */ ++ reset_pin = of_get_named_gpio(np, "reset-gpio", 0); ++ int_pin = of_get_named_gpio(np, "int-gpio", 0); ++ if (gpio_is_valid(reset_pin) && gpio_is_valid(int_pin)) { ++ int int_val = (client->addr == 0x14) ? ++ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ ++ error = devm_gpio_request_one(&client->dev, ++ reset_pin, GPIOF_OUT_INIT_LOW, ++ "gtxx reset"); ++ if (error) { ++ dev_err(&client->dev, ++ "Failed to request gpio%d reset pin: %d\n", ++ reset_pin, error); ++ return error; ++ } ++ error = devm_gpio_request_one(&client->dev, ++ int_pin, int_val, "gtxx int"); ++ if (error) { ++ dev_err(&client->dev, ++ "Failed to request gpio%d int pin: %d\n", ++ int_pin, error); ++ return error; ++ } ++ ++ msleep(5); ++ gpio_set_value(reset_pin, 1); ++ msleep(5); ++ gpio_set_value(int_pin, 0); ++ msleep(50); ++ gpio_direction_input(int_pin); ++ ++ dev_info(&client->dev, "Performed init sequence using " ++ "gpio%d/gpio%d as RST#/INT\n", reset_pin, int_pin); ++ } ++ ++ if (of_property_read_bool(np, "invert")) ++ ts->invert = true; ++ if (of_property_read_bool(np, "rotate")) ++ ts->rotate = true; ++#endif ++ ++ ts->client = client; ++ i2c_set_clientdata(client, ts); ++ ++ error = goodix_i2c_test(client); ++ if (error) { ++ dev_err(&client->dev, "I2C communication failure: %d\n", error); ++ return error; ++ } ++ ++ error = goodix_read_version(client, &version_info); ++ if (error) { ++ dev_err(&client->dev, "Read version failed.\n"); ++ return error; ++ } ++ ++ goodix_read_config(ts); ++ ++ error = goodix_request_input_dev(ts); ++ if (error) ++ return error; ++ ++ irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT; ++ error = devm_request_threaded_irq(&ts->client->dev, client->irq, ++ NULL, goodix_ts_irq_handler, ++ irq_flags, client->name, ts); ++ if (error) { ++ dev_err(&client->dev, "request IRQ failed: %d\n", error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static const struct i2c_device_id goodix_ts_id[] = { ++ { "GDIX1001:00", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, goodix_ts_id); ++ ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id goodix_acpi_match[] = { ++ { "GDIX1001", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); ++#endif ++ ++#ifdef CONFIG_OF ++static const struct of_device_id goodix_of_match[] = { ++ { .compatible = "gdx,gt9xx", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, goodix_of_match); ++#endif ++ ++static struct i2c_driver goodix_ts_driver = { ++ .probe = goodix_ts_probe, ++ .id_table = goodix_ts_id, ++ .driver = { ++ .name = "Goodix-TS", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_ACPI ++ .acpi_match_table = goodix_acpi_match, ++#endif ++#ifdef CONFIG_OF ++ .of_match_table = of_match_ptr(goodix_of_match), ++#endif ++ }, ++}; ++module_i2c_driver(goodix_ts_driver); ++ ++MODULE_AUTHOR("Benjamin Tissoires "); ++MODULE_AUTHOR("Bastien Nocera "); ++MODULE_DESCRIPTION("Goodix touchscreen driver"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.14.72.orig/drivers/input/touchscreen/Kconfig linux-3.14.72/drivers/input/touchscreen/Kconfig +--- linux-3.14.72.orig/drivers/input/touchscreen/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/touchscreen/Kconfig 2016-06-19 22:11:55.165149193 +0200 +@@ -265,6 +265,18 @@ + To compile this driver as a module, choose M here: the + module will be called egalax_ts. + ++config TOUCHSCREEN_ELAN ++ tristate "ELAN touchscreen input driver" ++ depends on I2C ++ help ++ Say Y here if you have an I2C ELAN touchscreen ++ attached. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called elan-touch. ++ + config TOUCHSCREEN_FUJITSU + tristate "Fujitsu serial touchscreen" + select SERIO +@@ -278,6 +290,19 @@ + To compile this driver as a module, choose M here: the + module will be called fujitsu-ts. + ++config TOUCHSCREEN_GOODIX ++ tristate "Goodix I2C touchscreen" ++ depends on I2C ++ help ++ Say Y here if you have the Goodix touchscreen (such as one ++ installed in Onda v975w tablets) connected to your ++ system. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called goodix. ++ + config TOUCHSCREEN_ILI210X + tristate "Ilitek ILI210X based touchscreen" + depends on I2C +diff -Nur linux-3.14.72.orig/drivers/input/touchscreen/Makefile linux-3.14.72/drivers/input/touchscreen/Makefile +--- linux-3.14.72.orig/drivers/input/touchscreen/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/touchscreen/Makefile 2016-06-19 22:11:55.165149193 +0200 +@@ -31,6 +31,7 @@ + obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o + obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o + obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o ++obj-$(CONFIG_TOUCHSCREEN_ELAN) += elan_ts.o + obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o + obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o + obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o +diff -Nur linux-3.14.72.orig/drivers/input/touchscreen/max11801_ts.c linux-3.14.72/drivers/input/touchscreen/max11801_ts.c +--- linux-3.14.72.orig/drivers/input/touchscreen/max11801_ts.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/input/touchscreen/max11801_ts.c 2016-06-19 22:11:55.165149193 +0200 +@@ -2,7 +2,7 @@ + * Driver for MAXI MAX11801 - A Resistive touch screen controller with + * i2c interface + * +- * Copyright (C) 2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. + * Author: Zhang Jiejing + * + * Based on mcs5000_ts.c +@@ -38,6 +38,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + + /* Register Address define */ + #define GENERNAL_STATUS_REG 0x00 +@@ -53,13 +57,30 @@ + #define AUX_MESURE_CONF_REG 0x0a + #define OP_MODE_CONF_REG 0x0b + ++#define Panel_Setup_X (0x69 << 1) ++#define Panel_Setup_Y (0x6b << 1) ++ ++#define XY_combined_measurement (0x70 << 1) ++#define X_measurement (0x78 << 1) ++#define Y_measurement (0x7a << 1) ++#define AUX_measurement (0x76 << 1) ++ + /* FIFO is found only in max11800 and max11801 */ + #define FIFO_RD_CMD (0x50 << 1) + #define MAX11801_FIFO_INT (1 << 2) + #define MAX11801_FIFO_OVERFLOW (1 << 3) ++#define MAX11801_EDGE_INT (1 << 1) ++ ++#define FIFO_RD_X_MSB (0x52 << 1) ++#define FIFO_RD_X_LSB (0x53 << 1) ++#define FIFO_RD_Y_MSB (0x54 << 1) ++#define FIFO_RD_Y_LSB (0x55 << 1) ++#define FIFO_RD_AUX_MSB (0x5a << 1) ++#define FIFO_RD_AUX_LSB (0x5b << 1) + + #define XY_BUFSIZE 4 + #define XY_BUF_OFFSET 4 ++#define AUX_BUFSIZE 2 + + #define MAX11801_MAX_X 0xfff + #define MAX11801_MAX_Y 0xfff +@@ -84,6 +105,64 @@ + struct input_dev *input_dev; + }; + ++static struct i2c_client *max11801_client; ++static unsigned int max11801_workmode; ++static u8 aux_buf[AUX_BUFSIZE]; ++ ++static int max11801_dcm_write_command(struct i2c_client *client, int command) ++{ ++ return i2c_smbus_write_byte(client, command); ++} ++ ++static u32 max11801_dcm_sample_aux(struct i2c_client *client) ++{ ++ int ret; ++ int aux = 0; ++ u32 sample_data; ++ ++ /* AUX_measurement */ ++ max11801_dcm_write_command(client, AUX_measurement); ++ mdelay(5); ++ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_MSB, ++ 1, &aux_buf[0]); ++ if (ret < 1) { ++ dev_err(&client->dev, "FIFO_RD_AUX_MSB read fails\n"); ++ return ret; ++ } ++ mdelay(5); ++ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_LSB, ++ 1, &aux_buf[1]); ++ if (ret < 1) { ++ dev_err(&client->dev, "FIFO_RD_AUX_LSB read fails\n"); ++ return ret; ++ } ++ ++ aux = (aux_buf[0] << 4) + (aux_buf[1] >> 4); ++ /* ++ * voltage = (9170*aux)/7371; ++ * voltage is (26.2*3150*aux)/(16.2*0xFFF) ++ * V(aux)=3150*sample/0xFFF,V(battery)=212*V(aux)/81 ++ * sample_data = (14840*aux)/7371-1541; ++ */ ++ sample_data = (14840 * aux) / 7371; ++ ++ return sample_data; ++} ++ ++u32 max11801_read_adc(void) ++{ ++ u32 adc_data; ++ ++ if (!max11801_client) { ++ pr_err("FAIL max11801_client not initialize\n"); ++ return -1; ++ } ++ adc_data = max11801_dcm_sample_aux(max11801_client); ++ ++ return adc_data; ++} ++EXPORT_SYMBOL_GPL(max11801_read_adc); ++ + static u8 read_register(struct i2c_client *client, int addr) + { + /* XXX: The chip ignores LSB of register address */ +@@ -104,29 +183,62 @@ + u8 buf[XY_BUFSIZE]; + int x = -1; + int y = -1; ++ u8 command = FIFO_RD_X_MSB; + + status = read_register(data->client, GENERNAL_STATUS_REG); +- +- if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) { ++ if ((!max11801_workmode && (status & (MAX11801_FIFO_INT | ++ MAX11801_FIFO_OVERFLOW))) || (max11801_workmode && (status & ++ MAX11801_EDGE_INT))) { + status = read_register(data->client, GENERNAL_STATUS_REG); ++ if (!max11801_workmode) { ++ /* ACM mode */ ++ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD, ++ XY_BUFSIZE, buf); ++ /* ++ * We should get 4 bytes buffer that contains X,Y ++ * and event tag ++ */ ++ if (ret < XY_BUFSIZE) ++ goto out; ++ } else { ++ /* DCM mode */ ++ /* X = panel setup */ ++ max11801_dcm_write_command(client, Panel_Setup_X); ++ /* X_measurement */ ++ max11801_dcm_write_command(client, X_measurement); ++ for (i = 0; i < 2; i++) { ++ ret = i2c_smbus_read_i2c_block_data(client, ++ command, 1, &buf[i]); ++ if (ret < 1) ++ goto out; ++ ++ command = FIFO_RD_X_LSB; ++ } ++ ++ /* Y = panel setup */ ++ max11801_dcm_write_command(client, Panel_Setup_Y); ++ /* Y_measurement */ ++ max11801_dcm_write_command(client, Y_measurement); ++ command = FIFO_RD_Y_MSB; ++ for (i = 2; i < XY_BUFSIZE; i++) { ++ ret = i2c_smbus_read_i2c_block_data(client, ++ command, 1, &buf[i]); ++ if (ret < 1) ++ goto out; + +- ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD, +- XY_BUFSIZE, buf); +- +- /* +- * We should get 4 bytes buffer that contains X,Y +- * and event tag +- */ +- if (ret < XY_BUFSIZE) +- goto out; ++ command = FIFO_RD_Y_LSB; ++ } ++ } + + for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) { +- if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG) ++ if ((buf[i + 1] & MEASURE_TAG_MASK) == ++ MEASURE_X_TAG) + x = (buf[i] << XY_BUF_OFFSET) + +- (buf[i + 1] >> XY_BUF_OFFSET); +- else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG) ++ (buf[i + 1] >> XY_BUF_OFFSET); ++ else if ((buf[i + 1] & MEASURE_TAG_MASK) == ++ MEASURE_Y_TAG) + y = (buf[i] << XY_BUF_OFFSET) + +- (buf[i + 1] >> XY_BUF_OFFSET); ++ (buf[i + 1] >> XY_BUF_OFFSET); + } + + if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK)) +@@ -137,18 +249,17 @@ + /* fall through */ + case EVENT_MIDDLE: + input_report_abs(data->input_dev, ABS_X, x); ++ y = MAX11801_MAX_Y - y; /* Calibration */ + input_report_abs(data->input_dev, ABS_Y, y); + input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1); + input_sync(data->input_dev); + break; +- + case EVENT_RELEASE: + input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0); + input_sync(data->input_dev); + break; +- + case EVENT_FIFO_END: +- break; ++ break; + } + } + out: +@@ -159,18 +270,37 @@ + { + struct i2c_client *client = data->client; + +- /* Average X,Y, take 16 samples, average eight media sample */ ++ max11801_client = client; ++ /* Average X,Y, take 16 samples average eight media sample */ + max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff); + /* X,Y panel setup time set to 20us */ + max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11); +- /* Rough pullup time (2uS), Fine pullup time (10us) */ ++ /* Rough pullup time (2uS), Fine pullup time (10us) */ + max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10); +- /* Auto mode init period = 5ms , scan period = 5ms*/ ++ /* Auto mode init period = 5ms, scan period = 5ms */ + max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa); + /* Aperture X,Y set to +- 4LSB */ + max11801_write_reg(client, APERTURE_CONF_REG, 0x33); +- /* Enable Power, enable Automode, enable Aperture, enable Average X,Y */ +- max11801_write_reg(client, OP_MODE_CONF_REG, 0x36); ++ /* ++ * Enable Power, enable Automode, enable Aperture, ++ * enable Average X,Y ++ */ ++ if (!max11801_workmode) ++ max11801_write_reg(client, OP_MODE_CONF_REG, 0x36); ++ else { ++ max11801_write_reg(client, OP_MODE_CONF_REG, 0x16); ++ /* ++ * Delay initial=1ms, Sampling time 2us ++ * Averaging sample depth 2 ++ * samples, Resolution 12bit ++ */ ++ max11801_write_reg(client, AUX_MESURE_CONF_REG, 0x76); ++ /* ++ * Use edge interrupt with ++ * direct conversion mode ++ */ ++ max11801_write_reg(client, GENERNAL_CONF_REG, 0xf3); ++ } + } + + static int max11801_ts_probe(struct i2c_client *client, +@@ -179,6 +309,7 @@ + struct max11801_data *data; + struct input_dev *input_dev; + int error; ++ struct device_node *of_node = client->dev.of_node; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + input_dev = devm_input_allocate_device(&client->dev); +@@ -201,6 +332,9 @@ + input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0); + input_set_drvdata(input_dev, data); + ++ if (of_property_read_u32(of_node, "work-mode", &max11801_workmode)) ++ max11801_workmode = *(int *)(client->dev).platform_data; ++ + max11801_ts_phy_init(data); + + error = devm_request_threaded_irq(&client->dev, client->irq, NULL, +@@ -226,10 +360,17 @@ + }; + MODULE_DEVICE_TABLE(i2c, max11801_ts_id); + ++static const struct of_device_id max11801_ts_dt_ids[] = { ++ { .compatible = "maxim,max11801", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, max11801_ts_dt_ids); ++ + static struct i2c_driver max11801_ts_driver = { + .driver = { + .name = "max11801_ts", + .owner = THIS_MODULE, ++ .of_match_table = max11801_ts_dt_ids, + }, + .id_table = max11801_ts_id, + .probe = max11801_ts_probe, +diff -Nur linux-3.14.72.orig/drivers/irqchip/irq-gic.c linux-3.14.72/drivers/irqchip/irq-gic.c +--- linux-3.14.72.orig/drivers/irqchip/irq-gic.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/irqchip/irq-gic.c 2016-06-19 22:11:55.169148931 +0200 +@@ -74,6 +74,27 @@ + static DEFINE_RAW_SPINLOCK(irq_controller_lock); + + /* ++ * This lock is used by the big.LITTLE migration code to ensure no IPIs ++ * can be pended on the old core after the map has been updated. ++ */ ++#ifdef CONFIG_BL_SWITCHER ++static DEFINE_RAW_SPINLOCK(cpu_map_migration_lock); ++ ++static inline void gic_migration_lock(unsigned long *flags) ++{ ++ raw_spin_lock_irqsave(&cpu_map_migration_lock, *flags); ++} ++ ++static inline void gic_migration_unlock(unsigned long flags) ++{ ++ raw_spin_unlock_irqrestore(&cpu_map_migration_lock, flags); ++} ++#else ++static inline void gic_migration_lock(unsigned long *flags) {} ++static inline void gic_migration_unlock(unsigned long flags) {} ++#endif ++ ++/* + * The GIC mapping of CPU interfaces does not necessarily match + * the logical CPU numbering. Let's use a mapping as returned + * by the GIC itself. +@@ -658,7 +679,7 @@ + int cpu; + unsigned long flags, map = 0; + +- raw_spin_lock_irqsave(&irq_controller_lock, flags); ++ gic_migration_lock(&flags); + + /* Convert our logical CPU mask into a physical one. */ + for_each_cpu(cpu, mask) +@@ -673,7 +694,7 @@ + /* this always happens on GIC0 */ + writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); + +- raw_spin_unlock_irqrestore(&irq_controller_lock, flags); ++ gic_migration_unlock(flags); + } + #endif + +@@ -744,8 +765,17 @@ + + raw_spin_lock(&irq_controller_lock); + +- /* Update the target interface for this logical CPU */ ++ /* ++ * Update the target interface for this logical CPU ++ * ++ * From the point we release the cpu_map_migration_lock any new ++ * SGIs will be pended on the new cpu which makes the set of SGIs ++ * pending on the old cpu static. That means we can defer the ++ * migration until after we have released the irq_controller_lock. ++ */ ++ raw_spin_lock(&cpu_map_migration_lock); + gic_cpu_map[cpu] = 1 << new_cpu_id; ++ raw_spin_unlock(&cpu_map_migration_lock); + + /* + * Find all the peripheral interrupts targetting the current +diff -Nur linux-3.14.72.orig/drivers/Kconfig linux-3.14.72/drivers/Kconfig +--- linux-3.14.72.orig/drivers/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/Kconfig 2016-06-19 22:11:55.169148931 +0200 +@@ -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.72.orig/drivers/leds/leds-gpio.c linux-3.14.72/drivers/leds/leds-gpio.c +--- linux-3.14.72.orig/drivers/leds/leds-gpio.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/leds/leds-gpio.c 2016-06-19 22:11:55.169148931 +0200 +@@ -204,6 +204,9 @@ + 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); + if (ret < 0) { +diff -Nur linux-3.14.72.orig/drivers/leds/leds-pwm.c linux-3.14.72/drivers/leds/leds-pwm.c +--- linux-3.14.72.orig/drivers/leds/leds-pwm.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/leds/leds-pwm.c 2016-06-19 22:11:55.169148931 +0200 +@@ -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) +@@ -117,6 +121,7 @@ + + led_dat->cdev.default_trigger = of_get_property(child, + "linux,default-trigger", NULL); ++ led_dat->active_low = of_property_read_bool(child, "active-low"); + of_property_read_u32(child, "max-brightness", + &led_dat->cdev.max_brightness); + +diff -Nur linux-3.14.72.orig/drivers/Makefile linux-3.14.72/drivers/Makefile +--- linux-3.14.72.orig/drivers/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/Makefile 2016-06-19 22:11:55.169148931 +0200 +@@ -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.72.orig/drivers/media/i2c/Kconfig linux-3.14.72/drivers/media/i2c/Kconfig +--- linux-3.14.72.orig/drivers/media/i2c/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/i2c/Kconfig 2016-06-19 22:11:55.169148931 +0200 +@@ -293,6 +293,19 @@ + To compile this driver as a module, choose M here: the + module will be called saa7191. + ++config VIDEO_TC358743 ++ tristate "Toshiba TC358743 decoder" ++ depends on VIDEO_V4L2 && I2C ++ select MEDIA_CONTROLLER ++ ---help--- ++ Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge ++ ++ This is a Analog Devices Component/Graphics Digitizer ++ with 4:1 Multiplexed HDMI Receiver. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called tc358743. ++ + config VIDEO_TVP514X + tristate "Texas Instruments TVP514x video decoder" + depends on VIDEO_V4L2 && I2C +diff -Nur linux-3.14.72.orig/drivers/media/i2c/Makefile linux-3.14.72/drivers/media/i2c/Makefile +--- linux-3.14.72.orig/drivers/media/i2c/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/i2c/Makefile 2016-06-19 22:11:55.169148931 +0200 +@@ -76,3 +76,4 @@ + obj-$(CONFIG_VIDEO_AK881X) += ak881x.o + obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o + obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o ++obj-$(CONFIG_VIDEO_TC358743) += tc358743.o +diff -Nur linux-3.14.72.orig/drivers/media/i2c/tc358743.c linux-3.14.72/drivers/media/i2c/tc358743.c +--- linux-3.14.72.orig/drivers/media/i2c/tc358743.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/i2c/tc358743.c 2016-06-19 22:11:55.169148931 +0200 +@@ -0,0 +1,1972 @@ ++/* ++ * tc358743 - Toshiba HDMI to CSI-2 bridge ++ * ++ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights ++ * reserved. ++ * ++ * This program is free software; you may redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * 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 THE AUTHORS OR COPYRIGHT HOLDERS ++ * 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. ++ * ++ */ ++ ++/* ++ * References (c = chapter, p = page): ++ * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 ++ * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tc358743_regs.h" ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "debug level (0-3)"); ++ ++MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); ++MODULE_AUTHOR("Ramakrishnan Muthukrishnan "); ++MODULE_AUTHOR("Mikhail Khelik "); ++MODULE_AUTHOR("Mats Randgaard "); ++MODULE_LICENSE("GPL"); ++ ++static const struct v4l2_dv_timings_cap tc358743_timings_cap = { ++ .type = V4L2_DV_BT_656_1120, ++ /* keep this initialization for compatibility with GCC < 4.4.6 */ ++ .reserved = { 0 }, ++ /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ ++ V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000, ++ V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | ++ V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, ++ V4L2_DV_BT_CAP_PROGRESSIVE | ++ V4L2_DV_BT_CAP_REDUCED_BLANKING | ++ V4L2_DV_BT_CAP_CUSTOM) ++}; ++ ++struct tc358743_state { ++ struct tc358743_platform_data pdata; ++ struct v4l2_of_bus_mipi_csi2 bus; ++ struct v4l2_subdev sd; ++ struct media_pad pad; ++ struct v4l2_ctrl_handler hdl; ++ struct i2c_client *i2c_client; ++ ++ /* controls */ ++ struct v4l2_ctrl *detect_tx_5v_ctrl; ++ struct v4l2_ctrl *audio_sampling_rate_ctrl; ++ struct v4l2_ctrl *audio_present_ctrl; ++ ++ /* work queues */ ++ struct workqueue_struct *work_queues; ++ struct delayed_work delayed_work_enable_hotplug; ++ ++ /* edid */ ++ bool edid_written; ++ ++ struct v4l2_dv_timings timings; ++ u32 mbus_fmt_code; ++ ++ struct gpio_desc *reset_gpio; ++}; ++ ++static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct tc358743_state, sd); ++} ++ ++/* --------------- I2C --------------- */ ++ ++static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct i2c_client *client = state->i2c_client; ++ int err; ++ u8 buf[2] = { reg >> 8, reg & 0xff }; ++ struct i2c_msg msgs[] = { ++ { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = n, ++ .buf = values, ++ }, ++ }; ++ ++ err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (err != ARRAY_SIZE(msgs)) { ++ v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", ++ __func__, reg, client->addr); ++ } ++} ++ ++static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct i2c_client *client = state->i2c_client; ++ int err, i; ++ struct i2c_msg msg; ++ u8 data[2 + n]; ++ ++ msg.addr = client->addr; ++ msg.buf = data; ++ msg.len = 2 + n; ++ msg.flags = 0; ++ ++ data[0] = reg >> 8; ++ data[1] = reg & 0xff; ++ ++ for (i = 0; i < n; i++) ++ data[2 + i] = values[i]; ++ ++ err = i2c_transfer(client->adapter, &msg, 1); ++ if (err != 1) { ++ v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", ++ __func__, reg, client->addr); ++ return; ++ } ++ ++ if (debug < 3) ++ return; ++ ++ switch (n) { ++ case 1: ++ v4l2_info(sd, "I2C write 0x%04x = 0x%02x", ++ reg, data[2]); ++ break; ++ case 2: ++ v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", ++ reg, data[3], data[2]); ++ break; ++ case 4: ++ v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", ++ reg, data[5], data[4], data[3], data[2]); ++ break; ++ default: ++ v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n", ++ n, reg); ++ } ++} ++ ++static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) ++{ ++ u8 val; ++ ++ i2c_rd(sd, reg, &val, 1); ++ ++ return val; ++} ++ ++static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) ++{ ++ i2c_wr(sd, reg, &val, 1); ++} ++ ++static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, ++ u8 mask, u8 val) ++{ ++ i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); ++} ++ ++static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) ++{ ++ u16 val; ++ ++ i2c_rd(sd, reg, (u8 *)&val, 2); ++ ++ return val; ++} ++ ++static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) ++{ ++ i2c_wr(sd, reg, (u8 *)&val, 2); ++} ++ ++static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) ++{ ++ i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); ++} ++ ++static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) ++{ ++ u32 val; ++ ++ i2c_rd(sd, reg, (u8 *)&val, 4); ++ ++ return val; ++} ++ ++static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) ++{ ++ i2c_wr(sd, reg, (u8 *)&val, 4); ++} ++ ++/* --------------- STATUS --------------- */ ++ ++static inline bool is_hdmi(struct v4l2_subdev *sd) ++{ ++ return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI; ++} ++ ++static inline bool tx_5v_power_present(struct v4l2_subdev *sd) ++{ ++ return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V; ++} ++ ++static inline bool no_signal(struct v4l2_subdev *sd) ++{ ++ return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS); ++} ++ ++static inline bool no_sync(struct v4l2_subdev *sd) ++{ ++ return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC); ++} ++ ++static inline bool audio_present(struct v4l2_subdev *sd) ++{ ++ return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE; ++} ++ ++static int get_audio_sampling_rate(struct v4l2_subdev *sd) ++{ ++ static const int code_to_rate[] = { ++ 44100, 0, 48000, 32000, 22050, 384000, 24000, 352800, ++ 88200, 768000, 96000, 705600, 176400, 0, 192000, 0 ++ }; ++ ++ /* Register FS_SET is not cleared when the cable is disconnected */ ++ if (no_signal(sd)) ++ return 0; ++ ++ return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]; ++} ++ ++static unsigned tc358743_num_csi_lanes_in_use(struct v4l2_subdev *sd) ++{ ++ return ((i2c_rd32(sd, CSI_CONTROL) & MASK_NOL) >> 1) + 1; ++} ++ ++/* --------------- TIMINGS --------------- */ ++ ++static inline unsigned fps(const struct v4l2_bt_timings *t) ++{ ++ if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t)) ++ return 0; ++ ++ return DIV_ROUND_CLOSEST((unsigned)t->pixelclock, ++ V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t)); ++} ++ ++static int tc358743_get_detected_timings(struct v4l2_subdev *sd, ++ struct v4l2_dv_timings *timings) ++{ ++ struct v4l2_bt_timings *bt = &timings->bt; ++ unsigned width, height, frame_width, frame_height, frame_interval, fps; ++ ++ memset(timings, 0, sizeof(struct v4l2_dv_timings)); ++ ++ if (no_signal(sd)) { ++ v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); ++ return -ENOLINK; ++ } ++ if (no_sync(sd)) ++ v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__); ++ ++ timings->type = V4L2_DV_BT_656_1120; ++ bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ? ++ V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; ++ ++ width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) + ++ i2c_rd8(sd, DE_WIDTH_H_LO); ++ height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) + ++ i2c_rd8(sd, DE_WIDTH_V_LO); ++ frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) + ++ i2c_rd8(sd, H_SIZE_LO); ++ frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) + ++ i2c_rd8(sd, V_SIZE_LO)) / 2; ++ /* frame interval in milliseconds * 10 ++ * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */ ++ frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) + ++ i2c_rd8(sd, FV_CNT_LO); ++ fps = (frame_interval > 0) ? ++ DIV_ROUND_CLOSEST(10000, frame_interval) : 0; ++ ++ bt->width = width; ++ bt->height = height; ++ bt->vsync = frame_height - height; ++ bt->hsync = frame_width - width; ++ bt->pixelclock = frame_width * frame_height * fps; ++ ++ return 0; ++} ++ ++/* --------------- HOTPLUG / HDCP / EDID --------------- */ ++ ++static void tc358743_delayed_work_enable_hotplug(struct work_struct *work) ++{ ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct tc358743_state *state = container_of(dwork, ++ struct tc358743_state, delayed_work_enable_hotplug); ++ struct v4l2_subdev *sd = &state->sd; ++ ++ v4l2_dbg(2, debug, sd, "%s:\n", __func__); ++ ++ i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0); ++} ++ ++static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable) ++{ ++ v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? ++ "enable" : "disable"); ++ ++ i2c_wr8_and_or(sd, HDCP_REG1, ++ ~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH), ++ MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO); ++ ++ i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET, ++ SET_AUTO_P3_RESET_FRAMES(0x0f)); ++ ++ /* HDCP is disabled by configuring the receiver as HDCP repeater. ++ * The repeater mode require software support to work, so ++ * HDCP authentication will fail. Set Ready and MAX_EXCED bits ++ * to avoid problems on MacBook Pro gen.8. ++ */ ++ i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0); ++ ++ i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN), ++ enable ? (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0); ++ ++ i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED, ++ enable ? 0 : MASK_MAX_EXCED); ++ ++ i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY), ++ enable ? 0 : MASK_REPEATER | MASK_READY); ++} ++ ++static void tc358743_disable_edid(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ v4l2_dbg(2, debug, sd, "%s:\n", __func__); ++ ++ cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); ++ ++ /* DDC access to EDID is also disabled when hotplug is disabled. See ++ * register DDC_CTL */ ++ i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0); ++} ++ ++static void tc358743_enable_edid(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ if (!state->edid_written) { ++ v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__); ++ return; ++ } ++ ++ v4l2_dbg(2, debug, sd, "%s:\n", __func__); ++ ++ /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when ++ * hotplug is enabled. See register DDC_CTL */ ++ queue_delayed_work(state->work_queues, ++ &state->delayed_work_enable_hotplug, HZ / 10); ++} ++ ++/* --------------- AVI --------------- */ ++/* TODO move to common library */ ++ ++struct aviInfoFrame { ++ u8 f17; ++ u8 y10; ++ u8 a0; ++ u8 b10; ++ u8 s10; ++ u8 c10; ++ u8 m10; ++ u8 r3210; ++ u8 itc; ++ u8 ec210; ++ u8 q10; ++ u8 sc10; ++ u8 f47; ++ u8 vic; ++ u8 yq10; ++ u8 cn10; ++ u8 pr3210; ++ u16 etb; ++ u16 sbb; ++ u16 elb; ++ u16 srb; ++}; ++ ++static const char *y10Text[4] = { ++ "RGB", ++ "YCbCr 4:2:2", ++ "YCbCr 4:4:4", ++ "Future", ++}; ++ ++static const char *c10Text[4] = { ++ "No Data", ++ "SMPTE 170M", ++ "ITU-R 709", ++ "Extended Colorimetry information valied", ++}; ++ ++static const char *itcText[2] = { ++ "No Data", ++ "IT content", ++}; ++ ++static const char *ec210Text[8] = { ++ "xvYCC601", ++ "xvYCC709", ++ "sYCC601", ++ "AdobeYCC601", ++ "AdobeRGB", ++ "5 reserved", ++ "6 reserved", ++ "7 reserved", ++}; ++ ++static const char *q10Text[4] = { ++ "Default", ++ "Limited Range", ++ "Full Range", ++ "Reserved", ++}; ++ ++static void parse_avi_infoframe(struct v4l2_subdev *sd, u8 *buf, ++ struct aviInfoFrame *avi) ++{ ++ avi->f17 = (buf[1] >> 7) & 0x1; ++ avi->y10 = (buf[1] >> 5) & 0x3; ++ avi->a0 = (buf[1] >> 4) & 0x1; ++ avi->b10 = (buf[1] >> 2) & 0x3; ++ avi->s10 = buf[1] & 0x3; ++ avi->c10 = (buf[2] >> 6) & 0x3; ++ avi->m10 = (buf[2] >> 4) & 0x3; ++ avi->r3210 = buf[2] & 0xf; ++ avi->itc = (buf[3] >> 7) & 0x1; ++ avi->ec210 = (buf[3] >> 4) & 0x7; ++ avi->q10 = (buf[3] >> 2) & 0x3; ++ avi->sc10 = buf[3] & 0x3; ++ avi->f47 = (buf[4] >> 7) & 0x1; ++ avi->vic = buf[4] & 0x7f; ++ avi->yq10 = (buf[5] >> 6) & 0x3; ++ avi->cn10 = (buf[5] >> 4) & 0x3; ++ avi->pr3210 = buf[5] & 0xf; ++ avi->etb = buf[6] + 256 * buf[7]; ++ avi->sbb = buf[8] + 256 * buf[9]; ++ avi->elb = buf[10] + 256 * buf[11]; ++ avi->srb = buf[12] + 256 * buf[13]; ++} ++ ++static void print_avi_infoframe(struct v4l2_subdev *sd) ++{ ++ u8 buf[14]; ++ u8 avi_len; ++ u8 avi_ver; ++ struct aviInfoFrame avi; ++ ++ if (!is_hdmi(sd)) { ++ v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n"); ++ return; ++ } ++ ++ avi_ver = i2c_rd8(sd, PK_AVI_1HEAD); ++ avi_len = i2c_rd8(sd, PK_AVI_2HEAD); ++ v4l2_info(sd, "AVI infoframe version %d (%d byte)\n", avi_ver, avi_len); ++ ++ if (avi_ver != 0x02) ++ return; ++ ++ i2c_rd(sd, PK_AVI_0BYTE, buf, ARRAY_SIZE(buf)); ++ ++ v4l2_info(sd, "\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], ++ buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], ++ buf[13]); ++ ++ parse_avi_infoframe(sd, buf, &avi); ++ ++ if (avi.vic) ++ v4l2_info(sd, "\tVIC: %d\n", avi.vic); ++ if (avi.itc) ++ v4l2_info(sd, "\t%s\n", itcText[avi.itc]); ++ ++ if (avi.y10) ++ v4l2_info(sd, "\t%s %s\n", y10Text[avi.y10], ++ !avi.c10 ? "" : ++ (avi.c10 == 0x3 ? ec210Text[avi.ec210] : ++ c10Text[avi.c10])); ++ else ++ v4l2_info(sd, "\t%s %s\n", y10Text[avi.y10], q10Text[avi.q10]); ++} ++ ++/* --------------- CTRLS --------------- */ ++ ++static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, ++ tx_5v_power_present(sd)); ++} ++ ++static int tc358743_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl, ++ get_audio_sampling_rate(sd)); ++} ++ ++static int tc358743_s_audio_present_ctrl(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ return v4l2_ctrl_s_ctrl(state->audio_present_ctrl, ++ audio_present(sd)); ++} ++ ++static int tc358743_update_controls(struct v4l2_subdev *sd) ++{ ++ int ret = 0; ++ ++ ret |= tc358743_s_ctrl_detect_tx_5v(sd); ++ ret |= tc358743_s_ctrl_audio_sampling_rate(sd); ++ ret |= tc358743_s_audio_present_ctrl(sd); ++ ++ return ret; ++} ++ ++/* --------------- INIT --------------- */ ++ ++static void tc358743_reset_phy(struct v4l2_subdev *sd) ++{ ++ v4l2_dbg(1, debug, sd, "%s:\n", __func__); ++ ++ i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0); ++ i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL); ++} ++ ++static void tc358743_reset(struct v4l2_subdev *sd, uint16_t mask) ++{ ++ u16 sysctl = i2c_rd16(sd, SYSCTL); ++ ++ i2c_wr16(sd, SYSCTL, sysctl | mask); ++ i2c_wr16(sd, SYSCTL, sysctl & ~mask); ++} ++ ++static inline void tc358743_sleep_mode(struct v4l2_subdev *sd, bool enable) ++{ ++ i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP, ++ enable ? MASK_SLEEP : 0); ++} ++ ++static inline void enable_stream(struct v4l2_subdev *sd, bool enable) ++{ ++ v4l2_dbg(3, debug, sd, "%s: %sable\n", ++ __func__, enable ? "en" : "dis"); ++ ++ i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN), ++ enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0); ++} ++ ++static void tc358743_set_pll(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct tc358743_platform_data *pdata = &state->pdata; ++ u16 pllctl0 = i2c_rd16(sd, PLLCTL0); ++ u16 pllctl1 = i2c_rd16(sd, PLLCTL1); ++ u16 pllctl0_new = SET_PLL_PRD(pdata->pll_prd) | ++ SET_PLL_FBD(pdata->pll_fbd); ++ ++ v4l2_dbg(2, debug, sd, "%s:\n", __func__); ++ ++ /* Only rewrite when needed, since rewriting triggers another format ++ * change event. */ ++ if ((pllctl0 != pllctl0_new) || ((pllctl1 & MASK_PLL_EN) == 0)) { ++ u32 hsck = (pdata->refclk_hz * pdata->pll_fbd) / pdata->pll_prd; ++ u16 pll_frs; ++ ++ if (hsck > 500000000) ++ pll_frs = 0x0; ++ else if (hsck > 250000000) ++ pll_frs = 0x1; ++ else if (hsck > 125000000) ++ pll_frs = 0x2; ++ else ++ pll_frs = 0x3; ++ ++ v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__); ++ tc358743_sleep_mode(sd, true); ++ i2c_wr16(sd, PLLCTL0, pllctl0_new); ++ i2c_wr16_and_or(sd, PLLCTL1, ++ ~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN), ++ (SET_PLL_FRS(pll_frs) | MASK_RESETB | ++ MASK_PLL_EN)); ++ udelay(10); /* REF_02, Sheet "Source HDMI" */ ++ i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN); ++ tc358743_sleep_mode(sd, false); ++ } ++} ++ ++static void tc358743_set_ref_clk(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct tc358743_platform_data *pdata = &state->pdata; ++ u32 sys_freq; ++ u32 lockdet_ref; ++ u16 fh_min; ++ u16 fh_max; ++ ++ BUG_ON(!(pdata->refclk_hz == 26000000 || ++ pdata->refclk_hz == 27000000 || ++ pdata->refclk_hz == 42000000)); ++ ++ sys_freq = pdata->refclk_hz / 10000; ++ i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff); ++ i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8); ++ ++ i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND, ++ (pdata->refclk_hz == 42000000) ? ++ MASK_PHY_SYSCLK_IND : 0x0); ++ ++ fh_min = pdata->refclk_hz / 100000; ++ i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff); ++ i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8); ++ ++ fh_max = (fh_min * 66) / 10; ++ i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff); ++ i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8); ++ ++ lockdet_ref = pdata->refclk_hz / 100; ++ i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff); ++ i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8); ++ i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16); ++ ++ i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD, ++ (pdata->refclk_hz == 27000000) ? ++ MASK_NCO_F0_MOD_27MHZ : 0x0); ++} ++ ++static void tc358743_set_csi_color_space(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ switch (state->mbus_fmt_code) { ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__); ++ i2c_wr8_and_or(sd, VOUT_SET2, ++ ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, ++ MASK_SEL422 | MASK_VOUT_422FIL_100); ++ i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, ++ MASK_VOUT_COLOR_601_YCBCR_LIMITED); ++ i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, ++ MASK_YCBCRFMT_422_8_BIT); ++ break; ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__); ++ i2c_wr8_and_or(sd, VOUT_SET2, ++ ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, ++ 0x00); ++ i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, ++ MASK_VOUT_COLOR_RGB_FULL); ++ i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0); ++ break; ++ default: ++ v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n", ++ __func__, state->mbus_fmt_code); ++ } ++} ++ ++static unsigned tc358743_num_csi_lanes_needed(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct v4l2_bt_timings *bt = &state->timings.bt; ++ u32 htotal = bt->width + bt->hfrontporch + bt->hsync + bt->hbackporch; ++ u32 vtotal = bt->height + bt->vfrontporch + bt->vsync + bt->vbackporch; ++ u32 bits_pr_pixel = ++ (state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ? 16 : 24; ++ u32 bps = htotal * vtotal * fps(bt) * bits_pr_pixel; ++ ++ return DIV_ROUND_UP(bps, state->pdata.bps_pr_lane); ++} ++ ++static void tc358743_set_csi(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct tc358743_platform_data *pdata = &state->pdata; ++ unsigned lanes = tc358743_num_csi_lanes_needed(sd); ++ ++ v4l2_dbg(3, debug, sd, "%s:\n", __func__); ++ ++ tc358743_reset(sd, MASK_CTXRST); ++ ++ if (lanes < 1) ++ i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE); ++ if (lanes < 1) ++ i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE); ++ if (lanes < 2) ++ i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE); ++ if (lanes < 3) ++ i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE); ++ if (lanes < 4) ++ i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE); ++ ++ i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt); ++ i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt); ++ i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt); ++ i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt); ++ i2c_wr32(sd, TWAKEUP, pdata->twakeup); ++ i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt); ++ i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt); ++ i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt); ++ i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt); ++ ++ i2c_wr32(sd, HSTXVREGEN, ++ ((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) | ++ ((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) | ++ ((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) | ++ ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | ++ ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); ++ ++ i2c_wr32(sd, TXOPTIONCNTRL, (state->bus.flags & ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) ? MASK_CONTCLKMODE : 0); ++} ++ ++static void tc358743_start_csi(struct v4l2_subdev *sd) ++{ ++ unsigned lanes = tc358743_num_csi_lanes_needed(sd); ++ ++ v4l2_dbg(3, debug, sd, "%s:\n", __func__); ++ ++ i2c_wr32(sd, STARTCNTRL, MASK_START); ++ i2c_wr32(sd, CSI_START, MASK_STRT); ++ ++ i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | ++ MASK_ADDRESS_CSI_CONTROL | ++ MASK_CSI_MODE | ++ MASK_TXHSMD | ++ ((lanes == 4) ? MASK_NOL_4 : ++ (lanes == 3) ? MASK_NOL_3 : ++ (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1)); ++ ++ i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | ++ MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK | ++ MASK_WCER | MASK_INER); ++ ++ i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR | ++ MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK); ++ ++ i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | ++ MASK_ADDRESS_CSI_INT_ENA | MASK_INTER); ++} ++ ++static void tc358743_set_hdmi_phy(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct tc358743_platform_data *pdata = &state->pdata; ++ ++ /* Default settings from REF_02, sheet "Source HDMI" ++ * and custom settings as platform data */ ++ i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0); ++ i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) | ++ SET_FREQ_RANGE_MODE_CYCLES(1)); ++ i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn, pdata->phy_auto_rst); ++ i2c_wr8(sd, PHY_BIAS, 0x40); ++ i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a)); ++ i2c_wr8(sd, AVM_CTL, 45); ++ i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V, ++ pdata->hdmi_det_v); ++ i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST), ++ (pdata->h_pi_rst ? MASK_H_PI_RST : 0) | ++ (pdata->v_pi_rst ? MASK_V_PI_RST : 0)); ++ i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY); ++} ++ ++static void tc358743_erase_bksv(struct v4l2_subdev *sd) ++{ ++ int i; ++ ++ for (i = 0; i < 5; i++) ++ i2c_wr8(sd, BKSV + i, 0); ++} ++ ++static void tc358743_set_hdmi_audio(struct v4l2_subdev *sd) ++{ ++ /* Default settings from REF_02, sheet "Source HDMI" */ ++ i2c_wr8(sd, FORCE_MUTE, 0x00); ++ i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 | ++ MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 | ++ MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0); ++ i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9); ++ i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2); ++ i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500)); ++ i2c_wr8(sd, FS_MUTE, 0x00); ++ i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE); ++ i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE); ++ i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM); ++ i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM); ++ i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S); ++ i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100)); ++ i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 | ++ MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX); ++} ++ ++static void tc358743_set_hdmi_info_frame_mode(struct v4l2_subdev *sd) ++{ ++ /* Default settings from REF_02, sheet "Source HDMI" */ ++ i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE | ++ MASK_ACP_INT_MODE | MASK_VS_INT_MODE | ++ MASK_SPD_INT_MODE | MASK_MS_INT_MODE | ++ MASK_AUD_INT_MODE | MASK_AVI_INT_MODE); ++ i2c_wr8(sd, NO_PKT_LIMIT, 0x2c); ++ i2c_wr8(sd, NO_PKT_CLR, 0x53); ++ i2c_wr8(sd, ERR_PK_LIMIT, 0x01); ++ i2c_wr8(sd, NO_PKT_LIMIT2, 0x30); ++ i2c_wr8(sd, NO_GDB_LIMIT, 0x10); ++} ++ ++static void tc358743_initial_setup(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct tc358743_platform_data *pdata = &state->pdata; ++ ++ /* Keep CEC and IR in reset since driver support is missing */ ++ i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST), ++ (MASK_CECRST | MASK_IRRST)); ++ ++ tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST); ++ tc358743_sleep_mode(sd, false); ++ ++ i2c_wr16(sd, FIFOCTL, pdata->fifo_level); ++ ++ tc358743_set_ref_clk(sd); ++ ++ i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE, ++ pdata->ddc5v_delay & MASK_DDC5V_MODE); ++ i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC); ++ ++ tc358743_set_hdmi_phy(sd); ++ tc358743_set_hdmi_hdcp(sd, pdata->enable_hdcp); ++ tc358743_set_hdmi_audio(sd); ++ tc358743_set_hdmi_info_frame_mode(sd); ++ ++ i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE, ++ MASK_VOUTCOLORMODE_AUTO); ++ i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT); ++} ++ ++/* --------------- IRQ --------------- */ ++ ++static void tc358743_clear_interrupt_status(struct v4l2_subdev *sd) ++{ ++ u16 i; ++ ++ /* clear interrupt status registers */ ++ for (i = SYS_INT; i <= KEY_INT; i++) ++ i2c_wr8(sd, i, 0xff); ++ ++ i2c_wr16(sd, INTSTATUS, 0xffff); ++} ++ ++static void tc358743_enable_interrupts(struct v4l2_subdev *sd) ++{ ++ tc358743_clear_interrupt_status(sd); ++ ++ /* enable interrupts */ ++ i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_HDMI_DET) & 0xff); ++ ++ i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG); ++ ++ i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG); ++ ++ i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK | ++ MASK_M_AF_UNLOCK) & 0xff); ++ ++ i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); ++} ++ ++static void tc358743_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled) ++{ ++ v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR)); ++ ++ i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER); ++} ++ ++static void tc358743_hdmi_misc_int_handler(struct v4l2_subdev *sd, ++ bool *handled) ++{ ++ u8 misc_int_mask = i2c_rd8(sd, MISC_INTM); ++ u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask; ++ ++ i2c_wr8(sd, MISC_INT, misc_int); ++ ++ v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int); ++ ++ if (misc_int & MASK_I_SYNC_CHG) { ++ ++ v4l2_dbg(1, debug, sd, "%s: Format changed\n", __func__); ++ ++ if (no_sync(sd) || no_signal(sd)) { ++ tc358743_reset_phy(sd); ++ tc358743_erase_bksv(sd); ++ } ++ ++ v4l2_subdev_notify(sd, TC358743_FMT_CHANGE, NULL); ++ ++ misc_int &= ~MASK_I_SYNC_CHG; ++ if (handled) ++ *handled = true; ++ } ++ ++ if (misc_int) { ++ v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n", ++ __func__, misc_int); ++ } ++} ++ ++static void tc358743_hdmi_cbit_int_handler(struct v4l2_subdev *sd, ++ bool *handled) ++{ ++ u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM); ++ u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask; ++ ++ i2c_wr8(sd, CBIT_INT, cbit_int); ++ ++ v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int); ++ ++ if (cbit_int & MASK_I_CBIT_FS) { ++ ++ v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n", ++ __func__); ++ tc358743_s_ctrl_audio_sampling_rate(sd); ++ ++ cbit_int &= ~MASK_I_CBIT_FS; ++ if (handled) ++ *handled = true; ++ } ++ ++ if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) { ++ ++ v4l2_dbg(1, debug, sd, "%s: Audio present changed\n", ++ __func__); ++ tc358743_s_audio_present_ctrl(sd); ++ ++ cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK); ++ if (handled) ++ *handled = true; ++ } ++ ++ if (cbit_int) { ++ v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n", ++ __func__, cbit_int); ++ } ++} ++ ++static void tc358743_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled) ++{ ++ u8 clk_int_mask = i2c_rd8(sd, CLK_INTM); ++ u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask; ++ ++ /* Bit 7 and bit 6 are set even when they are masked */ ++ i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG); ++ ++ v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int); ++ ++ if (clk_int & (MASK_I_IN_DE_CHG)) { ++ ++ v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n", ++ __func__); ++ ++ /* If the source switch to a new resolution with the same pixel ++ * frequency as the existing (ie. 1080p25 -> 720p50), the ++ * I_SYNC_CHG interrupt is not always triggered, while the ++ * I_IN_DE_CHG interrupt seems to work fine. FMT_CHANGE ++ * notifications are only sent when the signal is stable to ++ * reduce the number of notifications. */ ++ if (!no_signal(sd) && !no_sync(sd)) ++ v4l2_subdev_notify(sd, TC358743_FMT_CHANGE, NULL); ++ ++ clk_int &= ~(MASK_I_IN_DE_CHG); ++ if (handled) ++ *handled = true; ++ } ++ ++ if (clk_int) { ++ v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n", ++ __func__, clk_int); ++ } ++} ++ ++static void tc358743_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled) ++{ ++ struct tc358743_state *state = to_state(sd); ++ u8 sys_int_mask = i2c_rd8(sd, SYS_INTM); ++ u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask; ++ ++ i2c_wr8(sd, SYS_INT, sys_int); ++ ++ v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int); ++ ++ if (sys_int & MASK_I_DDC) { ++ bool tx_5v = tx_5v_power_present(sd); ++ ++ v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n", ++ __func__, tx_5v ? "yes" : "no"); ++ ++ if (tx_5v) { ++ tc358743_enable_edid(sd); ++ } else { ++ tc358743_disable_edid(sd); ++ memset(&state->timings, 0, sizeof(state->timings)); ++ tc358743_erase_bksv(sd); ++ } ++ ++ tc358743_update_controls(sd); ++ ++ sys_int &= ~MASK_I_DDC; ++ if (handled) ++ *handled = true; ++ } ++ ++ if (sys_int & MASK_I_HDMI) { ++ v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n", ++ __func__); ++ ++ /* Register is reset in DVI mode (REF_01, c. 6.6.41) */ ++ i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON); ++ ++ sys_int &= ~MASK_I_HDMI; ++ if (handled) ++ *handled = true; ++ } ++ ++ if (sys_int) { ++ v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n", ++ __func__, sys_int); ++ } ++} ++ ++/* --------------- CORE OPS --------------- */ ++ ++static int tc358743_log_status(struct v4l2_subdev *sd) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct v4l2_dv_timings timings; ++ uint8_t hdmi_sys_status = i2c_rd8(sd, SYS_STATUS); ++ uint16_t sysctl = i2c_rd16(sd, SYSCTL); ++ u8 vi_status3 = i2c_rd8(sd, VI_STATUS3); ++ const int deep_color_mode[4] = { 8, 10, 12, 16 }; ++ static const char * const input_color_space[] = { ++ "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)", ++ "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", ++ "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"}; ++ ++ v4l2_info(sd, "-----Chip status-----\n"); ++ v4l2_info(sd, "Chip ID: %d\n", i2c_rd16(sd, CHIPID) & ++ MASK_CHIPID); ++ v4l2_info(sd, "Chip revision: %d\n", ++ i2c_rd16(sd, CHIPID) & MASK_REVID); ++ v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n", ++ !!(sysctl & MASK_IRRST), ++ !!(sysctl & MASK_CECRST), ++ !!(sysctl & MASK_CTXRST), ++ !!(sysctl & MASK_HDMIRST)); ++ v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off"); ++ v4l2_info(sd, "Cable detected (+5V power): %s\n", ++ hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no"); ++ v4l2_info(sd, "DDC lines enabled: %s\n", ++ (i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ? ++ "yes" : "no"); ++ v4l2_info(sd, "Hotplug enabled: %s\n", ++ (i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ? ++ "yes" : "no"); ++ v4l2_info(sd, "CEC enabled: %s\n", ++ (i2c_rd16(sd, CECEN) & MASK_CECEN) ? "yes" : "no"); ++ v4l2_info(sd, "-----Signal status-----\n"); ++ v4l2_info(sd, "TMDS signal detected: %s\n", ++ hdmi_sys_status & MASK_S_TMDS ? "yes" : "no"); ++ v4l2_info(sd, "Stable sync signal: %s\n", ++ hdmi_sys_status & MASK_S_SYNC ? "yes" : "no"); ++ v4l2_info(sd, "PHY PLL locked: %s\n", ++ hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no"); ++ v4l2_info(sd, "PHY DE detected: %s\n", ++ hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no"); ++ ++ if (tc358743_get_detected_timings(sd, &timings)) { ++ v4l2_info(sd, "No video detected\n"); ++ } else { ++ v4l2_print_dv_timings(sd->name, "Detected format: ", &timings, ++ true); ++ } ++ v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings, ++ true); ++ ++ v4l2_info(sd, "-----CSI-TX status-----\n"); ++ v4l2_info(sd, "Lanes needed: %d\n", ++ tc358743_num_csi_lanes_needed(sd)); ++ v4l2_info(sd, "Lanes in use: %d\n", ++ tc358743_num_csi_lanes_in_use(sd)); ++ v4l2_info(sd, "Waiting for particular sync signal: %s\n", ++ (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ? ++ "yes" : "no"); ++ v4l2_info(sd, "Transmit mode: %s\n", ++ (i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ? ++ "yes" : "no"); ++ v4l2_info(sd, "Receive mode: %s\n", ++ (i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ? ++ "yes" : "no"); ++ v4l2_info(sd, "Stopped: %s\n", ++ (i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ? ++ "yes" : "no"); ++ v4l2_info(sd, "Color space: %s\n", ++ state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ? ++ "YCbCr 422 16-bit" : ++ state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ? ++ "RGB 888 24-bit" : "Unsupported"); ++ ++ v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); ++ v4l2_info(sd, "HDCP encrypted content: %s\n", ++ hdmi_sys_status & MASK_S_HDCP ? "yes" : "no"); ++ v4l2_info(sd, "Input color space: %s %s range\n", ++ input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1], ++ (vi_status3 & MASK_LIMITED) ? "limited" : "full"); ++ if (!is_hdmi(sd)) ++ return 0; ++ v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" : ++ "off"); ++ v4l2_info(sd, "Deep color mode: %d-bits per channel\n", ++ deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & ++ MASK_S_DEEPCOLOR) >> 2]); ++ print_avi_infoframe(sd); ++ ++ return 0; ++} ++ ++static long tc358743_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ++{ ++ switch (cmd) { ++ case TC358743_CSI_RESET: ++ { ++ /* ++ * This function is called often with CSI overflow. It should ++ * run as fast as possible for quick recovery. I2C operations ++ * are slow. This function takes about 20 ms. Stop stream first, ++ * reset CSI and enable stream. Avoid calling enable_stream ++ * twice which add an extra I2C read. ++ */ ++ unsigned short confctl = i2c_rd16(sd, CONFCTL); ++ ++ v4l2_dbg(3, debug, sd, "%s: TC358743_CSI_RESET\n", __func__); ++ ++ i2c_wr16(sd, CONFCTL, confctl & ++ (~(MASK_VBUFEN | MASK_ABUFEN))); ++ tc358743_set_csi(sd); ++ tc358743_start_csi(sd); ++ i2c_wr16(sd, CONFCTL, confctl | ++ (MASK_VBUFEN | MASK_ABUFEN)); ++ return 0; ++ } ++ } ++ ++ v4l2_dbg(1, debug, sd, "%s: unknown ioctl %08x\n", __func__, cmd); ++ ++ return -ENOTTY; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static void tc358743_print_register_map(struct v4l2_subdev *sd) ++{ ++ v4l2_info(sd, "0x0000–0x00FF: Global Control Register\n"); ++ v4l2_info(sd, "0x0100–0x01FF: CSI2-TX PHY Register\n"); ++ v4l2_info(sd, "0x0200–0x03FF: CSI2-TX PPI Register\n"); ++ v4l2_info(sd, "0x0400–0x05FF: Reserved\n"); ++ v4l2_info(sd, "0x0600–0x06FF: CEC Register\n"); ++ v4l2_info(sd, "0x0700–0x84FF: Reserved\n"); ++ v4l2_info(sd, "0x8500–0x85FF: HDMIRX System Control Register\n"); ++ v4l2_info(sd, "0x8600–0x86FF: HDMIRX Audio Control Register\n"); ++ v4l2_info(sd, "0x8700–0x87FF: HDMIRX InfoFrame packet data Register\n"); ++ v4l2_info(sd, "0x8800–0x88FF: HDMIRX HDCP Port Register\n"); ++ v4l2_info(sd, "0x8900–0x89FF: HDMIRX Video Output Port & 3D Register\n"); ++ v4l2_info(sd, "0x8A00–0x8BFF: Reserved\n"); ++ v4l2_info(sd, "0x8C00–0x8FFF: HDMIRX EDID-RAM (1024bytes)\n"); ++ v4l2_info(sd, "0x9000–0x90FF: HDMIRX GBD Extraction Control\n"); ++ v4l2_info(sd, "0x9100–0x92FF: HDMIRX GBD RAM read\n"); ++ v4l2_info(sd, "0x9300- : Reserved\n"); ++} ++ ++static int tc358743_get_reg_size(u16 address) ++{ ++ /* REF_01 p. 66-72 */ ++ if (address <= 0x00ff) ++ return 2; ++ else if ((address >= 0x0100) && (address <= 0x06FF)) ++ return 4; ++ else if ((address >= 0x0700) && (address <= 0x84ff)) ++ return 2; ++ else ++ return 1; ++} ++ ++static int tc358743_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ if (reg->reg > 0xffff) { ++ tc358743_print_register_map(sd); ++ return -EINVAL; ++ } ++ ++ reg->size = tc358743_get_reg_size(reg->reg); ++ ++ i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size); ++ ++ return 0; ++} ++ ++static int tc358743_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ if (reg->reg > 0xffff) { ++ tc358743_print_register_map(sd); ++ return -EINVAL; ++ } ++ ++ /* It should not be possible for the user to enable HDCP with a simple ++ * v4l2-dbg command. ++ * ++ * DO NOT REMOVE THIS unless all other issues with HDCP have been ++ * resolved. ++ */ ++ if (reg->reg == HDCP_MODE || ++ reg->reg == HDCP_REG1 || ++ reg->reg == HDCP_REG2 || ++ reg->reg == HDCP_REG3 || ++ reg->reg == BCAPS) ++ return 0; ++ ++ i2c_wr(sd, (u16)reg->reg, (u8 *)®->val, ++ tc358743_get_reg_size(reg->reg)); ++ ++ return 0; ++} ++#endif ++ ++static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) ++{ ++ u16 intstatus = i2c_rd16(sd, INTSTATUS); ++ ++ v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus); ++ ++ if (intstatus & MASK_HDMI_INT) { ++ u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0); ++ u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1); ++ ++ if (hdmi_int0 & MASK_I_MISC) ++ tc358743_hdmi_misc_int_handler(sd, handled); ++ if (hdmi_int1 & MASK_I_CBIT) ++ tc358743_hdmi_cbit_int_handler(sd, handled); ++ if (hdmi_int1 & MASK_I_CLK) ++ tc358743_hdmi_clk_int_handler(sd, handled); ++ if (hdmi_int1 & MASK_I_SYS) ++ tc358743_hdmi_sys_int_handler(sd, handled); ++ ++ i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT); ++ intstatus &= ~MASK_HDMI_INT; ++ } ++ ++ if (intstatus & MASK_CSI_INT) { ++ u32 csi_int = i2c_rd32(sd, CSI_INT); ++ ++ if (csi_int & MASK_INTER) ++ tc358743_csi_err_int_handler(sd, handled); ++ ++ i2c_wr16(sd, INTSTATUS, MASK_CSI_INT); ++ intstatus &= ~MASK_CSI_INT; ++ } ++ ++ intstatus = i2c_rd16(sd, INTSTATUS); ++ if (intstatus) { ++ v4l2_dbg(1, debug, sd, ++ "%s: Unhandled IntStatus interrupts: 0x%02x\n", ++ __func__, intstatus); ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) ++{ ++ struct tc358743_state *state = dev_id; ++ bool handled; ++ ++ tc358743_isr(&state->sd, 0, &handled); ++ ++ return handled ? IRQ_HANDLED : IRQ_NONE; ++} ++ ++/* --------------- VIDEO OPS --------------- */ ++ ++static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) ++{ ++ *status = 0; ++ *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; ++ *status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0; ++ ++ v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); ++ ++ return 0; ++} ++ ++static int tc358743_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_format *format) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ if (format->pad != 0) ++ return -EINVAL; ++ ++ switch (format->format.code) { ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ state->mbus_fmt_code = format->format.code; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ enable_stream(sd, false); ++ tc358743_set_pll(sd); ++ tc358743_set_csi(sd); ++ tc358743_set_csi_color_space(sd); ++ ++ return 0; ++} ++ ++static int tc358743_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_format *format) ++{ ++ struct tc358743_state *state = to_state(sd); ++ u8 vi_rep = i2c_rd8(sd, VI_REP); ++ ++ if (format->pad != 0) ++ return -EINVAL; ++ ++ format->format.code = state->mbus_fmt_code; ++ format->format.width = state->timings.bt.width; ++ format->format.height = state->timings.bt.height; ++ format->format.field = V4L2_FIELD_NONE; ++ ++ switch (vi_rep & MASK_VOUT_COLOR_SEL) { ++ case MASK_VOUT_COLOR_RGB_FULL: ++ case MASK_VOUT_COLOR_RGB_LIMITED: ++ format->format.colorspace = V4L2_COLORSPACE_SRGB; ++ break; ++ case MASK_VOUT_COLOR_601_YCBCR_LIMITED: ++ case MASK_VOUT_COLOR_601_YCBCR_FULL: ++ format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; ++ break; ++ case MASK_VOUT_COLOR_709_YCBCR_FULL: ++ case MASK_VOUT_COLOR_709_YCBCR_LIMITED: ++ format->format.colorspace = V4L2_COLORSPACE_REC709; ++ break; ++ default: ++ format->format.colorspace = 0; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int tc358743_s_dv_timings(struct v4l2_subdev *sd, ++ struct v4l2_dv_timings *timings) ++{ ++ struct tc358743_state *state = to_state(sd); ++ struct v4l2_bt_timings *bt; ++ ++ if (!timings) ++ return -EINVAL; ++ ++ if (debug) ++ v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ", ++ timings, false); ++ ++ if (!memcmp(&state->timings, timings, sizeof(struct v4l2_dv_timings))) { ++ v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); ++ return 0; ++ } ++ ++ bt = &timings->bt; ++ ++ if (!v4l2_valid_dv_timings(timings, ++ &tc358743_timings_cap, NULL, NULL)) { ++ v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); ++ return -ERANGE; ++ } ++ ++ /* Fill the optional fields .standards and .flags in struct ++ * v4l2_dv_timings if the format is one of the CEA or DMT timings */ ++ v4l2_find_dv_timings_cap(timings, ++ &tc358743_timings_cap, 250000, NULL, NULL); ++ ++ state->timings = *timings; ++ ++ enable_stream(sd, false); ++ tc358743_set_pll(sd); ++ tc358743_set_csi(sd); ++ ++ return 0; ++} ++ ++static int tc358743_g_dv_timings(struct v4l2_subdev *sd, ++ struct v4l2_dv_timings *timings) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ *timings = state->timings; ++ ++ return 0; ++} ++ ++static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, ++ struct v4l2_enum_dv_timings *timings) ++{ ++ return v4l2_enum_dv_timings_cap(timings, ++ &tc358743_timings_cap, NULL, NULL); ++} ++ ++static int tc358743_query_dv_timings(struct v4l2_subdev *sd, ++ struct v4l2_dv_timings *timings) ++{ ++ int ret; ++ ++ ret = tc358743_get_detected_timings(sd, timings); ++ if (ret) ++ return ret; ++ ++ if (debug) ++ v4l2_print_dv_timings(sd->name, "tc358743_query_dv_timings: ", ++ timings, false); ++ ++ if (!v4l2_valid_dv_timings(timings, ++ &tc358743_timings_cap, NULL, NULL)) { ++ v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); ++ return -ERANGE; ++ } ++ ++ return 0; ++} ++ ++static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, ++ struct v4l2_dv_timings_cap *cap) ++{ ++ *cap = tc358743_timings_cap; ++ ++ return 0; ++} ++ ++static int tc358743_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ cfg->flags = i2c_rd16(sd, TXOPTIONCNTRL) & MASK_CONTCLKMODE ? ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK : ++ V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; ++ ++ switch (tc358743_num_csi_lanes_in_use(sd)) { ++ case 1: ++ cfg->flags |= V4L2_MBUS_CSI2_1_LANE; ++ break; ++ case 2: ++ cfg->flags |= V4L2_MBUS_CSI2_2_LANE; ++ break; ++ case 3: ++ cfg->flags |= V4L2_MBUS_CSI2_3_LANE; ++ break; ++ case 4: ++ cfg->flags |= V4L2_MBUS_CSI2_4_LANE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ if (enable) ++ tc358743_start_csi(sd); ++ enable_stream(sd, enable); ++ if (!enable) ++ tc358743_set_csi(sd); ++ ++ return 0; ++} ++ ++/* --------------- PAD OPS --------------- */ ++ ++static int tc358743_g_edid(struct v4l2_subdev *sd, ++ struct v4l2_subdev_edid *edid) ++{ ++ struct tc358743_state *state = to_state(sd); ++ ++ if (edid->pad != 0) ++ return -EINVAL; ++ ++ if (!state->edid_written) ++ return -ENODATA; ++ ++ if (edid->blocks == 0) ++ return -EINVAL; ++ ++ if (edid->start_block >= 8) ++ return -EINVAL; ++ ++ if (edid->start_block + edid->blocks > 8) ++ edid->blocks = 8 - edid->start_block; ++ ++ if (!edid->edid) ++ return -EINVAL; ++ ++ i2c_rd(sd, EDID_RAM + (edid->start_block * 128), edid->edid, ++ edid->blocks * 128); ++ ++ return 0; ++} ++ ++static int tc358743_s_edid(struct v4l2_subdev *sd, ++ struct v4l2_subdev_edid *edid) ++{ ++ struct tc358743_state *state = to_state(sd); ++ u16 edid_len = edid->blocks * 128; ++ ++ v4l2_dbg(2, debug, sd, "%s\n", __func__); ++ ++ if (edid->pad != 0) ++ return -EINVAL; ++ ++ if (edid->start_block != 0) ++ return -EINVAL; ++ ++ if (edid->blocks > 8) { ++ edid->blocks = 8; ++ return -E2BIG; ++ } ++ ++ if (edid->blocks != 0 && !edid->edid) ++ return -EINVAL; ++ ++ tc358743_disable_edid(sd); ++ ++ i2c_wr8(sd, EDID_LEN1, edid_len & 0xff); ++ i2c_wr8(sd, EDID_LEN2, edid_len >> 8); ++ ++ if (edid->blocks == 0) { ++ state->edid_written = false; ++ return 0; ++ } ++ ++ i2c_wr(sd, EDID_RAM, edid->edid, edid_len); ++ ++ state->edid_written = true; ++ ++ if (tx_5v_power_present(sd)) ++ tc358743_enable_edid(sd); ++ ++ return 0; ++} ++ ++/* -------------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops tc358743_core_ops = { ++ .log_status = tc358743_log_status, ++ .ioctl = tc358743_ioctl, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = tc358743_g_register, ++ .s_register = tc358743_s_register, ++#endif ++ .interrupt_service_routine = tc358743_isr, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops tc358743_video_ops = { ++ .g_input_status = tc358743_g_input_status, ++ .s_dv_timings = tc358743_s_dv_timings, ++ .g_dv_timings = tc358743_g_dv_timings, ++ .query_dv_timings = tc358743_query_dv_timings, ++ .g_mbus_config = tc358743_g_mbus_config, ++ .s_stream = tc358743_s_stream, ++ .enum_dv_timings = tc358743_enum_dv_timings, ++ .dv_timings_cap = tc358743_dv_timings_cap, ++}; ++ ++static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { ++ .set_fmt = tc358743_set_fmt, ++ .get_fmt = tc358743_get_fmt, ++ .get_edid = tc358743_g_edid, ++ .set_edid = tc358743_s_edid, ++}; ++ ++static const struct v4l2_subdev_ops tc358743_ops = { ++ .core = &tc358743_core_ops, ++ .video = &tc358743_video_ops, ++ .pad = &tc358743_pad_ops, ++}; ++ ++/* --------------- CUSTOM CTRLS --------------- */ ++ ++static const struct v4l2_ctrl_config tc358743_ctrl_audio_sampling_rate = { ++ .id = TC358743_CID_AUDIO_SAMPLING_RATE, ++ .name = "Audio sampling rate", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .min = 0, ++ .max = 768000, ++ .step = 1, ++ .def = 0, ++ .flags = V4L2_CTRL_FLAG_READ_ONLY, ++}; ++ ++static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { ++ .id = TC358743_CID_AUDIO_PRESENT, ++ .name = "Audio present", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 0, ++ .flags = V4L2_CTRL_FLAG_READ_ONLY, ++}; ++ ++/* --------------- PROBE / REMOVE --------------- */ ++ ++#if CONFIG_OF ++static void tc358743_gpio_reset(struct tc358743_state *state) ++{ ++ gpiod_set_value(state->reset_gpio, 0); ++ usleep_range(5000, 10000); ++ gpiod_set_value(state->reset_gpio, 1); ++ usleep_range(1000, 2000); ++ gpiod_set_value(state->reset_gpio, 0); ++ msleep(20); ++} ++ ++static int tc358743_probe_of(struct tc358743_state *state) ++{ ++ struct device *dev = &state->i2c_client->dev; ++ struct device_node *np = dev->of_node; ++ struct device_node *ep; ++ struct clk *refclk; ++ u32 bps_pr_lane; ++ ++ refclk = devm_clk_get(dev, "refclk"); ++ if (IS_ERR(refclk)) { ++ if (PTR_ERR(refclk) != -EPROBE_DEFER) ++ dev_err(dev, "failed to get refclk: %ld\n", ++ PTR_ERR(refclk)); ++ return PTR_ERR(refclk); ++ } ++ ++ ep = v4l2_of_get_next_endpoint(dev->of_node, NULL); ++ if (ep) { ++ struct v4l2_of_endpoint endpoint; ++ ++ v4l2_of_parse_endpoint(ep, &endpoint); ++ if (endpoint.bus_type != V4L2_MBUS_CSI2 || ++ endpoint.bus.mipi_csi2.num_data_lanes == 0) { ++ dev_err(dev, "missing CSI-2 properties in endpoint\n"); ++ return -EINVAL; ++ } ++ ++ state->bus = endpoint.bus.mipi_csi2; ++ } else { ++ dev_err(dev, "missing endpoint node\n"); ++ return -EINVAL; ++ } ++ ++ clk_prepare_enable(refclk); ++ ++ state->pdata.refclk_hz = clk_get_rate(refclk); ++ state->pdata.ddc5v_delay = DDC5V_DELAY_100MS; ++ state->pdata.enable_hdcp = false; ++ /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ ++ state->pdata.fifo_level = 16; ++ /* ++ * The PLL input clock is obtained by dividing refclk by pll_prd. ++ * It must be between 6 MHz and 40 MHz, lower frequency is better. ++ */ ++ switch (state->pdata.refclk_hz) { ++ case 26000000: ++ case 27000000: ++ case 42000000: ++ state->pdata.pll_prd = state->pdata.refclk_hz / 6000000; ++ break; ++ default: ++ dev_err(dev, "unsupported refclk rate: %u Hz\n", ++ state->pdata.refclk_hz); ++ clk_disable_unprepare(refclk); ++ return -EINVAL; ++ } ++ ++ /* ++ * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. ++ * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. ++ */ ++ bps_pr_lane = 594000000U; ++ of_property_read_u32(np, "toshiba,bps-per-lane", &bps_pr_lane); ++ if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { ++ dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane); ++ clk_disable_unprepare(refclk); ++ return -EINVAL; ++ } ++ state->pdata.bps_pr_lane = bps_pr_lane; ++ ++ /* The CSI speed per lane is refclk / pll_prd * pll_fbd */ ++ state->pdata.pll_fbd = state->pdata.bps_pr_lane / ++ state->pdata.refclk_hz * state->pdata.pll_prd; ++ bps_pr_lane = state->pdata.refclk_hz / state->pdata.pll_prd * ++ state->pdata.pll_fbd; ++ if (bps_pr_lane != state->pdata.bps_pr_lane) { ++ dev_warn(dev, "bps per lane corrected to %u bps\n", ++ bps_pr_lane); ++ state->pdata.bps_pr_lane = bps_pr_lane; ++ } ++ ++ /* FIXME: These timings are from REF_02 for 594 Mbps per lane */ ++ state->pdata.lineinitcnt = 0xe80; ++ state->pdata.lptxtimecnt = 0x003; ++ /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ ++ state->pdata.tclk_headercnt = 0x1403; ++ state->pdata.tclk_trailcnt = 0x00; ++ /* ths-preparecnt: 3, ths-zerocnt: 1 */ ++ state->pdata.ths_headercnt = 0x0103; ++ state->pdata.twakeup = 0x4882; ++ state->pdata.tclk_postcnt = 0x008; ++ state->pdata.ths_trailcnt = 0x2; ++ state->pdata.hstxvregcnt = 0; ++ ++ /* HDMI PHY */ ++ state->pdata.phy_auto_rst = 0; ++ state->pdata.hdmi_det_v = 0; ++ state->pdata.h_pi_rst = 0; ++ state->pdata.v_pi_rst = 0; ++ ++ state->reset_gpio = devm_gpiod_get(dev, "reset"); ++ if (!IS_ERR(state->reset_gpio)) { ++ tc358743_gpio_reset(state); ++ } else { ++ dev_warn(dev, "failed to get reset gpio\n"); ++ } ++ ++ ++ return 0; ++} ++#else ++static inline int tc358743_probe_of(struct tc358743_state *state) ++{ ++ return -ENODEV; ++} ++#endif ++ ++static int tc358743_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ static struct v4l2_dv_timings default_timing = ++ V4L2_DV_BT_CEA_640X480P59_94; ++ struct tc358743_state *state; ++ struct tc358743_platform_data *pdata = client->dev.platform_data; ++ struct v4l2_subdev *sd; ++ int err; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return -EIO; ++ v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ state = devm_kzalloc(&client->dev, sizeof(struct tc358743_state), ++ GFP_KERNEL); ++ if (!state) { ++ v4l_err(client, "Could not allocate tc358743_state memory!\n"); ++ return -ENOMEM; ++ } ++ ++ state->i2c_client = client; ++ ++ /* platform data */ ++ if (pdata) { ++ state->pdata = *pdata; ++ } else { ++ err = tc358743_probe_of(state); ++ if (err == -ENODEV) ++ v4l_err(client, "No platform data!\n"); ++ if (err) ++ return err; ++ } ++ ++ sd = &state->sd; ++ v4l2_i2c_subdev_init(sd, client, &tc358743_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; ++ ++ /* i2c access */ ++ if (i2c_rd16(sd, CHIPID) != 0x0000) { ++ v4l2_info(sd, "not a TC358743 on address 0x%x\n", ++ client->addr << 1); ++ return -ENODEV; ++ } ++ /* read the interrupt mask register, it should carry the ++ * default values, as it hasn't been touched at this point. ++ */ ++ if (i2c_rd16(sd, INTMASK) != 0x0400) { ++ v4l2_warn(sd, "initial interrupt mask: 0x%04x\n", ++ i2c_rd16(sd, INTMASK)); ++ i2c_wr16(sd, INTMASK, 0x0400); ++ } ++ ++ tc358743_clear_interrupt_status(sd); ++ ++ if (state->i2c_client->irq) { ++ err = devm_request_threaded_irq(&client->dev, ++ state->i2c_client->irq, ++ NULL, tc358743_irq_handler, ++ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ++ "tc358743", state); ++ if (err) ++ return err; ++ } ++ ++ /* control handlers */ ++ v4l2_ctrl_handler_init(&state->hdl, 3); ++ ++ /* private controls */ ++ state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, ++ V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); ++ ++ /* custom controls */ ++ state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl, ++ &tc358743_ctrl_audio_sampling_rate, NULL); ++ ++ state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl, ++ &tc358743_ctrl_audio_present, NULL); ++ ++ sd->ctrl_handler = &state->hdl; ++ if (state->hdl.error) { ++ err = state->hdl.error; ++ goto err_hdl; ++ } ++ ++ if (tc358743_update_controls(sd)) { ++ err = -ENODEV; ++ goto err_hdl; ++ } ++ ++ /* work queues */ ++ state->work_queues = create_singlethread_workqueue(client->name); ++ if (!state->work_queues) { ++ v4l2_err(sd, "Could not create work queue\n"); ++ err = -ENOMEM; ++ goto err_hdl; ++ } ++ ++ state->pad.flags = MEDIA_PAD_FL_SOURCE; ++ err = media_entity_init(&sd->entity, 1, &state->pad, 0); ++ if (err < 0) ++ goto err_hdl; ++ ++ sd->dev = &client->dev; ++ err = v4l2_async_register_subdev(sd); ++ if (err < 0) ++ goto err_hdl; ++ ++ INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, ++ tc358743_delayed_work_enable_hotplug); ++ ++ tc358743_initial_setup(sd); ++ ++ tc358743_s_dv_timings(sd, &default_timing); ++ ++ state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24; ++ tc358743_set_csi_color_space(sd); ++ ++ tc358743_enable_interrupts(sd); ++ ++ v4l2_ctrl_handler_setup(sd->ctrl_handler); ++ ++ v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, ++ client->addr << 1, client->adapter->name); ++ ++ return 0; ++ ++err_hdl: ++ media_entity_cleanup(&sd->entity); ++ v4l2_ctrl_handler_free(&state->hdl); ++ return err; ++} ++ ++static int tc358743_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct tc358743_state *state = to_state(sd); ++ ++ cancel_delayed_work(&state->delayed_work_enable_hotplug); ++ destroy_workqueue(state->work_queues); ++ v4l2_async_unregister_subdev(sd); ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&state->hdl); ++ ++ return 0; ++} ++ ++static struct i2c_device_id tc358743_id[] = { ++ {"tc358743", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, tc358743_id); ++ ++static struct i2c_driver tc358743_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "tc358743", ++ }, ++ .probe = tc358743_probe, ++ .remove = tc358743_remove, ++ .id_table = tc358743_id, ++}; ++ ++module_i2c_driver(tc358743_driver); +diff -Nur linux-3.14.72.orig/drivers/media/i2c/tc358743_regs.h linux-3.14.72/drivers/media/i2c/tc358743_regs.h +--- linux-3.14.72.orig/drivers/media/i2c/tc358743_regs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/i2c/tc358743_regs.h 2016-06-19 22:11:55.169148931 +0200 +@@ -0,0 +1,670 @@ ++/* ++ * tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks ++ * ++ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights ++ * reserved. ++ * ++ * This program is free software; you may redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * 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 THE AUTHORS OR COPYRIGHT HOLDERS ++ * 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. ++ * ++ */ ++ ++/* ++ * References (c = chapter, p = page): ++ * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 ++ */ ++ ++/* Bit masks has prefix 'MASK_' and options after '_'. */ ++ ++#ifndef __TC358743_REGS_H ++#define __TC358743_REGS_H ++ ++#define CHIPID 0x0000 ++#define MASK_CHIPID 0xff00 ++#define MASK_REVID 0x00ff ++ ++#define SYSCTL 0x0002 ++#define MASK_IRRST 0x0800 ++#define MASK_CECRST 0x0400 ++#define MASK_CTXRST 0x0200 ++#define MASK_HDMIRST 0x0100 ++#define MASK_SLEEP 0x0001 ++ ++#define CONFCTL 0x0004 ++#define MASK_PWRISO 0x8000 ++#define MASK_ACLKOPT 0x1000 ++#define MASK_AUDCHNUM 0x0c00 ++#define MASK_AUDCHNUM_8 0x0000 ++#define MASK_AUDCHNUM_6 0x0400 ++#define MASK_AUDCHNUM_4 0x0800 ++#define MASK_AUDCHNUM_2 0x0c00 ++#define MASK_AUDCHSEL 0x0200 ++#define MASK_I2SDLYOPT 0x0100 ++#define MASK_YCBCRFMT 0x00c0 ++#define MASK_YCBCRFMT_444 0x0000 ++#define MASK_YCBCRFMT_422_12_BIT 0x0040 ++#define MASK_YCBCRFMT_COLORBAR 0x0080 ++#define MASK_YCBCRFMT_422_8_BIT 0x00c0 ++#define MASK_INFRMEN 0x0020 ++#define MASK_AUDOUTSEL 0x0018 ++#define MASK_AUDOUTSEL_CSI 0x0000 ++#define MASK_AUDOUTSEL_I2S 0x0010 ++#define MASK_AUDOUTSEL_TDM 0x0018 ++#define MASK_AUTOINDEX 0x0004 ++#define MASK_ABUFEN 0x0002 ++#define MASK_VBUFEN 0x0001 ++ ++#define FIFOCTL 0x0006 ++ ++#define INTSTATUS 0x0014 ++#define MASK_AMUTE_INT 0x0400 ++#define MASK_HDMI_INT 0x0200 ++#define MASK_CSI_INT 0x0100 ++#define MASK_SYS_INT 0x0020 ++#define MASK_CEC_EINT 0x0010 ++#define MASK_CEC_TINT 0x0008 ++#define MASK_CEC_RINT 0x0004 ++#define MASK_IR_EINT 0x0002 ++#define MASK_IR_DINT 0x0001 ++ ++#define INTMASK 0x0016 ++#define MASK_AMUTE_MSK 0x0400 ++#define MASK_HDMI_MSK 0x0200 ++#define MASK_CSI_MSK 0x0100 ++#define MASK_SYS_MSK 0x0020 ++#define MASK_CEC_EMSK 0x0010 ++#define MASK_CEC_TMSK 0x0008 ++#define MASK_CEC_RMSK 0x0004 ++#define MASK_IR_EMSK 0x0002 ++#define MASK_IR_DMSK 0x0001 ++ ++#define INTFLAG 0x0018 ++#define INTSYSSTATUS 0x001A ++ ++#define PLLCTL0 0x0020 ++#define MASK_PLL_PRD 0xf000 ++#define SET_PLL_PRD(prd) ((((prd) - 1) << 12) &\ ++ MASK_PLL_PRD) ++#define MASK_PLL_FBD 0x01ff ++#define SET_PLL_FBD(fbd) (((fbd) - 1) & MASK_PLL_FBD) ++ ++#define PLLCTL1 0x0022 ++#define MASK_PLL_FRS 0x0c00 ++#define SET_PLL_FRS(frs) (((frs) << 10) & MASK_PLL_PRD) ++#define MASK_PLL_LBWS 0x0300 ++#define MASK_LFBREN 0x0040 ++#define MASK_BYPCKEN 0x0020 ++#define MASK_CKEN 0x0010 ++#define MASK_RESETB 0x0002 ++#define MASK_PLL_EN 0x0001 ++ ++#define CLW_CNTRL 0x0140 ++#define MASK_CLW_LANEDISABLE 0x0001 ++ ++#define D0W_CNTRL 0x0144 ++#define MASK_D0W_LANEDISABLE 0x0001 ++ ++#define D1W_CNTRL 0x0148 ++#define MASK_D1W_LANEDISABLE 0x0001 ++ ++#define D2W_CNTRL 0x014C ++#define MASK_D2W_LANEDISABLE 0x0001 ++ ++#define D3W_CNTRL 0x0150 ++#define MASK_D3W_LANEDISABLE 0x0001 ++ ++#define STARTCNTRL 0x0204 ++#define MASK_START 0x00000001 ++ ++#define LINEINITCNT 0x0210 ++#define LPTXTIMECNT 0x0214 ++#define TCLK_HEADERCNT 0x0218 ++#define TCLK_TRAILCNT 0x021C ++#define THS_HEADERCNT 0x0220 ++#define TWAKEUP 0x0224 ++#define TCLK_POSTCNT 0x0228 ++#define THS_TRAILCNT 0x022C ++#define HSTXVREGCNT 0x0230 ++ ++#define HSTXVREGEN 0x0234 ++#define MASK_D3M_HSTXVREGEN 0x0010 ++#define MASK_D2M_HSTXVREGEN 0x0008 ++#define MASK_D1M_HSTXVREGEN 0x0004 ++#define MASK_D0M_HSTXVREGEN 0x0002 ++#define MASK_CLM_HSTXVREGEN 0x0001 ++ ++ ++#define TXOPTIONCNTRL 0x0238 ++#define MASK_CONTCLKMODE 0x00000001 ++ ++#define CSI_CONTROL 0x040C ++#define MASK_CSI_MODE 0x8000 ++#define MASK_HTXTOEN 0x0400 ++#define MASK_TXHSMD 0x0080 ++#define MASK_HSCKMD 0x0020 ++#define MASK_NOL 0x0006 ++#define MASK_NOL_1 0x0000 ++#define MASK_NOL_2 0x0002 ++#define MASK_NOL_3 0x0004 ++#define MASK_NOL_4 0x0006 ++#define MASK_EOTDIS 0x0001 ++ ++#define CSI_INT 0x0414 ++#define MASK_INTHLT 0x00000008 ++#define MASK_INTER 0x00000004 ++ ++#define CSI_INT_ENA 0x0418 ++#define MASK_IENHLT 0x00000008 ++#define MASK_IENER 0x00000004 ++ ++#define CSI_ERR 0x044C ++#define MASK_INER 0x00000200 ++#define MASK_WCER 0x00000100 ++#define MASK_QUNK 0x00000010 ++#define MASK_TXBRK 0x00000002 ++ ++#define CSI_ERR_INTENA 0x0450 ++#define CSI_ERR_HALT 0x0454 ++ ++#define CSI_CONFW 0x0500 ++#define MASK_MODE 0xe0000000 ++#define MASK_MODE_SET 0xa0000000 ++#define MASK_MODE_CLEAR 0xc0000000 ++#define MASK_ADDRESS 0x1f000000 ++#define MASK_ADDRESS_CSI_CONTROL 0x03000000 ++#define MASK_ADDRESS_CSI_INT_ENA 0x06000000 ++#define MASK_ADDRESS_CSI_ERR_INTENA 0x14000000 ++#define MASK_ADDRESS_CSI_ERR_HALT 0x15000000 ++#define MASK_DATA 0x0000ffff ++ ++#define CSI_INT_CLR 0x050C ++#define MASK_ICRER 0x00000004 ++ ++#define CSI_START 0x0518 ++#define MASK_STRT 0x00000001 ++ ++#define CECEN 0x0600 ++#define MASK_CECEN 0x0001 ++ ++#define HDMI_INT0 0x8500 ++#define MASK_I_KEY 0x80 ++#define MASK_I_MISC 0x02 ++#define MASK_I_PHYERR 0x01 ++ ++#define HDMI_INT1 0x8501 ++#define MASK_I_GBD 0x80 ++#define MASK_I_HDCP 0x40 ++#define MASK_I_ERR 0x20 ++#define MASK_I_AUD 0x10 ++#define MASK_I_CBIT 0x08 ++#define MASK_I_PACKET 0x04 ++#define MASK_I_CLK 0x02 ++#define MASK_I_SYS 0x01 ++ ++#define SYS_INT 0x8502 ++#define MASK_I_ACR_CTS 0x80 ++#define MASK_I_ACRN 0x40 ++#define MASK_I_DVI 0x20 ++#define MASK_I_HDMI 0x10 ++#define MASK_I_NOPMBDET 0x08 ++#define MASK_I_DPMBDET 0x04 ++#define MASK_I_TMDS 0x02 ++#define MASK_I_DDC 0x01 ++ ++#define CLK_INT 0x8503 ++#define MASK_I_OUT_H_CHG 0x40 ++#define MASK_I_IN_DE_CHG 0x20 ++#define MASK_I_IN_HV_CHG 0x10 ++#define MASK_I_DC_CHG 0x08 ++#define MASK_I_PXCLK_CHG 0x04 ++#define MASK_I_PHYCLK_CHG 0x02 ++#define MASK_I_TMDSCLK_CHG 0x01 ++ ++#define CBIT_INT 0x8505 ++#define MASK_I_AF_LOCK 0x80 ++#define MASK_I_AF_UNLOCK 0x40 ++#define MASK_I_CBIT_FS 0x02 ++ ++#define ERR_INT 0x8507 ++#define MASK_I_EESS_ERR 0x80 ++ ++#define HDCP_INT 0x8508 ++#define MASK_I_AVM_SET 0x80 ++#define MASK_I_AVM_CLR 0x40 ++#define MASK_I_LINKERR 0x20 ++#define MASK_I_SHA_END 0x10 ++#define MASK_I_R0_END 0x08 ++#define MASK_I_KM_END 0x04 ++#define MASK_I_AKSV_END 0x02 ++#define MASK_I_AN_END 0x01 ++ ++#define MISC_INT 0x850B ++#define MASK_I_AS_LAYOUT 0x10 ++#define MASK_I_NO_SPD 0x08 ++#define MASK_I_NO_VS 0x03 ++#define MASK_I_SYNC_CHG 0x02 ++#define MASK_I_AUDIO_MUTE 0x01 ++ ++#define KEY_INT 0x850F ++ ++#define SYS_INTM 0x8512 ++#define MASK_M_ACR_CTS 0x80 ++#define MASK_M_ACR_N 0x40 ++#define MASK_M_DVI_DET 0x20 ++#define MASK_M_HDMI_DET 0x10 ++#define MASK_M_NOPMBDET 0x08 ++#define MASK_M_BPMBDET 0x04 ++#define MASK_M_TMDS 0x02 ++#define MASK_M_DDC 0x01 ++ ++#define CLK_INTM 0x8513 ++#define MASK_M_OUT_H_CHG 0x40 ++#define MASK_M_IN_DE_CHG 0x20 ++#define MASK_M_IN_HV_CHG 0x10 ++#define MASK_M_DC_CHG 0x08 ++#define MASK_M_PXCLK_CHG 0x04 ++#define MASK_M_PHYCLK_CHG 0x02 ++#define MASK_M_TMDS_CHG 0x01 ++ ++#define PACKET_INTM 0x8514 ++ ++#define CBIT_INTM 0x8515 ++#define MASK_M_AF_LOCK 0x80 ++#define MASK_M_AF_UNLOCK 0x40 ++#define MASK_M_CBIT_FS 0x02 ++ ++#define AUDIO_INTM 0x8516 ++ ++#define ERR_INTM 0x8517 ++#define MASK_M_EESS_ERR 0x80 ++ ++#define HDCP_INTM 0x8518 ++#define MASK_M_AVM_SET 0x80 ++#define MASK_M_AVM_CLR 0x40 ++#define MASK_M_LINKERR 0x20 ++#define MASK_M_SHA_END 0x10 ++#define MASK_M_R0_END 0x08 ++#define MASK_M_KM_END 0x04 ++#define MASK_M_AKSV_END 0x02 ++#define MASK_M_AN_END 0x01 ++ ++#define MISC_INTM 0x851B ++#define MASK_M_AS_LAYOUT 0x10 ++#define MASK_M_NO_SPD 0x08 ++#define MASK_M_NO_VS 0x03 ++#define MASK_M_SYNC_CHG 0x02 ++#define MASK_M_AUDIO_MUTE 0x01 ++ ++#define KEY_INTM 0x851F ++ ++#define SYS_STATUS 0x8520 ++#define MASK_S_SYNC 0x80 ++#define MASK_S_AVMUTE 0x40 ++#define MASK_S_HDCP 0x20 ++#define MASK_S_HDMI 0x10 ++#define MASK_S_PHY_SCDT 0x08 ++#define MASK_S_PHY_PLL 0x04 ++#define MASK_S_TMDS 0x02 ++#define MASK_S_DDC5V 0x01 ++ ++#define CSI_STATUS 0x0410 ++#define MASK_S_WSYNC 0x0400 ++#define MASK_S_TXACT 0x0200 ++#define MASK_S_RXACT 0x0100 ++#define MASK_S_HLT 0x0001 ++ ++#define VI_STATUS1 0x8522 ++#define MASK_S_V_GBD 0x08 ++#define MASK_S_DEEPCOLOR 0x0c ++#define MASK_S_V_422 0x02 ++#define MASK_S_V_INTERLACE 0x01 ++ ++#define AU_STATUS0 0x8523 ++#define MASK_S_A_SAMPLE 0x01 ++ ++#define VI_STATUS3 0x8528 ++#define MASK_S_V_COLOR 0x1e ++#define MASK_LIMITED 0x01 ++ ++#define PHY_CTL0 0x8531 ++#define MASK_PHY_SYSCLK_IND 0x02 ++#define MASK_PHY_CTL 0x01 ++ ++ ++#define PHY_CTL1 0x8532 /* Not in REF_01 */ ++#define MASK_PHY_AUTO_RST1 0xf0 ++#define MASK_PHY_AUTO_RST1_OFF 0x00 ++#define SET_PHY_AUTO_RST1_US(us) ((((us) / 200) << 4) & \ ++ MASK_PHY_AUTO_RST1) ++#define MASK_FREQ_RANGE_MODE 0x0f ++#define SET_FREQ_RANGE_MODE_CYCLES(cycles) (((cycles) - 1) & \ ++ MASK_FREQ_RANGE_MODE) ++ ++#define PHY_CTL2 0x8533 /* Not in REF_01 */ ++#define MASK_PHY_AUTO_RST4 0x04 ++#define MASK_PHY_AUTO_RST3 0x02 ++#define MASK_PHY_AUTO_RST2 0x01 ++#define MASK_PHY_AUTO_RSTn (MASK_PHY_AUTO_RST4 | \ ++ MASK_PHY_AUTO_RST3 | \ ++ MASK_PHY_AUTO_RST2) ++ ++#define PHY_EN 0x8534 ++#define MASK_ENABLE_PHY 0x01 ++ ++#define PHY_RST 0x8535 ++#define MASK_RESET_CTRL 0x01 /* Reset active low */ ++ ++#define PHY_BIAS 0x8536 /* Not in REF_01 */ ++ ++#define PHY_CSQ 0x853F /* Not in REF_01 */ ++#define MASK_CSQ_CNT 0x0f ++#define SET_CSQ_CNT_LEVEL(n) (n & MASK_CSQ_CNT) ++ ++#define SYS_FREQ0 0x8540 ++#define SYS_FREQ1 0x8541 ++ ++#define SYS_CLK 0x8542 /* Not in REF_01 */ ++#define MASK_CLK_DIFF 0x0C ++#define MASK_CLK_DIV 0x03 ++ ++#define DDC_CTL 0x8543 ++#define MASK_DDC_ACK_POL 0x08 ++#define MASK_DDC_ACTION 0x04 ++#define MASK_DDC5V_MODE 0x03 ++#define MASK_DDC5V_MODE_0MS 0x00 ++#define MASK_DDC5V_MODE_50MS 0x01 ++#define MASK_DDC5V_MODE_100MS 0x02 ++#define MASK_DDC5V_MODE_200MS 0x03 ++ ++#define HPD_CTL 0x8544 ++#define MASK_HPD_CTL0 0x10 ++#define MASK_HPD_OUT0 0x01 ++ ++#define ANA_CTL 0x8545 ++#define MASK_APPL_PCSX 0x30 ++#define MASK_APPL_PCSX_HIZ 0x00 ++#define MASK_APPL_PCSX_L_FIX 0x10 ++#define MASK_APPL_PCSX_H_FIX 0x20 ++#define MASK_APPL_PCSX_NORMAL 0x30 ++#define MASK_ANALOG_ON 0x01 ++ ++#define AVM_CTL 0x8546 ++ ++#define INIT_END 0x854A ++#define MASK_INIT_END 0x01 ++ ++#define HDMI_DET 0x8552 ++#define MASK_HDMI_DET_MOD1 0x80 ++#define MASK_HDMI_DET_MOD0 0x40 ++#define MASK_HDMI_DET_V 0x30 ++#define MASK_HDMI_DET_V_SYNC 0x00 ++#define MASK_HDMI_DET_V_ASYNC_25MS 0x10 ++#define MASK_HDMI_DET_V_ASYNC_50MS 0x20 ++#define MASK_HDMI_DET_V_ASYNC_100MS 0x30 ++#define MASK_HDMI_DET_NUM 0x0f ++ ++#define HDCP_MODE 0x8560 ++#define MASK_MODE_RST_TN 0x20 ++#define MASK_LINE_REKEY 0x10 ++#define MASK_AUTO_CLR 0x04 ++ ++#define HDCP_REG1 0x8563 /* Not in REF_01 */ ++#define MASK_AUTH_UNAUTH_SEL 0x70 ++#define MASK_AUTH_UNAUTH_SEL_12_FRAMES 0x70 ++#define MASK_AUTH_UNAUTH_SEL_8_FRAMES 0x60 ++#define MASK_AUTH_UNAUTH_SEL_4_FRAMES 0x50 ++#define MASK_AUTH_UNAUTH_SEL_2_FRAMES 0x40 ++#define MASK_AUTH_UNAUTH_SEL_64_FRAMES 0x30 ++#define MASK_AUTH_UNAUTH_SEL_32_FRAMES 0x20 ++#define MASK_AUTH_UNAUTH_SEL_16_FRAMES 0x10 ++#define MASK_AUTH_UNAUTH_SEL_ONCE 0x00 ++#define MASK_AUTH_UNAUTH 0x01 ++#define MASK_AUTH_UNAUTH_AUTO 0x01 ++ ++#define HDCP_REG2 0x8564 /* Not in REF_01 */ ++#define MASK_AUTO_P3_RESET 0x0F ++#define SET_AUTO_P3_RESET_FRAMES(n) (n & MASK_AUTO_P3_RESET) ++#define MASK_AUTO_P3_RESET_OFF 0x00 ++ ++#define VOUT_SET2 0x8573 ++#define MASK_SEL422 0x80 ++#define MASK_VOUT_422FIL_100 0x40 ++#define MASK_VOUTCOLORMODE 0x03 ++#define MASK_VOUTCOLORMODE_THROUGH 0x00 ++#define MASK_VOUTCOLORMODE_AUTO 0x01 ++#define MASK_VOUTCOLORMODE_MANUAL 0x03 ++ ++#define VOUT_SET3 0x8574 ++#define MASK_VOUT_EXTCNT 0x08 ++ ++#define VI_REP 0x8576 ++#define MASK_VOUT_COLOR_SEL 0xe0 ++#define MASK_VOUT_COLOR_RGB_FULL 0x00 ++#define MASK_VOUT_COLOR_RGB_LIMITED 0x20 ++#define MASK_VOUT_COLOR_601_YCBCR_FULL 0x40 ++#define MASK_VOUT_COLOR_601_YCBCR_LIMITED 0x60 ++#define MASK_VOUT_COLOR_709_YCBCR_FULL 0x80 ++#define MASK_VOUT_COLOR_709_YCBCR_LIMITED 0xa0 ++#define MASK_VOUT_COLOR_FULL_TO_LIMITED 0xc0 ++#define MASK_VOUT_COLOR_LIMITED_TO_FULL 0xe0 ++#define MASK_IN_REP_HEN 0x10 ++#define MASK_IN_REP 0x0f ++ ++#define DE_WIDTH_H_LO 0x8582 /* Not in REF_01 */ ++#define DE_WIDTH_H_HI 0x8583 /* Not in REF_01 */ ++#define DE_WIDTH_V_LO 0x8588 /* Not in REF_01 */ ++#define DE_WIDTH_V_HI 0x8589 /* Not in REF_01 */ ++#define H_SIZE_LO 0x858A /* Not in REF_01 */ ++#define H_SIZE_HI 0x858B /* Not in REF_01 */ ++#define V_SIZE_LO 0x858C /* Not in REF_01 */ ++#define V_SIZE_HI 0x858D /* Not in REF_01 */ ++#define FV_CNT_LO 0x85A1 /* Not in REF_01 */ ++#define FV_CNT_HI 0x85A2 /* Not in REF_01 */ ++ ++#define FH_MIN0 0x85AA /* Not in REF_01 */ ++#define FH_MIN1 0x85AB /* Not in REF_01 */ ++#define FH_MAX0 0x85AC /* Not in REF_01 */ ++#define FH_MAX1 0x85AD /* Not in REF_01 */ ++#define HV_RST 0x85AF /* Not in REF_01 */ ++#define MASK_H_PI_RST 0x20 ++#define MASK_V_PI_RST 0x10 ++ ++#define EDID_MODE 0x85C7 ++#define MASK_EDID_SPEED 0x40 ++#define MASK_EDID_MODE 0x03 ++#define MASK_EDID_MODE_DISABLE 0x00 ++#define MASK_EDID_MODE_DDC2B 0x01 ++#define MASK_EDID_MODE_E_DDC 0x02 ++ ++#define EDID_LEN1 0x85CA ++#define EDID_LEN2 0x85CB ++ ++#define HDCP_REG3 0x85D1 /* Not in REF_01 */ ++#define KEY_RD_CMD 0x01 ++ ++#define FORCE_MUTE 0x8600 ++#define MASK_FORCE_AMUTE 0x10 ++#define MASK_FORCE_DMUTE 0x01 ++ ++#define CMD_AUD 0x8601 ++#define MASK_CMD_BUFINIT 0x04 ++#define MASK_CMD_LOCKDET 0x02 ++#define MASK_CMD_MUTE 0x01 ++ ++#define AUTO_CMD0 0x8602 ++#define MASK_AUTO_MUTE7 0x80 ++#define MASK_AUTO_MUTE6 0x40 ++#define MASK_AUTO_MUTE5 0x20 ++#define MASK_AUTO_MUTE4 0x10 ++#define MASK_AUTO_MUTE3 0x08 ++#define MASK_AUTO_MUTE2 0x04 ++#define MASK_AUTO_MUTE1 0x02 ++#define MASK_AUTO_MUTE0 0x01 ++ ++#define AUTO_CMD1 0x8603 ++#define MASK_AUTO_MUTE10 0x04 ++#define MASK_AUTO_MUTE9 0x02 ++#define MASK_AUTO_MUTE8 0x01 ++ ++#define AUTO_CMD2 0x8604 ++#define MASK_AUTO_PLAY3 0x08 ++#define MASK_AUTO_PLAY2 0x04 ++ ++#define BUFINIT_START 0x8606 ++#define SET_BUFINIT_START_MS(milliseconds) ((milliseconds) / 100) ++ ++#define FS_MUTE 0x8607 ++#define MASK_FS_ELSE_MUTE 0x80 ++#define MASK_FS22_MUTE 0x40 ++#define MASK_FS24_MUTE 0x20 ++#define MASK_FS88_MUTE 0x10 ++#define MASK_FS96_MUTE 0x08 ++#define MASK_FS176_MUTE 0x04 ++#define MASK_FS192_MUTE 0x02 ++#define MASK_FS_NO_MUTE 0x01 ++ ++#define FS_IMODE 0x8620 ++#define MASK_NLPCM_HMODE 0x40 ++#define MASK_NLPCM_SMODE 0x20 ++#define MASK_NLPCM_IMODE 0x10 ++#define MASK_FS_HMODE 0x08 ++#define MASK_FS_AMODE 0x04 ++#define MASK_FS_SMODE 0x02 ++#define MASK_FS_IMODE 0x01 ++ ++#define FS_SET 0x8621 ++#define MASK_FS 0x0f ++ ++#define LOCKDET_REF0 0x8630 ++#define LOCKDET_REF1 0x8631 ++#define LOCKDET_REF2 0x8632 ++ ++#define ACR_MODE 0x8640 ++#define MASK_ACR_LOAD 0x10 ++#define MASK_N_MODE 0x04 ++#define MASK_CTS_MODE 0x01 ++ ++#define ACR_MDF0 0x8641 ++#define MASK_ACR_L2MDF 0x70 ++#define MASK_ACR_L2MDF_0_PPM 0x00 ++#define MASK_ACR_L2MDF_61_PPM 0x10 ++#define MASK_ACR_L2MDF_122_PPM 0x20 ++#define MASK_ACR_L2MDF_244_PPM 0x30 ++#define MASK_ACR_L2MDF_488_PPM 0x40 ++#define MASK_ACR_L2MDF_976_PPM 0x50 ++#define MASK_ACR_L2MDF_1976_PPM 0x60 ++#define MASK_ACR_L2MDF_3906_PPM 0x70 ++#define MASK_ACR_L1MDF 0x07 ++#define MASK_ACR_L1MDF_0_PPM 0x00 ++#define MASK_ACR_L1MDF_61_PPM 0x01 ++#define MASK_ACR_L1MDF_122_PPM 0x02 ++#define MASK_ACR_L1MDF_244_PPM 0x03 ++#define MASK_ACR_L1MDF_488_PPM 0x04 ++#define MASK_ACR_L1MDF_976_PPM 0x05 ++#define MASK_ACR_L1MDF_1976_PPM 0x06 ++#define MASK_ACR_L1MDF_3906_PPM 0x07 ++ ++#define ACR_MDF1 0x8642 ++#define MASK_ACR_L3MDF 0x07 ++#define MASK_ACR_L3MDF_0_PPM 0x00 ++#define MASK_ACR_L3MDF_61_PPM 0x01 ++#define MASK_ACR_L3MDF_122_PPM 0x02 ++#define MASK_ACR_L3MDF_244_PPM 0x03 ++#define MASK_ACR_L3MDF_488_PPM 0x04 ++#define MASK_ACR_L3MDF_976_PPM 0x05 ++#define MASK_ACR_L3MDF_1976_PPM 0x06 ++#define MASK_ACR_L3MDF_3906_PPM 0x07 ++ ++#define SDO_MODE1 0x8652 ++#define MASK_SDO_BIT_LENG 0x70 ++#define MASK_SDO_FMT 0x03 ++#define MASK_SDO_FMT_RIGHT 0x00 ++#define MASK_SDO_FMT_LEFT 0x01 ++#define MASK_SDO_FMT_I2S 0x02 ++ ++#define DIV_MODE 0x8665 /* Not in REF_01 */ ++#define MASK_DIV_DLY 0xf0 ++#define SET_DIV_DLY_MS(milliseconds) ((((milliseconds) / 100) << 4) & \ ++ MASK_DIV_DLY) ++#define MASK_DIV_MODE 0x01 ++ ++#define NCO_F0_MOD 0x8670 ++#define MASK_NCO_F0_MOD 0x03 ++#define MASK_NCO_F0_MOD_42MHZ 0x00 ++#define MASK_NCO_F0_MOD_27MHZ 0x01 ++ ++#define PK_INT_MODE 0x8709 ++#define MASK_ISRC2_INT_MODE 0x80 ++#define MASK_ISRC_INT_MODE 0x40 ++#define MASK_ACP_INT_MODE 0x20 ++#define MASK_VS_INT_MODE 0x10 ++#define MASK_SPD_INT_MODE 0x08 ++#define MASK_MS_INT_MODE 0x04 ++#define MASK_AUD_INT_MODE 0x02 ++#define MASK_AVI_INT_MODE 0x01 ++ ++#define NO_PKT_LIMIT 0x870B ++#define MASK_NO_ACP_LIMIT 0xf0 ++#define SET_NO_ACP_LIMIT_MS(milliseconds) ((((milliseconds) / 80) << 4) & \ ++ MASK_NO_ACP_LIMIT) ++#define MASK_NO_AVI_LIMIT 0x0f ++#define SET_NO_AVI_LIMIT_MS(milliseconds) (((milliseconds) / 80) & \ ++ MASK_NO_AVI_LIMIT) ++ ++#define NO_PKT_CLR 0x870C ++#define MASK_NO_VS_CLR 0x40 ++#define MASK_NO_SPD_CLR 0x20 ++#define MASK_NO_ACP_CLR 0x10 ++#define MASK_NO_AVI_CLR1 0x02 ++#define MASK_NO_AVI_CLR0 0x01 ++ ++#define ERR_PK_LIMIT 0x870D ++#define NO_PKT_LIMIT2 0x870E ++#define PK_AVI_0HEAD 0x8710 ++#define PK_AVI_1HEAD 0x8711 ++#define PK_AVI_2HEAD 0x8712 ++#define PK_AVI_0BYTE 0x8713 ++#define PK_AVI_1BYTE 0x8714 ++#define PK_AVI_2BYTE 0x8715 ++#define PK_AVI_3BYTE 0x8716 ++#define PK_AVI_4BYTE 0x8717 ++#define PK_AVI_5BYTE 0x8718 ++#define PK_AVI_6BYTE 0x8719 ++#define PK_AVI_7BYTE 0x871A ++#define PK_AVI_8BYTE 0x871B ++#define PK_AVI_9BYTE 0x871C ++#define PK_AVI_10BYTE 0x871D ++#define PK_AVI_11BYTE 0x871E ++#define PK_AVI_12BYTE 0x871F ++#define PK_AVI_13BYTE 0x8720 ++#define PK_AVI_14BYTE 0x8721 ++#define PK_AVI_15BYTE 0x8722 ++#define PK_AVI_16BYTE 0x8723 ++ ++#define BKSV 0x8800 ++ ++#define BCAPS 0x8840 ++#define MASK_HDMI_RSVD 0x80 ++#define MASK_REPEATER 0x40 ++#define MASK_READY 0x20 ++#define MASK_FASTI2C 0x10 ++#define MASK_1_1_FEA 0x02 ++#define MASK_FAST_REAU 0x01 ++ ++#define BSTATUS1 0x8842 ++#define MASK_MAX_EXCED 0x08 ++ ++#define EDID_RAM 0x8C00 ++#define NO_GDB_LIMIT 0x9007 ++ ++#endif +diff -Nur linux-3.14.72.orig/drivers/media/pci/cx88/cx88-core.c linux-3.14.72/drivers/media/pci/cx88/cx88-core.c +--- linux-3.14.72.orig/drivers/media/pci/cx88/cx88-core.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/pci/cx88/cx88-core.c 2016-06-19 22:11:55.169148931 +0200 +@@ -1034,14 +1034,7 @@ + if (NULL == vfd) + return NULL; + *vfd = *template_; +- /* +- * The dev pointer of v4l2_device is NULL, instead we set the +- * video_device dev_parent pointer to the correct PCI bus device. +- * This driver is a rare example where there is one v4l2_device, +- * but the video nodes have different parent (PCI) devices. +- */ + vfd->v4l2_dev = &core->v4l2_dev; +- vfd->dev_parent = &pci->dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + core->name, type, core->board.name); +diff -Nur linux-3.14.72.orig/drivers/media/pci/Kconfig linux-3.14.72/drivers/media/pci/Kconfig +--- linux-3.14.72.orig/drivers/media/pci/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/pci/Kconfig 2016-06-19 22:11:55.169148931 +0200 +@@ -12,6 +12,7 @@ + comment "Media capture support" + source "drivers/media/pci/meye/Kconfig" + source "drivers/media/pci/sta2x11/Kconfig" ++source "drivers/media/pci/tw6869/Kconfig" + endif + + if MEDIA_ANALOG_TV_SUPPORT +diff -Nur linux-3.14.72.orig/drivers/media/pci/Makefile linux-3.14.72/drivers/media/pci/Makefile +--- linux-3.14.72.orig/drivers/media/pci/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/pci/Makefile 2016-06-19 22:11:55.169148931 +0200 +@@ -24,3 +24,4 @@ + obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ + obj-$(CONFIG_VIDEO_MEYE) += meye/ + obj-$(CONFIG_STA2X11_VIP) += sta2x11/ ++obj-$(CONFIG_VIDEO_TW6869) += tw6869/ +diff -Nur linux-3.14.72.orig/drivers/media/pci/tw6869/Kconfig linux-3.14.72/drivers/media/pci/tw6869/Kconfig +--- linux-3.14.72.orig/drivers/media/pci/tw6869/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/pci/tw6869/Kconfig 2016-06-19 22:11:55.169148931 +0200 +@@ -0,0 +1,9 @@ ++config VIDEO_TW6869 ++ tristate "Techwell tw6869 Video For Linux" ++ depends on VIDEO_DEV && PCI && VIDEO_V4L2 ++ select VIDEOBUF2_DMA_CONTIG ++ ---help--- ++ Support for Techwell tw6869 based frame grabber boards. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called tw6869. +diff -Nur linux-3.14.72.orig/drivers/media/pci/tw6869/Makefile linux-3.14.72/drivers/media/pci/tw6869/Makefile +--- linux-3.14.72.orig/drivers/media/pci/tw6869/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/pci/tw6869/Makefile 2016-06-19 22:11:55.169148931 +0200 +@@ -0,0 +1 @@ ++obj-$(CONFIG_VIDEO_TW6869) += tw6869.o +diff -Nur linux-3.14.72.orig/drivers/media/pci/tw6869/tw6869.c linux-3.14.72/drivers/media/pci/tw6869/tw6869.c +--- linux-3.14.72.orig/drivers/media/pci/tw6869/tw6869.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/pci/tw6869/tw6869.c 2016-06-19 22:11:55.169148931 +0200 +@@ -0,0 +1,1439 @@ ++/* ++ * Copyright 2015 www.starterkit.ru ++ * ++ * Based on: ++ * Driver for Intersil|Techwell TW6869 based DVR cards ++ * (c) 2011-12 liran [Intersil|Techwell China] ++ * ++ * V4L2 PCI Skeleton Driver ++ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. ++ * All rights reserved. ++ * ++ * This program is free software; you may redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * 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 THE AUTHORS OR COPYRIGHT HOLDERS ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "tw6869.h" ++ ++MODULE_DESCRIPTION("tw6869/65 media bridge driver"); ++MODULE_AUTHOR("starterkit "); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("0.3.2"); ++ ++static const struct pci_device_id tw6869_pci_tbl[] = { ++ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6869)}, ++ { 0, } ++}; ++ ++struct tw6869_buf { ++ struct vb2_buffer vb; ++ struct list_head list; ++ dma_addr_t dma; ++}; ++ ++/** ++ * struct tw6869_vch - instance of one video channel ++ * @dev: parent device ++ * @vdev: video channel (v4l2 video device) ++ * @id: DMA id (0...7) ++ * @p_buf: DMA P-buffer ++ * @b_buf: DMA B-buffer ++ * @pb: P-buffer | B-buffer ping-pong state ++ * @mlock: the main serialization lock ++ * @queue: queue maintained by videobuf2 layer ++ * @buf_list: list of buffer in use ++ * @lock: spinlock controlling access to channel ++ * @hdl: handler for control framework ++ * @format: pixel format ++ * @std: video standard (e.g. PAL/NTSC) ++ * @input: input line for video signal ++ * @sequence: sequence number of acquired buffer ++ * @dcount: number of dropped frames ++ * @fps: current frame rate ++ */ ++struct tw6869_vch { ++ struct tw6869_dev *dev; ++ struct video_device vdev; ++ ++ unsigned int id; ++ struct tw6869_buf *p_buf; ++ struct tw6869_buf *b_buf; ++ unsigned int pb; ++ ++ struct mutex mlock; ++ struct vb2_queue queue; ++ struct list_head buf_list; ++ spinlock_t lock; ++ ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_pix_format format; ++ v4l2_std_id std; ++ unsigned int input; ++ ++ unsigned int sequence; ++ unsigned int dcount; ++ unsigned int fps; ++}; ++ ++/** ++ * struct tw6869_ach - instance of one audio channel ++ * @dev: parent device ++ * @ss: audio channel (pcm substream) ++ * @id: DMA id (8...15) ++ * @p_buf: DMA P-buffer ++ * @b_buf: DMA B-buffer ++ * @pb: P-buffer | B-buffer ping-pong state ++ * @buf: split an contiguous buffer into chunks ++ * @buf_list: chunk list ++ * @lock: spinlock controlling access to channel ++ * @ptr: PCM buffer pointer ++ */ ++struct tw6869_ach { ++ struct tw6869_dev *dev; ++ struct snd_pcm_substream *ss; ++ ++ unsigned int id; ++ struct tw6869_buf *p_buf; ++ struct tw6869_buf *b_buf; ++ unsigned int pb; ++ ++ struct tw6869_buf buf[TW_APAGE_MAX]; ++ struct list_head buf_list; ++ spinlock_t lock; ++ ++ dma_addr_t ptr; ++}; ++ ++/** ++ * struct tw6869_dev - instance of device ++ * @pdev: PCI device ++ * @mmio: hardware base address ++ * @rlock: spinlock controlling access to registers ++ * @ch_max: channels used ++ * @id_err: DMA error counters ++ * @v4l2_dev: device registered in v4l2 layer ++ * @alloc_ctx: context for videobuf2 ++ * @vch: array of video channel instance ++ * @snd_card: device registered in ALSA layer ++ * @ach: array of audio channel instance ++ */ ++struct tw6869_dev { ++ struct pci_dev *pdev; ++ unsigned char __iomem *mmio; ++ spinlock_t rlock; ++ ++ unsigned int ch_max; ++ unsigned int id_err[2 * TW_CH_MAX]; ++ ++ struct v4l2_device v4l2_dev; ++ struct vb2_alloc_ctx *alloc_ctx; ++ struct tw6869_vch vch[TW_CH_MAX]; ++ ++ struct snd_card *snd_card; ++ struct tw6869_ach ach[TW_CH_MAX]; ++}; ++ ++/**********************************************************************/ ++ ++static inline void tw_write(struct tw6869_dev *dev, unsigned int reg, ++ unsigned int val) ++{ ++ iowrite32(val, dev->mmio + reg); ++} ++ ++static inline unsigned int tw_read(struct tw6869_dev *dev, ++ unsigned int reg) ++{ ++ return ioread32(dev->mmio + reg); ++} ++ ++static inline void tw_write_mask(struct tw6869_dev *dev, ++ unsigned int reg, unsigned int val, unsigned int mask) ++{ ++ unsigned int v = tw_read(dev, reg); ++ ++ v = (v & ~mask) | (val & mask); ++ tw_write(dev, reg, v); ++} ++ ++static inline void tw_clear(struct tw6869_dev *dev, ++ unsigned int reg, unsigned int val) ++{ ++ tw_write_mask(dev, reg, 0, val); ++} ++ ++static inline void tw_set(struct tw6869_dev *dev, ++ unsigned int reg, unsigned int val) ++{ ++ tw_write_mask(dev, reg, val, val); ++} ++ ++static inline unsigned int tw_id_is_on(struct tw6869_dev *dev, ++ unsigned int id) ++{ ++ unsigned int e = tw_read(dev, R32_DMA_CHANNEL_ENABLE); ++ unsigned int c = tw_read(dev, R32_DMA_CMD); ++ ++ return (c & BIT(31)) && (c & e & BIT_ID(id)); ++} ++ ++static inline unsigned int tw_id_is_off(struct tw6869_dev *dev, ++ unsigned int id) ++{ ++ unsigned int e = tw_read(dev, R32_DMA_CHANNEL_ENABLE); ++ unsigned int c = tw_read(dev, R32_DMA_CMD); ++ ++ return !((c | e) & BIT_ID(id)); ++} ++ ++static inline void tw_id_on(struct tw6869_dev *dev, unsigned int id) ++{ ++ int c = 3; ++ ++ while (!tw_id_is_on(dev, id) && c--) { ++ tw_set(dev, R32_DMA_CMD, BIT(31) | BIT_ID(id)); ++ tw_set(dev, R32_DMA_CHANNEL_ENABLE, BIT_ID(id)); ++ } ++} ++ ++static inline void tw_id_off(struct tw6869_dev *dev, unsigned int id) ++{ ++ int c = 3; ++ ++ while (!tw_id_is_off(dev, id) && c--) { ++ tw_clear(dev, R32_DMA_CMD, BIT_ID(id)); ++ tw_clear(dev, R32_DMA_CHANNEL_ENABLE, BIT_ID(id)); ++ } ++ ++ if (!tw_read(dev, R32_DMA_CHANNEL_ENABLE)) ++ tw_write(dev, R32_DMA_CMD, 0); ++} ++ ++static void tw6869_id_dma_cmd(struct tw6869_dev *dev, ++ unsigned int id, ++ unsigned int cmd) ++{ ++ switch (cmd) { ++ case TW_DMA_ON: ++ dev->id_err[ID2ID(id)] = 0; ++ tw_id_on(dev, id); ++ dev_info(&dev->pdev->dev, "DMA %u ON\n", id); ++ break; ++ case TW_DMA_OFF: ++ tw_id_off(dev, id); ++ dev_info(&dev->pdev->dev, "DMA %u OFF\n", id); ++ break; ++ case TW_DMA_RST: ++ if (tw_id_is_on(dev, id)) { ++ tw_id_off(dev, id); ++ if (++dev->id_err[ID2ID(id)] > TW_DMA_ERR_MAX) { ++ dev_err(&dev->pdev->dev, "DMA %u forced OFF\n", id); ++ break; ++ } ++ tw_id_on(dev, id); ++ dev_info(&dev->pdev->dev, "DMA %u RST\n", id); ++ } else { ++ dev_info(&dev->pdev->dev, "DMA %u spurious RST\n", id); ++ } ++ break; ++ default: ++ dev_err(&dev->pdev->dev, "DMA %u unknown cmd %u\n", id, cmd); ++ } ++} ++ ++static unsigned int tw6869_virq(struct tw6869_dev *dev, ++ unsigned int id, ++ unsigned int pb, ++ unsigned int err) ++{ ++ struct tw6869_vch *vch = &dev->vch[ID2CH(id)]; ++ struct tw6869_buf *done = NULL; ++ struct tw6869_buf *next = NULL; ++ ++ spin_lock(&vch->lock); ++ if (!vb2_is_streaming(&vch->queue) || !vch->p_buf || !vch->b_buf) { ++ spin_unlock(&vch->lock); ++ return TW_DMA_OFF; ++ } ++ ++ if (err || (vch->pb != pb)) { ++ vch->pb = 0; ++ spin_unlock(&vch->lock); ++ return TW_DMA_RST; ++ } ++ ++ if (!list_empty(&vch->buf_list)) { ++ next = list_first_entry(&vch->buf_list, struct tw6869_buf, list); ++ list_del(&next->list); ++ if (pb) { ++ done = vch->b_buf; ++ vch->b_buf = next; ++ } else { ++ done = vch->p_buf; ++ vch->p_buf = next; ++ } ++ } ++ vch->pb = !pb; ++ spin_unlock(&vch->lock); ++ ++ if (done && next) { ++ tw_write(dev, pb ? R32_DMA_B_ADDR(id) : R32_DMA_P_ADDR(id), next->dma); ++ v4l2_get_timestamp(&done->vb.v4l2_buf.timestamp); ++ done->vb.v4l2_buf.sequence = vch->sequence++; ++ vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE); ++ } else { ++ dev_info(&dev->pdev->dev, "vch%u NOBUF seq=%u dcount=%u\n", ++ ID2CH(id), vch->sequence, ++vch->dcount); ++ } ++ return 0; ++} ++ ++static unsigned int tw6869_airq(struct tw6869_dev *dev, ++ unsigned int id, ++ unsigned int pb) ++{ ++ struct tw6869_ach *ach = &dev->ach[ID2CH(id)]; ++ struct tw6869_buf *done = NULL; ++ struct tw6869_buf *next = NULL; ++ ++ spin_lock(&ach->lock); ++ if (!ach->ss || !ach->p_buf || !ach->b_buf) { ++ spin_unlock(&ach->lock); ++ return TW_DMA_OFF; ++ } ++ ++ if (ach->pb != pb) { ++ ach->pb = 0; ++ spin_unlock(&ach->lock); ++ return TW_DMA_RST; ++ } ++ ++ if (!list_empty(&ach->buf_list)) { ++ next = list_first_entry(&ach->buf_list, struct tw6869_buf, list); ++ list_move_tail(&next->list, &ach->buf_list); ++ if (pb) { ++ done = ach->p_buf; ++ ach->b_buf = next; ++ } else { ++ done = ach->b_buf; ++ ach->p_buf = next; ++ } ++ } ++ ach->pb = !pb; ++ spin_unlock(&ach->lock); ++ ++ if (done && next) { ++ tw_write(dev, pb ? R32_DMA_B_ADDR(id) : R32_DMA_P_ADDR(id), next->dma); ++ ach->ptr = done->dma - ach->buf[0].dma; ++ snd_pcm_period_elapsed(ach->ss); ++ } else { ++ return TW_DMA_OFF; ++ } ++ return 0; ++} ++ ++static irqreturn_t tw6869_irq(int irq, void *dev_id) ++{ ++ struct tw6869_dev *dev = dev_id; ++ unsigned int int_sts, fifo_sts, pb_sts, dma_en, id; ++ ++ int_sts = tw_read(dev, R32_INT_STATUS); ++ fifo_sts = tw_read(dev, R32_FIFO_STATUS); ++ pb_sts = tw_read(dev, R32_PB_STATUS); ++ dma_en = tw_read(dev, R32_DMA_CHANNEL_ENABLE); ++ dma_en &= tw_read(dev, R32_DMA_CMD); ++ ++ for (id = 0; id < (2 * TW_CH_MAX); id++) { ++ unsigned int verr = fifo_sts & TW_VERR(id); ++ ++ if ((dma_en & BIT(id)) && ((int_sts & BIT(id)) || verr)) { ++ unsigned int pb = !!(pb_sts & BIT(id)); ++ unsigned int cmd = (BIT(id) & TW_VID) ? ++ tw6869_virq(dev, id, pb, verr) : ++ tw6869_airq(dev, id, pb); ++ ++ if (cmd) { ++ spin_lock(&dev->rlock); ++ tw6869_id_dma_cmd(dev, id, cmd); ++ spin_unlock(&dev->rlock); ++ } else { ++ dev->id_err[id] = 0; ++ } ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++/**********************************************************************/ ++ ++static inline struct tw6869_buf *to_tw6869_buf(struct vb2_buffer *vb2) ++{ ++ return container_of(vb2, struct tw6869_buf, vb); ++} ++ ++static int to_tw6869_pixformat(unsigned int pixelformat) ++{ ++ int ret; ++ ++ switch (pixelformat) { ++ case V4L2_PIX_FMT_YUYV: ++ ret = TW_FMT_YUYV; ++ break; ++ case V4L2_PIX_FMT_UYVY: ++ ret = TW_FMT_UYVY; ++ break; ++ case V4L2_PIX_FMT_RGB565: ++ ret = TW_FMT_RGB565; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static unsigned int tw6869_fields_map(v4l2_std_id std, unsigned int rate) ++{ ++ unsigned int map[15] = { ++ 0x00000000, 0x00000001, 0x00004001, 0x00104001, 0x00404041, ++ 0x01041041, 0x01104411, 0x01111111, 0x04444445, 0x04511445, ++ 0x05145145, 0x05151515, 0x05515455, 0x05551555, 0x05555555 ++ }; ++ unsigned int std_625_50[26] = { ++ 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, ++ 8, 8, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 0 ++ }; ++ unsigned int std_525_60[31] = { ++ 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, ++ 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 0, 0 ++ }; ++ unsigned int i = (std & V4L2_STD_625_50) ? ++ std_625_50[(rate > 25) ? 25 : rate] : ++ std_525_60[(rate > 30) ? 30 : rate]; ++ ++ return map[i]; ++} ++ ++static void tw6869_fill_pix_format(struct tw6869_vch *vch, ++ struct v4l2_pix_format *pix) ++{ ++ pix->width = 720; ++ pix->height = (vch->std & V4L2_STD_625_50) ? 576 : 480; ++ pix->field = V4L2_FIELD_INTERLACED_BT; ++ pix->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ pix->bytesperline = pix->width * 2; ++ pix->sizeimage = pix->bytesperline * pix->height; ++ pix->priv = 0; ++} ++ ++static void tw6869_vch_hw_cfg(struct tw6869_vch *vch) ++{ ++ struct tw6869_dev *dev = vch->dev; ++ struct v4l2_pix_format *pix = &vch->format; ++ unsigned int cfg; ++ ++ if (vch->std & V4L2_STD_625_50) ++ tw_set(dev, R32_VIDEO_CONTROL1, BIT_CH(vch->id) << 13); ++ else ++ tw_clear(dev, R32_VIDEO_CONTROL1, BIT_CH(vch->id) << 13); ++ ++ cfg = tw6869_fields_map(vch->std, vch->fps) << 1; ++ cfg |= cfg << 1; ++ if (cfg > 0) ++ cfg |= BIT(31); ++ tw_write(dev, R32_VIDEO_FIELD_CTRL(vch->id), cfg); ++ ++ /* Analog mux input0, no drop, enable master */ ++ cfg = ((vch->input & 0x0) << 30) | ++ BIT(27) | (ID2SC(vch->id) << 25) | ++ ((to_tw6869_pixformat(pix->pixelformat) & 0x7) << 20); ++ tw_write(dev, R32_DMA_CHANNEL_CONFIG(vch->id), cfg); ++ ++ cfg = (((pix->height >> 1) & 0x3FF) << 22) | ++ ((pix->bytesperline & 0x7FF) << 11) | ++ (pix->bytesperline & 0x7FF); ++ tw_write(dev, R32_DMA_WHP(vch->id), cfg); ++ ++ tw_write(dev, R32_DMA_P_ADDR(vch->id), vch->p_buf->dma); ++ tw_write(dev, R32_DMA_B_ADDR(vch->id), vch->b_buf->dma); ++} ++ ++/* ++ * Videobuf2 Operations ++ */ ++static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, ++ unsigned int *nbuffers, unsigned int *nplanes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct tw6869_vch *vch = vb2_get_drv_priv(vq); ++ struct tw6869_dev *dev = vch->dev; ++ ++ if (vq->num_buffers + *nbuffers < TW_FRAME_MAX) ++ *nbuffers = TW_FRAME_MAX - vq->num_buffers; ++ ++ if (fmt && fmt->fmt.pix.sizeimage < vch->format.sizeimage) ++ return -EINVAL; ++ ++ *nplanes = 1; ++ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vch->format.sizeimage; ++ alloc_ctxs[0] = dev->alloc_ctx; ++ return 0; ++} ++ ++static int buffer_init(struct vb2_buffer *vb) ++{ ++ struct tw6869_buf *buf = to_tw6869_buf(vb); ++ ++ buf->dma = vb2_dma_contig_plane_dma_addr(vb, 0); ++ INIT_LIST_HEAD(&buf->list); ++ { /* pass the buffer physical address */ ++ unsigned int *cpu = vb2_plane_vaddr(vb, 0); ++ *cpu = buf->dma; ++ } ++ return 0; ++} ++ ++static int buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct tw6869_vch *vch = vb2_get_drv_priv(vb->vb2_queue); ++ unsigned long size = vch->format.sizeimage; ++ ++ if (vb2_plane_size(vb, 0) < size) { ++ v4l2_err(&vch->dev->v4l2_dev, "buffer too small (%lu < %lu)\n", ++ vb2_plane_size(vb, 0), size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(vb, 0, size); ++ return 0; ++} ++ ++static void buffer_queue(struct vb2_buffer *vb) ++{ ++ struct tw6869_vch *vch = vb2_get_drv_priv(vb->vb2_queue); ++ struct tw6869_buf *buf = to_tw6869_buf(vb); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&vch->lock, flags); ++ list_add_tail(&buf->list, &vch->buf_list); ++ spin_unlock_irqrestore(&vch->lock, flags); ++} ++ ++static int start_streaming(struct vb2_queue *vq, unsigned int count) ++{ ++ struct tw6869_vch *vch = vb2_get_drv_priv(vq); ++ struct tw6869_dev *dev = vch->dev; ++ unsigned long flags; ++ ++ if (count < 2) ++ return -ENOBUFS; ++ ++ spin_lock_irqsave(&vch->lock, flags); ++ vch->p_buf = list_first_entry(&vch->buf_list, struct tw6869_buf, list); ++ list_del(&vch->p_buf->list); ++ ++ vch->b_buf = list_first_entry(&vch->buf_list, struct tw6869_buf, list); ++ list_del(&vch->b_buf->list); ++ ++ vch->sequence = 0; ++ vch->dcount = 0; ++ vch->pb = 0; ++ spin_unlock_irqrestore(&vch->lock, flags); ++ ++ spin_lock_irqsave(&dev->rlock, flags); ++ tw6869_vch_hw_cfg(vch); ++ tw6869_id_dma_cmd(dev, vch->id, TW_DMA_ON); ++ spin_unlock_irqrestore(&dev->rlock, flags); ++ ++ return 0; ++} ++ ++static int stop_streaming(struct vb2_queue *vq) ++{ ++ struct tw6869_vch *vch = vb2_get_drv_priv(vq); ++ struct tw6869_dev *dev = vch->dev; ++ struct tw6869_buf *buf, *node; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->rlock, flags); ++ tw6869_id_dma_cmd(dev, vch->id, TW_DMA_OFF); ++ spin_unlock_irqrestore(&dev->rlock, flags); ++ ++ spin_lock_irqsave(&vch->lock, flags); ++ if (vch->p_buf) { ++ buf = vch->p_buf; ++ vch->p_buf = NULL; ++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); ++ } ++ ++ if (vch->b_buf) { ++ buf = vch->b_buf; ++ vch->b_buf = NULL; ++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); ++ } ++ ++ list_for_each_entry_safe(buf, node, &vch->buf_list, list) { ++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); ++ list_del(&buf->list); ++ } ++ spin_unlock_irqrestore(&vch->lock, flags); ++ ++ return 0; ++} ++ ++static struct vb2_ops tw6869_qops = { ++ .queue_setup = queue_setup, ++ .buf_init = buffer_init, ++ .buf_prepare = buffer_prepare, ++ .buf_queue = buffer_queue, ++ .start_streaming = start_streaming, ++ .stop_streaming = stop_streaming, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++}; ++ ++static int tw6869_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ struct tw6869_dev *dev = vch->dev; ++ ++ strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); ++ snprintf(cap->card, sizeof(cap->card), "tw6869 vch%u", ID2CH(vch->id)); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", ++ pci_name(dev->pdev)); ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | ++ V4L2_CAP_STREAMING; ++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; ++ return 0; ++} ++ ++static int tw6869_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ int ret; ++ ++ ret = to_tw6869_pixformat(pix->pixelformat); ++ if (ret < 0) ++ return ret; ++ ++ tw6869_fill_pix_format(vch, pix); ++ return 0; ++} ++ ++static int tw6869_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ int ret; ++ ++ ret = tw6869_try_fmt_vid_cap(file, priv, f); ++ if (ret) ++ return ret; ++ ++ if (vb2_is_busy(&vch->queue)) ++ return -EBUSY; ++ ++ vch->format = f->fmt.pix; ++ return 0; ++} ++ ++static int tw6869_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ ++ f->fmt.pix = vch->format; ++ return 0; ++} ++ ++static int tw6869_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ if (f->index > 2) ++ return -EINVAL; ++ ++ switch (f->index) { ++ case 1: ++ strcpy(f->description, "4:2:2, packed, YUYV"); ++ f->pixelformat = V4L2_PIX_FMT_YUYV; ++ break; ++ case 2: ++ strcpy(f->description, "16 bpp RGB, le"); ++ f->pixelformat = V4L2_PIX_FMT_RGB565; ++ break; ++ default: ++ strcpy(f->description, "4:2:2, packed, UYVY"); ++ f->pixelformat = V4L2_PIX_FMT_UYVY; ++ } ++ f->flags = 0; ++ return 0; ++} ++ ++static int tw6869_enum_framesizes(struct file *file, void *priv, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ ++ if (fsize->index != 0) ++ return -EINVAL; ++ ++ fsize->discrete.width = vch->format.width; ++ fsize->discrete.height = vch->format.height; ++ ++ return 0; ++} ++ ++static int tw6869_querystd(struct file *file, void *priv, v4l2_std_id *std) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ struct tw6869_dev *dev = vch->dev; ++ unsigned int std_now; ++ char *std_str; ++ ++ std_now = (tw_read(dev, R8_STANDARD_SEL(vch->id)) & 0x70) >> 4; ++ ++ switch (std_now) { ++ case TW_STD_PAL_M: ++ std_str = "PAL (M)"; ++ *std = V4L2_STD_525_60; ++ break; ++ case TW_STD_PAL_60: ++ std_str = "PAL 60"; ++ *std = V4L2_STD_525_60; ++ break; ++ case TW_STD_NTSC_M: ++ std_str = "NTSC (M)"; ++ *std = V4L2_STD_525_60; ++ break; ++ case TW_STD_NTSC_443: ++ std_str = "NTSC 4.43"; ++ *std = V4L2_STD_525_60; ++ break; ++ case TW_STD_PAL: ++ std_str = "PAL (B,D,G,H,I)"; ++ *std = V4L2_STD_625_50; ++ break; ++ case TW_STD_PAL_CN: ++ std_str = "PAL (CN)"; ++ *std = V4L2_STD_625_50; ++ break; ++ case TW_STD_SECAM: ++ std_str = "SECAM"; ++ *std = V4L2_STD_625_50; ++ break; ++ default: ++ std_str = "Not valid"; ++ *std = 0; ++ } ++ v4l2_info(&dev->v4l2_dev, "vch%u std %s\n", ID2CH(vch->id), std_str); ++ return 0; ++} ++ ++static int tw6869_s_std(struct file *file, void *priv, v4l2_std_id std) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ v4l2_std_id new_std = (std & V4L2_STD_625_50) ? ++ V4L2_STD_625_50 : V4L2_STD_525_60; ++ ++ if (new_std == vch->std) ++ return 0; ++ ++ if (vb2_is_busy(&vch->queue)) ++ return -EBUSY; ++ ++ vch->std = new_std; ++ vch->fps = (new_std & V4L2_STD_625_50) ? 25 : 30; ++ tw6869_fill_pix_format(vch, &vch->format); ++ return 0; ++} ++ ++static int tw6869_g_std(struct file *file, void *priv, v4l2_std_id *std) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ v4l2_std_id new_std = 0; ++ ++ tw6869_querystd(file, priv, &new_std); ++ if (new_std) ++ tw6869_s_std(file, priv, new_std); ++ ++ vch->fps = (vch->std & V4L2_STD_625_50) ? 25 : 30; ++ *std = vch->std; ++ return 0; ++} ++ ++/* SK-TW6869: only input0 is available */ ++static int tw6869_enum_input(struct file *file, void *priv, ++ struct v4l2_input *i) ++{ ++ if (i->index >= TW_VIN_MAX) ++ return -EINVAL; ++ ++ i->type = V4L2_INPUT_TYPE_CAMERA; ++ i->std = V4L2_STD_ALL; ++ sprintf(i->name, "Camera %d", i->index); ++ return 0; ++} ++ ++static int tw6869_s_input(struct file *file, void *priv, unsigned int i) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ ++ vch->input = i; ++ return 0; ++} ++ ++static int tw6869_g_input(struct file *file, void *priv, unsigned int *i) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ ++ *i = vch->input; ++ return 0; ++} ++ ++static int tw6869_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *sp) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ struct v4l2_captureparm *cp = &sp->parm.capture; ++ ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = 1; ++ cp->timeperframe.denominator = vch->fps; ++ return 0; ++} ++ ++static int tw6869_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *sp) ++{ ++ struct tw6869_vch *vch = video_drvdata(file); ++ unsigned int denominator = sp->parm.capture.timeperframe.denominator; ++ unsigned int numerator = sp->parm.capture.timeperframe.numerator; ++ unsigned int fps; ++ ++ fps = (!numerator || !denominator) ? 0 : denominator / numerator; ++ if (vch->std & V4L2_STD_625_50) ++ fps = (!fps || fps > 25) ? 25 : fps; ++ else ++ fps = (!fps || fps > 30) ? 30 : fps; ++ ++ vch->fps = fps; ++ v4l2_info(&vch->dev->v4l2_dev, ++ "vch%u fps %u\n", ID2CH(vch->id), vch->fps); ++ ++ return tw6869_g_parm(file, priv, sp); ++} ++ ++/* The control handler */ ++static int tw6869_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct tw6869_vch *vch = ++ container_of(ctrl->handler, struct tw6869_vch, hdl); ++ struct tw6869_dev *dev = vch->dev; ++ unsigned int id = vch->id; ++ int ret = 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ tw_write(dev, R8_BRIGHT_CTRL(id), ctrl->val); ++ break; ++ case V4L2_CID_CONTRAST: ++ tw_write(dev, R8_CONTRAST_CTRL(id), ctrl->val); ++ break; ++ case V4L2_CID_SATURATION: ++ tw_write(dev, R8_SAT_U_CTRL(id), ctrl->val); ++ tw_write(dev, R8_SAT_V_CTRL(id), ctrl->val); ++ break; ++ case V4L2_CID_HUE: ++ tw_write(dev, R8_HUE_CTRL(id), ctrl->val); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++/* ++ * File operations for the device ++ */ ++static const struct v4l2_ctrl_ops tw6869_ctrl_ops = { ++ .s_ctrl = tw6869_s_ctrl, ++}; ++ ++static const struct v4l2_ioctl_ops tw6869_ioctl_ops = { ++ .vidioc_querycap = tw6869_querycap, ++ .vidioc_try_fmt_vid_cap = tw6869_try_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = tw6869_s_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = tw6869_g_fmt_vid_cap, ++ .vidioc_enum_fmt_vid_cap = tw6869_enum_fmt_vid_cap, ++ .vidioc_enum_framesizes = tw6869_enum_framesizes, ++ ++ .vidioc_querystd = tw6869_querystd, ++ .vidioc_s_std = tw6869_s_std, ++ .vidioc_g_std = tw6869_g_std, ++ ++ .vidioc_enum_input = tw6869_enum_input, ++ .vidioc_s_input = tw6869_s_input, ++ .vidioc_g_input = tw6869_g_input, ++ ++ .vidioc_g_parm = tw6869_g_parm, ++ .vidioc_s_parm = tw6869_s_parm, ++ ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ ++ .vidioc_log_status = v4l2_ctrl_log_status, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++}; ++ ++static const struct v4l2_file_operations tw6869_fops = { ++ .owner = THIS_MODULE, ++ .open = v4l2_fh_open, ++ .release = vb2_fop_release, ++ .unlocked_ioctl = video_ioctl2, ++ .read = vb2_fop_read, ++ .mmap = vb2_fop_mmap, ++ .poll = vb2_fop_poll, ++}; ++ ++static int tw6869_vch_register(struct tw6869_vch *vch) ++{ ++ struct tw6869_dev *dev = vch->dev; ++ struct v4l2_ctrl_handler *hdl = &vch->hdl; ++ struct vb2_queue *q = &vch->queue; ++ struct video_device *vdev = &vch->vdev; ++ int ret = 0; ++ ++ /* Add the controls */ ++ v4l2_ctrl_handler_init(hdl, 4); ++ v4l2_ctrl_new_std(hdl, &tw6869_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); ++ v4l2_ctrl_new_std(hdl, &tw6869_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 255, 1, 100); ++ v4l2_ctrl_new_std(hdl, &tw6869_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(hdl, &tw6869_ctrl_ops, ++ V4L2_CID_HUE, -128, 127, 1, 0); ++ if (hdl->error) { ++ ret = hdl->error; ++ return ret; ++ } ++ ++ /* Fill in the initial format-related settings */ ++ vch->std = V4L2_STD_525_60; ++ vch->fps = 30; ++ vch->format.pixelformat = V4L2_PIX_FMT_UYVY; ++ tw6869_fill_pix_format(vch, &vch->format); ++ ++ mutex_init(&vch->mlock); ++ ++ /* Initialize the vb2 queue */ ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; ++ q->drv_priv = vch; ++ q->buf_struct_size = sizeof(struct tw6869_buf); ++ q->ops = &tw6869_qops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->lock = &vch->mlock; ++ q->gfp_flags = __GFP_DMA32; ++ ret = vb2_queue_init(q); ++ if (ret) ++ goto free_hdl; ++ ++ spin_lock_init(&vch->lock); ++ INIT_LIST_HEAD(&vch->buf_list); ++ ++ /* Initialize the video_device structure */ ++ strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); ++ vdev->release = video_device_release_empty; ++ vdev->fops = &tw6869_fops, ++ vdev->ioctl_ops = &tw6869_ioctl_ops, ++ vdev->lock = &vch->mlock; ++ vdev->queue = q; ++ vdev->v4l2_dev = &dev->v4l2_dev; ++ vdev->ctrl_handler = hdl; ++ vdev->tvnorms = V4L2_STD_ALL; ++ video_set_drvdata(vdev, vch); ++ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); ++ if (!ret) ++ return 0; ++ ++free_hdl: ++ v4l2_ctrl_handler_free(hdl); ++ return ret; ++} ++ ++static void tw6869_video_unregister(struct tw6869_dev *dev) ++{ ++ unsigned int i; ++ ++ /* Reset and disable all DMA channels */ ++ tw_write(dev, R32_DMA_CMD, 0); ++ tw_write(dev, R32_DMA_CHANNEL_ENABLE, 0); ++ ++ if (!dev->alloc_ctx) ++ return; ++ ++ if (dev->ch_max > TW_CH_MAX) ++ dev->ch_max = TW_CH_MAX; ++ ++ for (i = 0; i < dev->ch_max; i++) { ++ struct tw6869_vch *vch = &dev->vch[ID2CH(i)]; ++ video_unregister_device(&vch->vdev); ++ v4l2_ctrl_handler_free(&vch->hdl); ++ } ++ ++ v4l2_device_unregister(&dev->v4l2_dev); ++ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); ++ dev->alloc_ctx = NULL; ++} ++ ++static int tw6869_video_register(struct tw6869_dev *dev) ++{ ++ struct pci_dev *pdev = dev->pdev; ++ unsigned int i; ++ int ret; ++ ++ /* Initialize the top-level structure */ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if (ret) ++ return ret; ++ ++ dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(dev->alloc_ctx)) { ++ ret = PTR_ERR(dev->alloc_ctx); ++ v4l2_err(&dev->v4l2_dev, "can't allocate buffer context\n"); ++ v4l2_device_unregister(&dev->v4l2_dev); ++ dev->alloc_ctx = NULL; ++ return ret; ++ } ++ ++ for (i = 0; i < TW_CH_MAX; i++) { ++ struct tw6869_vch *vch = &dev->vch[ID2CH(i)]; ++ vch->dev = dev; ++ vch->id = i; ++ ret = tw6869_vch_register(vch); ++ if (ret) { ++ dev->ch_max = i; ++ tw6869_video_unregister(dev); ++ return ret; ++ } ++ dev_info(&pdev->dev, "vch%i registered as %s\n", ++ vch->id, ++ video_device_node_name(&vch->vdev)); ++ } ++ return 0; ++} ++ ++/**********************************************************************/ ++ ++static int tw6869_pcm_hw_params(struct snd_pcm_substream *ss, ++ struct snd_pcm_hw_params *hw_params) ++{ ++ return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params)); ++} ++ ++static int tw6869_pcm_hw_free(struct snd_pcm_substream *ss) ++{ ++ return snd_pcm_lib_free_pages(ss); ++} ++ ++static const struct snd_pcm_hardware tw6869_capture_hw = { ++ .info = (SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER | ++ SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ .rates = SNDRV_PCM_RATE_48000, ++ .rate_min = 48000, ++ .rate_max = 48000, ++ .channels_min = 1, ++ .channels_max = 1, ++ .buffer_bytes_max = TW_PAGE_SIZE * TW_APAGE_MAX, ++ .period_bytes_min = TW_PAGE_SIZE, ++ .period_bytes_max = TW_PAGE_SIZE, ++ .periods_min = 2, ++ .periods_max = TW_APAGE_MAX, ++}; ++ ++static int tw6869_pcm_open(struct snd_pcm_substream *ss) ++{ ++ struct tw6869_dev *dev = snd_pcm_substream_chip(ss); ++ struct tw6869_ach *ach = &dev->ach[ID2CH(ss->number)]; ++ struct snd_pcm_runtime *rt = ss->runtime; ++ int ret; ++ ++ rt->hw = tw6869_capture_hw; ++ ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); ++ if (ret < 0) ++ return ret; ++ ++ ach->ss = ss; ++ return 0; ++} ++ ++static int tw6869_pcm_close(struct snd_pcm_substream *ss) ++{ ++ struct tw6869_dev *dev = snd_pcm_substream_chip(ss); ++ struct tw6869_ach *ach = &dev->ach[ID2CH(ss->number)]; ++ ++ ach->ss = NULL; ++ return 0; ++} ++ ++static int tw6869_pcm_prepare(struct snd_pcm_substream *ss) ++{ ++ struct tw6869_dev *dev = snd_pcm_substream_chip(ss); ++ struct tw6869_ach *ach = &dev->ach[ID2CH(ss->number)]; ++ struct snd_pcm_runtime *rt = ss->runtime; ++ unsigned int period = snd_pcm_lib_period_bytes(ss); ++ unsigned long flags; ++ unsigned int i; ++ ++ spin_lock_irqsave(&ach->lock, flags); ++ ach->p_buf = NULL; ++ ach->b_buf = NULL; ++ ++ if ((period != TW_PAGE_SIZE) || ++ (rt->periods < 2) || ++ (rt->periods > TW_APAGE_MAX)) { ++ spin_unlock_irqrestore(&ach->lock, flags); ++ return -EINVAL; ++ } ++ ++ INIT_LIST_HEAD(&ach->buf_list); ++ for (i = 0; i < rt->periods; i++) { ++ ach->buf[i].dma = rt->dma_addr + period * i; ++ INIT_LIST_HEAD(&ach->buf[i].list); ++ list_add_tail(&ach->buf[i].list, &ach->buf_list); ++ } ++ ++ ach->p_buf = list_first_entry(&ach->buf_list, struct tw6869_buf, list); ++ list_move_tail(&ach->p_buf->list, &ach->buf_list); ++ ++ ach->b_buf = list_first_entry(&ach->buf_list, struct tw6869_buf, list); ++ list_move_tail(&ach->b_buf->list, &ach->buf_list); ++ ++ ach->ptr = 0; ++ ach->pb = 0; ++ spin_unlock_irqrestore(&ach->lock, flags); ++ ++ return 0; ++} ++ ++static void tw6869_ach_hw_cfg(struct tw6869_ach *ach) ++{ ++ struct tw6869_dev *dev = ach->dev; ++ ++ tw_write(dev, R32_DMA_P_ADDR(ach->id), ach->p_buf->dma); ++ tw_write(dev, R32_DMA_B_ADDR(ach->id), ach->b_buf->dma); ++} ++ ++static int tw6869_pcm_trigger(struct snd_pcm_substream *ss, int cmd) ++{ ++ struct tw6869_dev *dev = snd_pcm_substream_chip(ss); ++ struct tw6869_ach *ach = &dev->ach[ID2CH(ss->number)]; ++ unsigned long flags; ++ int ret = 0; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ if (ach->p_buf && ach->b_buf) { ++ spin_lock_irqsave(&dev->rlock, flags); ++ tw6869_ach_hw_cfg(ach); ++ tw6869_id_dma_cmd(dev, ach->id, TW_DMA_ON); ++ spin_unlock_irqrestore(&dev->rlock, flags); ++ } else { ++ ret = -EIO; ++ } ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ spin_lock_irqsave(&dev->rlock, flags); ++ tw6869_id_dma_cmd(dev, ach->id, TW_DMA_OFF); ++ spin_unlock_irqrestore(&dev->rlock, flags); ++ ++ spin_lock_irqsave(&ach->lock, flags); ++ ach->p_buf = NULL; ++ ach->b_buf = NULL; ++ spin_unlock_irqrestore(&ach->lock, flags); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static snd_pcm_uframes_t tw6869_pcm_pointer(struct snd_pcm_substream *ss) ++{ ++ struct tw6869_dev *dev = snd_pcm_substream_chip(ss); ++ struct tw6869_ach *ach = &dev->ach[ID2CH(ss->number)]; ++ ++ return bytes_to_frames(ss->runtime, ach->ptr); ++} ++ ++static struct snd_pcm_ops tw6869_pcm_ops = { ++ .open = tw6869_pcm_open, ++ .close = tw6869_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = tw6869_pcm_hw_params, ++ .hw_free = tw6869_pcm_hw_free, ++ .prepare = tw6869_pcm_prepare, ++ .trigger = tw6869_pcm_trigger, ++ .pointer = tw6869_pcm_pointer, ++}; ++ ++static int tw6869_snd_pcm_init(struct tw6869_dev *dev) ++{ ++ struct snd_card *card = dev->snd_card; ++ struct snd_pcm *pcm; ++ struct snd_pcm_substream *ss; ++ int ret; ++ ++ ret = snd_pcm_new(card, card->driver, 0, 0, TW_CH_MAX, &pcm); ++ if (ret < 0) ++ return ret; ++ ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tw6869_pcm_ops); ++ snd_pcm_chip(pcm) = dev; ++ pcm->info_flags = 0; ++ strcpy(pcm->name, card->shortname); ++ ++ ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; ++ while (ss && (ss->next != ss)) { ++ struct tw6869_ach *ach = &dev->ach[ID2CH(ss->number)]; ++ ach->dev = dev; ++ ach->id = ID2CH(ss->number) + TW_CH_MAX; ++ spin_lock_init(&ach->lock); ++ sprintf(ss->name, "vch%u audio", ID2CH(ss->number)); ++ ss = ss->next; ++ } ++ ++ return snd_pcm_lib_preallocate_pages_for_all(pcm, ++ SNDRV_DMA_TYPE_DEV, ++ snd_dma_pci_data(dev->pdev), ++ TW_APAGE_MAX * TW_PAGE_SIZE, ++ TW_APAGE_MAX * TW_PAGE_SIZE); ++} ++ ++static void tw6869_audio_unregister(struct tw6869_dev *dev) ++{ ++ /* Reset and disable audio DMA */ ++ tw_clear(dev, R32_DMA_CMD, TW_AID); ++ tw_clear(dev, R32_DMA_CHANNEL_ENABLE, TW_AID); ++ ++ if (!dev->snd_card) ++ return; ++ ++ snd_card_free(dev->snd_card); ++ dev->snd_card = NULL; ++} ++ ++/* TODO: mixer controls */ ++static int tw6869_audio_register(struct tw6869_dev *dev) ++{ ++ struct pci_dev *pdev = dev->pdev; ++ static struct snd_device_ops ops = { NULL }; ++ struct snd_card *card; ++ int ret; ++ ++ ret = snd_card_create(SNDRV_DEFAULT_IDX1, KBUILD_MODNAME, ++ THIS_MODULE, 0, &card); ++ if (ret < 0) ++ return ret; ++ ++ dev->snd_card = card; ++ ++ strcpy(card->driver, KBUILD_MODNAME); ++ strcpy(card->shortname, KBUILD_MODNAME); ++ sprintf(card->longname, "%s on %s IRQ %d", card->shortname, ++ pci_name(pdev), pdev->irq); ++ ++ ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops); ++ if (ret < 0) ++ goto snd_error; ++ ++ snd_card_set_dev(card, &pdev->dev); ++ ++ ret = tw6869_snd_pcm_init(dev); ++ if (ret < 0) ++ goto snd_error; ++ ++ ret = snd_card_register(card); ++ if (!ret) ++ return 0; ++ ++snd_error: ++ snd_card_free(card); ++ dev->snd_card = NULL; ++ return ret; ++} ++ ++/**********************************************************************/ ++ ++static void tw6869_reset(struct tw6869_dev *dev) ++{ ++ /* Software Reset */ ++ tw_write(dev, R32_SYS_SOFT_RST, 0x01); ++ tw_write(dev, R32_SYS_SOFT_RST, 0x0F); ++ ++ /* Reset Internal audio and video decoders */ ++ tw_write(dev, R8_AVSRST(0), 0x1F); ++ tw_write(dev, R8_AVSRST(4), 0x1F); ++ ++ /* Reset all DMA channels */ ++ tw_write(dev, R32_DMA_CMD, 0); ++ ++ /* Disable all DMA channels */ ++ tw_write(dev, R32_DMA_CHANNEL_ENABLE, 0); ++ ++ /* Enable DMA FIFO overflow and pointer check */ ++ tw_write(dev, R32_DMA_CONFIG, 0x00FFFF04); ++ ++ /* Minimum time span for DMA interrupting host (default: 0x00098968) */ ++ tw_write(dev, R32_DMA_TIMER_INTERVAL, 0x00098968); ++ ++ /* DMA timeout (default: 0x140C8584) */ ++ tw_write(dev, R32_DMA_CHANNEL_TIMEOUT, 0x140C8584); ++ ++ /* Frame mode DMA */ ++ tw_write(dev, R32_PHASE_REF, 0xAAAA144D); ++ ++ /* Show blue background if no signal */ ++ tw_write(dev, R8_MISC_CONTROL1(0), 0xE7); ++ tw_write(dev, R8_MISC_CONTROL1(4), 0xE7); ++ ++ /* Audio DMA 4096 bytes, sampling frequency reference 48 kHz */ ++ tw_write(dev, R32_AUDIO_CONTROL1, 0x80000001 | (0x0A2C << 5)); ++ tw_write(dev, R32_AUDIO_CONTROL2, 0x0A2C2AAA); ++} ++ ++static int tw6869_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ struct tw6869_dev *dev; ++ int ret; ++ ++ /* Allocate a new instance */ ++ dev = devm_kzalloc(&pdev->dev, sizeof(struct tw6869_dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ ret = pci_enable_device(pdev); ++ if (ret) ++ return ret; ++ ++ pci_set_master(pdev); ++ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); ++ if (ret) { ++ dev_err(&pdev->dev, "no suitable DMA available\n"); ++ goto disable_pci; ++ } ++ ++ ret = pci_request_regions(pdev, KBUILD_MODNAME); ++ if (ret) ++ goto disable_pci; ++ ++ dev->mmio = pci_iomap(pdev, 0, 0); ++ if (!dev->mmio) { ++ ret = -EIO; ++ goto release_regs; ++ } ++ ++ tw6869_reset(dev); ++ ++ ret = devm_request_irq(&pdev->dev, pdev->irq, ++ tw6869_irq, IRQF_SHARED, KBUILD_MODNAME, dev); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq failed\n"); ++ goto unmap_regs; ++ } ++ ++ dev->pdev = pdev; ++ dev->ch_max = TW_CH_MAX; ++ spin_lock_init(&dev->rlock); ++ ++ ret = tw6869_video_register(dev); ++ if (ret) ++ goto unmap_regs; ++ ++ ret = tw6869_audio_register(dev); ++ if (ret) ++ goto video_unreg; ++ ++ dev_info(&pdev->dev, "driver loaded\n"); ++ return 0; ++ ++video_unreg: ++ tw6869_video_unregister(dev); ++unmap_regs: ++ pci_iounmap(pdev, dev->mmio); ++release_regs: ++ pci_release_regions(pdev); ++disable_pci: ++ pci_disable_device(pdev); ++ return ret; ++} ++ ++static void tw6869_remove(struct pci_dev *pdev) ++{ ++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); ++ struct tw6869_dev *dev = ++ container_of(v4l2_dev, struct tw6869_dev, v4l2_dev); ++ ++ tw6869_audio_unregister(dev); ++ tw6869_video_unregister(dev); ++ pci_iounmap(pdev, dev->mmio); ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++} ++ ++/* TODO: PM */ ++static struct pci_driver tw6869_driver = { ++ .name = KBUILD_MODNAME, ++ .probe = tw6869_probe, ++ .remove = tw6869_remove, ++ .id_table = tw6869_pci_tbl, ++}; ++ ++module_pci_driver(tw6869_driver); +diff -Nur linux-3.14.72.orig/drivers/media/pci/tw6869/tw6869.h linux-3.14.72/drivers/media/pci/tw6869/tw6869.h +--- linux-3.14.72.orig/drivers/media/pci/tw6869/tw6869.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/pci/tw6869/tw6869.h 2016-06-19 22:11:55.169148931 +0200 +@@ -0,0 +1,119 @@ ++/* ++ * Copyright 2015 www.starterkit.ru ++ * ++ * Based on: ++ * tw686x common header file ++ * Copyright 2009-10 liran [Techwell China] ++ * ++ * This program is free software; you may redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * 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 THE AUTHORS OR COPYRIGHT HOLDERS ++ * 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. ++ */ ++ ++#ifndef __TW6869_H ++#define __TW6869_H ++ ++#define PCI_VENDOR_ID_TECHWELL 0x1797 ++#define PCI_DEVICE_ID_6869 0x6869 ++ ++#define TW_CH_MAX 8 ++#define TW_VIN_MAX 4 ++#define TW_FRAME_MAX 4 ++#define TW_APAGE_MAX 16 ++#define TW_DMA_ERR_MAX 5 ++#define TW_PAGE_SIZE 4096 ++ ++#define TW_VID 0x00FF ++#define TW_AID 0xFF00 ++#define TW_CH_0to3 0x0F ++#define TW_CH_4to7 0xF0 ++ ++#define ID2ID(id) ((id) & 0xF) ++#define ID2CH(id) ((id) & 0x7) ++#define ID2SC(id) ((id) & 0x3) ++ ++#define BIT_ID(id) BIT((id) & 0xF) ++#define BIT_CH(id) BIT((id) & 0x7) ++#define BIT_SC(id) BIT((id) & 0x3) ++ ++#define IS_VID(id) (BIT_ID(id) & TW_VID) ++#define IS_CH03(id) (BIT_CH(id) & TW_CH_0to3) ++ ++#define TW_FIFO_ERR(id) ((BIT(24) | BIT(16)) << ID2CH(id)) ++#define TW_PARS_ERR(id) ((BIT(8) | BIT(0)) << ID2CH(id)) ++#define TW_VERR(id) (IS_VID(id) ? TW_FIFO_ERR(id) : 0) ++ ++#define TW_DMA_ON 1 ++#define TW_DMA_OFF 2 ++#define TW_DMA_RST 3 ++ ++#define TW_STD_NTSC_M 0 ++#define TW_STD_PAL 1 ++#define TW_STD_SECAM 2 ++#define TW_STD_NTSC_443 3 ++#define TW_STD_PAL_M 4 ++#define TW_STD_PAL_CN 5 ++#define TW_STD_PAL_60 6 ++ ++#define TW_FMT_UYVY 0 ++#define TW_FMT_RGB565 5 ++#define TW_FMT_YUYV 6 ++ ++/** ++ * Register definitions ++ */ ++#define R32_INT_STATUS 0x000 /* 0x00 */ ++#define R32_PB_STATUS 0x004 /* 0x01 */ ++#define R32_DMA_CMD 0x008 /* 0x02 */ ++#define R32_FIFO_STATUS 0x00C /* 0x03 */ ++#define R32_VIDEO_CHANNEL_ID 0x010 /* 0x04 */ ++#define R32_VIDEO_PARSER_STATUS 0x014 /* 0x05 */ ++#define R32_SYS_SOFT_RST 0x018 /* 0x06 */ ++#define R32_DMA_CHANNEL_ENABLE 0x028 /* 0x0a */ ++#define R32_DMA_CONFIG 0x02C /* 0x0b */ ++#define R32_DMA_TIMER_INTERVAL 0x030 /* 0x0c */ ++#define R32_DMA_CHANNEL_TIMEOUT 0x034 /* 0x0d */ ++#define R32_DMA_CHANNEL_CONFIG(id) (0x040 + ID2CH(id) * 0x04) /* 0x10 */ ++#define R32_VIDEO_CONTROL1 0x0A8 /* 0x2A */ ++#define R32_VIDEO_CONTROL2 0x0AC /* 0x2B */ ++#define R32_AUDIO_CONTROL1 0x0B0 /* 0x2C */ ++#define R32_AUDIO_CONTROL2 0x0B4 /* 0x2D */ ++#define R32_PHASE_REF 0x0B8 /* 0x2E */ ++#define R32_VIDEO_FIELD_CTRL(id) (0x0E4 + ID2CH(id) * 0x04) /* 0x39 */ ++#define R32_DMA_P_ADDR(id) (IS_VID(id) ? (0x200 + ID2CH(id) * 0x20) : (0x060 + ID2CH(id) * 0x08)) ++#define R32_DMA_B_ADDR(id) (IS_VID(id) ? (0x208 + ID2CH(id) * 0x20) : (0x064 + ID2CH(id) * 0x08)) ++#define R32_DMA_WHP(id) (0x204 + ID2CH(id) * 0x20) /* 0x81 */ ++ ++/* 0x100, 0x200 */ ++#define R8_VIDEO_STATUS(id) ((IS_CH03(id) ? 0x400 : 0x800) + ID2SC(id) * 0x40) ++/* 0x101, 0x201 */ ++#define R8_BRIGHT_CTRL(id) ((IS_CH03(id) ? 0x404 : 0x804) + ID2SC(id) * 0x40) ++/* 0x102, 0x202 */ ++#define R8_CONTRAST_CTRL(id) ((IS_CH03(id) ? 0x408 : 0x808) + ID2SC(id) * 0x40) ++/* 0x104, 0x204 */ ++#define R8_SAT_U_CTRL(id) ((IS_CH03(id) ? 0x410 : 0x810) + ID2SC(id) * 0x40) ++/* 0x105, 0x205 */ ++#define R8_SAT_V_CTRL(id) ((IS_CH03(id) ? 0x414 : 0x814) + ID2SC(id) * 0x40) ++/* 0x106, 0x206 */ ++#define R8_HUE_CTRL(id) ((IS_CH03(id) ? 0x418 : 0x818) + ID2SC(id) * 0x40) ++/* 0x10E, 0x20E */ ++#define R8_STANDARD_SEL(id) ((IS_CH03(id) ? 0x438 : 0x838) + ID2SC(id) * 0x40) ++/* 0x180, 0x280 */ ++#define R8_AVSRST(id) (IS_CH03(id) ? 0x600 : 0xA00) ++/* 0x18F, 0x28F */ ++#define R8_VERTICAL_CONTROL1(id) (IS_CH03(id) ? 0x63C : 0xA3C) ++/* 0x196, 0x296 */ ++#define R8_MISC_CONTROL1(id) (IS_CH03(id) ? 0x658 : 0xA58) ++/* 0x1D0, 0x2D0 */ ++#define R8_AIGAIN_CTRL(id) ((IS_CH03(id) ? 0x740 : 0xB40) + ID2SC(id) * 0x04) ++ ++#endif /* __TW6869_H */ +diff -Nur linux-3.14.72.orig/drivers/media/platform/Kconfig linux-3.14.72/drivers/media/platform/Kconfig +--- linux-3.14.72.orig/drivers/media/platform/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/platform/Kconfig 2016-06-19 22:11:55.169148931 +0200 +@@ -115,6 +115,22 @@ + 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 ++ ---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/mxc/subdev/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.72.orig/drivers/media/platform/Makefile linux-3.14.72/drivers/media/platform/Makefile +--- linux-3.14.72.orig/drivers/media/platform/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/platform/Makefile 2016-06-19 22:11:55.169148931 +0200 +@@ -51,4 +51,8 @@ + + obj-$(CONFIG_ARCH_OMAP) += omap/ + ++obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/capture/ ++obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/subdev/ ++obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc/output/ ++ + ccflags-y += -I$(srctree)/drivers/media/i2c +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/capture/adv7180.c linux-3.14.72/drivers/media/platform/mxc/capture/adv7180.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/adv7180.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/adv7180.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,1380 @@ ++/* ++ * Copyright 2005-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 adv7180.c ++ * ++ * @brief Analog Device ADV7180 video decoder functions ++ * ++ * @ingroup Camera ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "v4l2-int-device.h" ++#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. */ ++ int frame_rate; /*!< Frame rate. */ ++} 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 */ ++ .frame_rate = 30, ++ }, ++ { /*! (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, ++ .frame_rate = 25, ++ }, ++ { /*! Unlocked standard */ ++ .v4l2_id = V4L2_STD_ALL, ++ .name = "Autodetect", ++ .raw_width = 720, ++ .raw_height = 625, ++ .active_width = 720, ++ .active_height = 576, ++ .frame_rate = 0, ++ }, ++}; ++ ++/*!* 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 status_1, standard, idx; ++ bool locked; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n"); ++ ++ status_1 = adv7180_read(ADV7180_STATUS_1); ++ locked = status_1 & 0x1; ++ standard = status_1 & 0x70; ++ ++ mutex_lock(&mutex); ++ *std = V4L2_STD_ALL; ++ idx = ADV7180_NOT_LOCKED; ++ if (locked) { ++ if (standard == 0x40) { ++ *std = V4L2_STD_PAL; ++ idx = ADV7180_PAL; ++ } else if (standard == 0) { ++ *std = V4L2_STD_NTSC; ++ idx = ADV7180_NTSC; ++ } ++ } ++ 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_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) ++{ ++ video_fmt_t fmt; ++ int i; ++ ++ if (fival->index != 0) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(video_fmts) - 1; i++) { ++ fmt = video_fmts[i]; ++ if (fival->width == fmt.active_width && ++ fival->height == fmt.active_height) { ++ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; ++ fival->discrete.numerator = 1; ++ fival->discrete.denominator = fmt.frame_rate; ++ 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, ++ "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_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 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.72.orig/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c linux-3.14.72/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,493 @@ ++ ++/* ++ * 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; ++ ++ 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; ++ } ++ err = cam_mipi_csi2_enable(cam, ¶ms.csi_mem.mipi); ++ if (err) ++ return err; ++ ++ 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_channel_request(cam->ipu, CSI_MEM, ¶ms, &cam->ipu_chan); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d\n", __func__, 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; ++ int err2 = 0; ++ cam_data *cam = (cam_data *) private; ++ ++ if (cam->overlay_active == false) ++ return 0; ++ ++ err = ipu_channel_disable(cam->ipu_chan, true); ++ ++ ipu_channel_free(&cam->ipu_chan); ++ ++ csi_buffer_num = 0; ++ ++ err2 = cam_mipi_csi2_disable(cam); ++ 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 ? err : err2; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int bg_overlay_enable_csi(void *private) ++{ ++ return cam_ipu_enable_csi((cam_data *)private); ++} ++ ++/*! ++ * 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 cam_ipu_disable_csi(cam); ++} ++ ++/*! ++ * 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.72.orig/drivers/media/platform/mxc/capture/ipu_csi_enc.c linux-3.14.72/drivers/media/platform/mxc/capture/ipu_csi_enc.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_csi_enc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_csi_enc.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,384 @@ ++/* ++ * 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 ++ struct v4l2_format cam_fmt; ++ ++ 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) ++ { ++ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); ++ if (cam_fmt.fmt.pix.pixelformat == IPU_PIX_FMT_GENERIC_16) ++ pixel_fmt = cam_fmt.fmt.pix.pixelformat; ++ else ++ 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 if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) ++ pixel_fmt = IPU_PIX_FMT_GENERIC; ++ else { ++ printk(KERN_ERR "format not supported\n"); ++ return -EINVAL; ++ } ++ err = cam_mipi_csi2_enable(cam, ¶ms.csi_mem.mipi); ++ if (err) ++ return err; ++ ++ err = ipu_channel_request(cam->ipu, CSI_MEM, ¶ms, &cam->ipu_chan); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d\n", __func__, 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, ++ cam->rotation, ++ 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"); ++ ++ if (cam->dummy_frame.vaddress && ++ cam->dummy_frame.buffer.length ++ < PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage)) { ++ dma_free_coherent(0, cam->dummy_frame.buffer.length, ++ cam->dummy_frame.vaddress, ++ cam->dummy_frame.paddress); ++ cam->dummy_frame.vaddress = 0; ++ } ++ ++ if (!cam->dummy_frame.vaddress) { ++ 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.length = ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); ++ } ++ cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; ++ 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) { ++ pr_err("%s: Error requesting IPU_IRQ_CSI0_OUT_EOF\n", __func__); ++ 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; ++ int err2 = 0; ++ ++ err = ipu_channel_disable(cam->ipu_chan, true); ++ ++ ipu_channel_free(&cam->ipu_chan); ++ ++ err2 = cam_mipi_csi2_disable(cam); ++ return err ? err : err2; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int csi_enc_enable_csi(void *private) ++{ ++ return cam_ipu_enable_csi((cam_data *)private); ++} ++ ++/*! ++ * 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 cam_ipu_disable_csi(cam); ++} ++ ++/*! ++ * 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.72.orig/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c linux-3.14.72/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,580 @@ ++/* ++ * 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; ++ ++ 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; ++ } ++ err = cam_mipi_csi2_enable(cam, ¶ms.csi_mem.mipi); ++ if (err) ++ return err; ++ ++ 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_channel_request(cam->ipu, CSI_MEM, ¶ms, &cam->ipu_chan); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d\n", __func__, 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; ++ int err2 = 0; ++ struct fb_info *fbi = NULL; ++ struct fb_var_screeninfo fbvar; ++ ++ if (cam->overlay_active == false) ++ return 0; ++ ++ err = ipu_channel_disable(cam->ipu_chan, true); ++ ++ ipu_channel_free(&cam->ipu_chan); ++ ++ 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); ++ err2 = cam_mipi_csi2_disable(cam); ++ ++ 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 ? err : err2; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int foreground_enable_csi(void *private) ++{ ++ return cam_ipu_enable_csi((cam_data *)private); ++} ++ ++/*! ++ * 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 cam_ipu_disable_csi(cam); ++} ++ ++/*! ++ * 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.72.orig/drivers/media/platform/mxc/capture/ipu_prp_enc.c linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_enc.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_prp_enc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_enc.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,538 @@ ++/* ++ * 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; ++ ++ 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; ++ } ++ err = cam_mipi_csi2_enable(cam, &enc.csi_prp_enc_mem.mipi); ++ if (err) ++ return err; ++ ++ err = ipu_channel_request(cam->ipu, CSI_PRP_ENC_MEM, &enc, &cam->ipu_chan); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d\n", __func__, 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_channel_request(cam->ipu, MEM_ROT_ENC_MEM, NULL, &cam->ipu_chan_rot); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d for rot\n", __func__, err); ++ 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; ++ int irq; ++ 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; ++ ++ irq = (cam->rotation >= IPU_ROTATE_90_RIGHT) ? ++ IPU_IRQ_PRP_ENC_ROT_OUT_EOF : IPU_IRQ_PRP_ENC_OUT_EOF; ++ err = ipu_request_irq(cam->ipu, irq, ++ prp_enc_callback, 0, "Mxc Camera", cam); ++ if (err) { ++ pr_err("%s: Error requesting irq=%d\n", __func__, irq); ++ 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; ++ int err2 = 0; ++ int err3 = 0; ++ ++ 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_channel_disable(cam->ipu_chan, true); ++ err2 = ipu_channel_disable(cam->ipu_chan_rot, true); ++ ++ ipu_channel_free(&cam->ipu_chan); ++ ipu_channel_free(&cam->ipu_chan_rot); ++ ++ 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; ++ } ++ err3 = cam_mipi_csi2_disable(cam); ++ return err ? err : (err2 ? err2 : err3); ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_enc_enable_csi(void *private) ++{ ++ return cam_ipu_enable_csi((cam_data *)private); ++} ++ ++/*! ++ * 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 cam_ipu_disable_csi(cam); ++} ++ ++/*! ++ * 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.72.orig/drivers/media/platform/mxc/capture/ipu_prp_sw.h linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_sw.h +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_prp_sw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_sw.h 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,43 @@ ++/* ++ * 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_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.72.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,472 @@ ++/* ++ * 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; ++ ++ 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; ++ ++ err = cam_mipi_csi2_enable(cam, &vf.csi_prp_vf_mem.mipi); ++ if (err) ++ return err; ++ ++ err = ipu_channel_request(cam->ipu, CSI_PRP_VF_MEM, &vf, &cam->ipu_chan); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d\n", __func__, err); ++ 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_channel_request(cam->ipu, MEM_ROT_VF_MEM, NULL, &cam->ipu_chan_rot); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d for rot\n", __func__, err); ++ 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_channel_free(&cam->ipu_chan_rot); ++out_3: ++ ipu_channel_free(&cam->ipu_chan); ++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) ++{ ++ int err = 0; ++ cam_data *cam = (cam_data *) private; ++ ++ if (cam->overlay_active == false) ++ return 0; ++ ++ ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam); ++ ++ ipu_channel_disable(cam->ipu_chan, true); ++ ipu_channel_disable(cam->ipu_chan_rot, true); ++ ipu_channel_free(&cam->ipu_chan); ++ ipu_channel_free(&cam->ipu_chan_rot); ++ ++ err = cam_mipi_csi2_disable(cam); ++ ++ 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 err; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_vf_enable_csi(void *private) ++{ ++ return cam_ipu_enable_csi((cam_data *)private); ++} ++ ++/*! ++ * 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 cam_ipu_disable_csi(cam); ++} ++ ++/*! ++ * 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.72.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,528 @@ ++/* ++ * 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; ++ ++ 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; ++ ++ err = cam_mipi_csi2_enable(cam, &vf.csi_prp_vf_mem.mipi); ++ if (err) ++ return err; ++ ++ err = ipu_channel_request(cam->ipu, CSI_PRP_VF_MEM, &vf, &cam->ipu_chan); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d\n", __func__, err); ++ 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_channel_request(cam->ipu, MEM_ROT_VF_MEM, NULL, &cam->ipu_chan_rot); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d for rot\n", __func__, err); ++ 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: ++ ipu_channel_free(&cam->ipu_chan_rot); ++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_channel_free(&cam->ipu_chan); ++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; ++ int err2; ++ struct fb_info *fbi = NULL; ++ struct fb_var_screeninfo fbvar; ++ ++ 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_channel_disable(cam->ipu_chan, true); ++ ipu_channel_disable(cam->ipu_chan_rot, true); ++ ipu_channel_free(&cam->ipu_chan_rot); ++ ipu_channel_free(&cam->ipu_chan); ++ ++ 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); ++ err2 = cam_mipi_csi2_disable(cam); ++ ++ 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 ? err : err2; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_vf_enable_csi(void *private) ++{ ++ return cam_ipu_enable_csi((cam_data *)private); ++} ++ ++/*! ++ * 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 cam_ipu_disable_csi(cam); ++} ++ ++/*! ++ * 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.72.orig/drivers/media/platform/mxc/capture/ipu_still.c linux-3.14.72/drivers/media/platform/mxc/capture/ipu_still.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ipu_still.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ipu_still.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,269 @@ ++/* ++ * 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_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_channel_request(cam->ipu, CSI_MEM, ¶ms, &cam->ipu_chan); ++ if (err) { ++ pr_err("%s:ipu_channel_request %d\n", __func__, 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.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); ++ cam_ipu_enable_csi(cam); ++#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 ++ ++ cam_ipu_disable_csi(cam); ++ ipu_channel_disable(cam->ipu_chan, true); ++ ipu_channel_free(&cam->ipu_chan); ++ 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.72.orig/drivers/media/platform/mxc/capture/Kconfig linux-3.14.72/drivers/media/platform/mxc/capture/Kconfig +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/Kconfig 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,108 @@ ++if VIDEO_MXC_CAPTURE ++config VIDEO_V4L2_MXC_INT_DEVICE ++ tristate ++ ++menu "MXC Camera/V4L2 PRP Features support" ++config VIDEO_MXC_IPU_CAMERA ++ bool ++ select VIDEO_V4L2_MXC_INT_DEVICE ++ select MXC_IPU_CSI_ENC ++ select MXC_IPU_PRP_ENC ++ depends on VIDEO_MXC_CAPTURE && MXC_IPU ++ default y ++ ++config MXC_TVIN_TDA1997X ++ tristate "NXP TDA1997x HDMI Receiver Input support" ++ depends on I2C ++ ---help--- ++ If you plan to use the NXP tda1997x/tdf1997x HDMI reciever with your i ++ ++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 ++ select MXC_MIPI_CSI2 ++ select VIDEO_V4L2_MXC_INT_DEVICE ++ ---help--- ++ If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here. ++ ++config MXC_CAMERA_OV5647_MIPI ++ tristate "OmniVision ov5647 camera support using mipi" ++ depends on MXC_MIPI_CSI2 ++ depends on !VIDEO_MXC_EMMA_CAMERA && I2C ++ ---help--- ++ If you plan to use the ov5647 Camera with mipi interface in your MXC system, say Y here. ++ ++config MXC_HDMI_CSI2_TC358743 ++ tristate "Toshiba tc358743 Hdmi to CSI 2 bridge" ++ depends on !VIDEO_MXC_EMMA_CAMERA && I2C ++ select MXC_MIPI_CSI2 if ARCH_MX6Q ++ select MXC_CAMERA_SENSOR_CLK ++ ---help--- ++ Toshina HDMI to MIPI-CSI2 bridge ++ ++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.72.orig/drivers/media/platform/mxc/capture/Makefile linux-3.14.72/drivers/media/platform/mxc/capture/Makefile +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/Makefile 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,30 @@ ++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_int-objs := ov5640.o ++obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera_int.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 ++ ++ov5647_camera_mipi-objs := ov5647_mipi.o ++obj-$(CONFIG_MXC_CAMERA_OV5647_MIPI) += ov5647_camera_mipi.o ++ ++tc358743_h2c_bridge-objs := tc358743_h2c.o ++obj-$(CONFIG_MXC_HDMI_CSI2_TC358743) += tc358743_h2c_bridge.o ++ ++adv7180_tvin-objs := adv7180.o ++obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o ++ ++obj-$(CONFIG_VIDEO_V4L2_MXC_INT_DEVICE) += v4l2-int-device.o ++ ++tda1997x-video-objs := tda1997x.o ++obj-$(CONFIG_MXC_TVIN_TDA1997X) += tda1997x-video.o +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c linux-3.14.72/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 2016-06-19 22:11:55.173148668 +0200 +@@ -0,0 +1,3383 @@ ++/* ++ * 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 ++#include ++#include ++#include "v4l2-int-device.h" ++#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 = 0, ++ .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("%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; ++ } ++ } ++ ++ 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; ++ u32 map_sizeimage; ++ struct sensor_data *sensor = cam->sensor->priv; ++ ++ if (sensor && sensor->adata) { ++ const struct additional_data *adata = sensor->adata; ++ map_sizeimage = adata->map_sizeimage; ++ } ++ else { ++ map_sizeimage = cam->v2f.fmt.pix.sizeimage; ++ } ++ ++ pr_debug("%s: size=%d\n", __func__, map_sizeimage); ++ ++ for (i = 0; i < count; i++) { ++ cam->frame[i].vaddress = ++ dma_alloc_coherent(0, ++ PAGE_ALIGN(map_sizeimage), ++ &cam->frame[i].paddress, ++ GFP_DMA | GFP_KERNEL); ++ if (cam->frame[i].vaddress == 0) { ++ pr_err("%s: failed.\n", __func__); ++ 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(map_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("%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 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("%s\n", __func__); ++ ++ 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("%s\n", __func__); ++ return 0; ++} ++ ++static int mxc_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf) ++{ ++ pr_debug("%s\n", __func__); ++ ++ if (buf->index < 0 || buf->index >= FRAME_NUM || buf->length < ++ 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 || ++ palette == V4L2_PIX_FMT_SBGGR8)); ++} ++ ++/*! ++ * 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("%s\n", __func__); ++ ++ 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("%s: ipu%d/csi%d capture_on=%d %s\n", __func__, cam->ipu_id, ++ cam->csi, cam->capture_on, ++ mxc_capture_inputs[cam->current_input].name); ++ 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("%s\n", __func__); ++ ++ 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("%s: type=%d\n", __func__, 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, bool try_fmt) ++{ ++ int retval = 0; ++ int size = 0; ++ int bytesperline = 0; ++ int *width, *height; ++ ++ pr_debug("%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: 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; ++ case V4L2_PIX_FMT_SBGGR8: ++ size = f->fmt.pix.width * f->fmt.pix.height; ++ 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 (try_fmt) { ++ /* XXX: workaround for gstreamer */ ++ if (f->fmt.pix.sizeimage < size || ++ f->fmt.pix.sizeimage % size) ++ f->fmt.pix.sizeimage = size; ++ else ++ size = f->fmt.pix.sizeimage; ++ ++ break; ++ } ++ else { ++ 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); ++ if (!try_fmt) ++ 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("%s\n", __func__); ++ ++ /* 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; ++} ++ ++static int mxc_v4l2_send_command(cam_data *cam, ++ struct v4l2_send_command_control *c) { ++ int ret =0; ++ ++ if (vidioc_int_send_command(cam->sensor, c)) { ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++/*! ++ * 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("%s\n", __func__); ++ ++ 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; ++ case V4L2_MXC_CAM_ROTATE_NONE: ++ if (vidioc_int_s_ctrl(cam->sensor, c)) { ++ ret = -EINVAL; ++ } ++ break; ++ case V4L2_MXC_CAM_ROTATE_VERT_FLIP: ++ if (vidioc_int_s_ctrl(cam->sensor, c)) { ++ ret = -EINVAL; ++ } ++ break; ++ case V4L2_MXC_CAM_ROTATE_HORIZ_FLIP: ++ if (vidioc_int_s_ctrl(cam->sensor, c)) { ++ ret = -EINVAL; ++ } ++ break; ++ case V4L2_MXC_CAM_ROTATE_180: ++ if (vidioc_int_s_ctrl(cam->sensor, c)) { ++ ret = -EINVAL; ++ } ++ 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_AUTO_FOCUS_START: { ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ break; ++ } ++ ++ case V4L2_CID_AUTO_FOCUS_STOP: { ++ if (vidioc_int_s_ctrl(cam->sensor, c)) { ++ ret = -EINVAL; ++ } ++ 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; ++} ++ ++void setup_ifparm(cam_data *cam, int init_defrect) ++{ ++ struct v4l2_format cam_fmt; ++ ipu_csi_signal_cfg_t csi_param; ++ struct v4l2_ifparm ifparm; ++ int swidth, sheight; ++ int sleft, stop; ++ ++ vidioc_int_g_ifparm(cam->sensor, &ifparm); ++ memset(&csi_param, 0, sizeof(csi_param)); ++ csi_param.csi = cam->csi; ++ csi_param.mclk = ifparm.u.bt656.clock_curr; ++ ++ pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr); ++ switch (ifparm.if_type) { ++ case V4L2_IF_TYPE_BT1120_PROGRESSIVE_DDR: ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR; ++ break; ++ case V4L2_IF_TYPE_BT1120_PROGRESSIVE_SDR: ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR; ++ break; ++ case V4L2_IF_TYPE_BT1120_INTERLACED_DDR: ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR; ++ break; ++ case V4L2_IF_TYPE_BT1120_INTERLACED_SDR: ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR; ++ break; ++ case V4L2_IF_TYPE_BT656_PROGRESSIVE: ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; ++ break; ++ case V4L2_IF_TYPE_BT656_INTERLACED: ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; ++ break; ++ case V4L2_IF_TYPE_BT656: ++// csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; ++// break; ++ default: ++ if (ifparm.u.bt656.clock_curr == 0) { ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; ++ /*protocol bt656 use 27Mhz pixel clock */ ++ csi_param.mclk = 27000000; ++ } else if (ifparm.u.bt656.clock_curr == 1) { ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; ++ } else ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; ++ } ++ ++ csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; ++ ++ csi_param.data_width = ++ (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) || ++ (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_BT_10BIT) ? ++ IPU_CSI_DATA_WIDTH_10 : IPU_CSI_DATA_WIDTH_8; ++ ++ csi_param.pack_tight = (csi_param.data_width == IPU_CSI_DATA_WIDTH_10) ? 1 : 0; ++ ++ 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; ++ pr_debug("vsync_pol(%d) hsync_pol(%d) ext_vsync(%d)\n", csi_param.Vsync_pol, csi_param.Hsync_pol, csi_param.ext_vsync); ++ ++ /* 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); ++ ++ switch (cam_fmt.fmt.pix.pixelformat) { ++ case V4L2_PIX_FMT_RGB565: ++ csi_param.data_fmt = IPU_PIX_FMT_RGB565; ++ break; ++ case V4L2_PIX_FMT_BGR24: ++ csi_param.data_fmt = IPU_PIX_FMT_BGR24; ++ break; ++ case V4L2_PIX_FMT_RGB24: ++ csi_param.data_fmt = IPU_PIX_FMT_RGB24; ++ break; ++ case V4L2_PIX_FMT_BGR32: ++ csi_param.data_fmt = IPU_PIX_FMT_BGR32; ++ break; ++ case V4L2_PIX_FMT_RGB32: ++ csi_param.data_fmt = IPU_PIX_FMT_RGB32; ++ break; ++ case V4L2_PIX_FMT_YUV422P: ++ csi_param.data_fmt = IPU_PIX_FMT_YUV422P; ++ break; ++ case V4L2_PIX_FMT_UYVY: ++ csi_param.data_fmt = IPU_PIX_FMT_UYVY; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ csi_param.data_fmt = IPU_PIX_FMT_YUYV; ++ break; ++ case V4L2_PIX_FMT_YUV420: ++ csi_param.data_fmt = IPU_PIX_FMT_YUV420P; ++ break; ++ case V4L2_PIX_FMT_YVU420: ++ csi_param.data_fmt = IPU_PIX_FMT_YVU420P;; ++ break; ++ case V4L2_PIX_FMT_NV12: ++ csi_param.data_fmt = IPU_PIX_FMT_NV12; ++ break; ++ case V4L2_PIX_FMT_SBGGR8: ++ default: ++ csi_param.data_fmt = IPU_PIX_FMT_GENERIC; ++ break; ++ } ++ ++ 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; ++ } ++ ++ if (init_defrect) { ++ /* 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("On Open: Input to ipu size is %d x %d\n", ++ cam_fmt.fmt.pix.width, 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); ++ } ++ swidth = cam->crop_current.width; ++ sheight = cam->crop_current.height; ++ sleft = 0; ++ stop = 0; ++ cam_fmt.type = V4L2_BUF_TYPE_SENSOR; ++ cam_fmt.fmt.spix.swidth = 0; ++ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); ++ if (cam_fmt.fmt.spix.swidth) { ++ swidth = cam_fmt.fmt.spix.swidth; ++ sheight = cam_fmt.fmt.spix.sheight; ++ sleft = cam_fmt.fmt.spix.left; ++ stop = cam_fmt.fmt.spix.top; ++ } ++ /* 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_window_size_crop(cam->ipu, ++ swidth, sheight, ++ cam->crop_current.width, cam->crop_current.height, ++ sleft + cam->crop_current.left, stop + cam->crop_current.top, ++ cam->csi); ++ ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width, ++ cam->crop_bounds.height, ++ csi_param.data_fmt, csi_param); ++} ++ ++/*! ++ * 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_streamparm currentparm; ++ u32 current_fps, parm_fps; ++ int err = 0; ++ ++ pr_debug("%s\n", __func__); ++ ++ 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. */ ++ setup_ifparm(cam, 0); ++ ++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("%s: %Lx\n", __func__, e); ++ switch (e) { ++ case V4L2_STD_PAL: ++ pr_debug(" Setting standard to PAL %Lx\n", V4L2_STD_PAL); ++ cam->standard.id = V4L2_STD_PAL; ++ video_index = TV_PAL; ++ break; ++ case 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; ++ break; ++ case V4L2_STD_UNKNOWN: ++ case V4L2_STD_ALL: ++ /* auto-detect don't report an error */ ++ cam->standard.id = V4L2_STD_ALL; ++ video_index = TV_NOT_LOCKED; ++ break; ++ default: ++ 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("%s\n", __func__); ++ ++ 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("%s\n", __func__); ++ ++ if (!wait_event_interruptible_timeout(cam->enc_queue, ++ cam->enc_counter != 0, ++ 50 * 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; ++} ++ ++static void power_down_callback(struct work_struct *work) ++{ ++ cam_data *cam = container_of(work, struct _cam_data, power_down_work.work); ++ ++ down(&cam->busy_lock); ++ if (!cam->open_count) { ++ pr_info("%s: ipu%d/csi%d\n", __func__, cam->ipu_id, cam->csi); ++ vidioc_int_s_power(cam->sensor, 0); ++ cam->power_on = 0; ++ } ++ up(&cam->busy_lock); ++} ++ ++/* cam->busy_lock is held */ ++void power_up_camera(cam_data *cam) ++{ ++ if (cam->power_on) { ++ cancel_delayed_work(&cam->power_down_work); ++ return; ++ } ++ vidioc_int_s_power(cam->sensor, 1); ++ vidioc_int_init(cam->sensor); ++ vidioc_int_dev_init(cam->sensor); ++ cam->power_on = 1; ++} ++ ++ ++void power_off_camera(cam_data *cam) ++{ ++ schedule_delayed_work(&cam->power_down_work, (HZ * 2)); ++} ++ ++unsigned long csi_in_use; ++ ++/*! ++ * 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 video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ int err = 0; ++ struct sensor_data *sensor; ++ int csi_bit; ++ ++ if (!cam) { ++ pr_err("%s: %s cam_data not found!\n", __func__, dev->name); ++ return -EBADF; ++ } ++ if (!cam->sensor) { ++ pr_err("%s: %s no sensor ipu%d/csi%d\n", ++ __func__, dev->name, cam->ipu_id, cam->csi); ++ return -EAGAIN; ++ } ++ if (cam->sensor->type != v4l2_int_type_slave) { ++ pr_err("%s: %s wrong type ipu%d/csi%d, type=%d/%d\n", ++ __func__, dev->name, cam->ipu_id, cam->csi, ++ cam->sensor->type, v4l2_int_type_slave); ++ return -EAGAIN; ++ } ++ ++ sensor = cam->sensor->priv; ++ if (!sensor) { ++ pr_err("%s: Internal error, sensor_data is not found!\n", ++ __func__); ++ return -EBADF; ++ } ++ pr_debug("%s: %s ipu%d/csi%d\n", __func__, dev->name, ++ cam->ipu_id, cam->csi); ++ ++ down(&cam->busy_lock); ++ ++ err = 0; ++ if (signal_pending(current)) ++ goto oops; ++ ++ if (cam->open_count++ == 0) { ++ struct regmap *gpr; ++ ++ csi_bit = (cam->ipu_id << 1) | cam->csi; ++ if (test_and_set_bit(csi_bit, &csi_in_use)) { ++ pr_err("%s: %s CSI already in use\n", __func__, dev->name); ++ err = -EBUSY; ++ cam->open_count = 0; ++ goto oops; ++ } ++ cam->csi_in_use = 1; ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ if (of_machine_is_compatible("fsl,imx6q")) { ++ if (cam->ipu_id == cam->csi) { ++ unsigned shift = 19 + cam->csi; ++ unsigned mask = 1 << shift; ++ unsigned val = (cam->mipi_camera ? 0 : 1) << shift; ++ ++ regmap_update_bits(gpr, IOMUXC_GPR1, mask, val); ++ } ++ } else if (of_machine_is_compatible("fsl,imx6dl")) { ++ unsigned shift = cam->csi * 3; ++ unsigned mask = 7 << shift; ++ unsigned val = (cam->mipi_camera ? csi_bit : 4) << shift; ++ ++ regmap_update_bits(gpr, IOMUXC_GPR13, mask, val); ++ } ++ } else { ++ pr_err("%s: failed to find fsl,imx6q-iomux-gpr regmap\n", ++ __func__); ++ } ++ ++ 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); ++ setup_ifparm(cam, 1); ++ if (!IS_ERR(sensor->sensor_clk)) ++ clk_prepare_enable(sensor->sensor_clk); ++ power_up_camera(cam); ++ } ++ ++ 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("%s\n", __func__); ++ ++ if (!cam) { ++ pr_err("%s: 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); ++ ++ /* 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->open_count == 0) { ++ if (cam->capture_pid == current->pid) { ++ err |= mxc_streamoff(cam); ++ wake_up_interruptible(&cam->enc_queue); ++ } ++ if (!IS_ERR(sensor->sensor_clk)) ++ 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++; ++ power_off_camera(cam); ++ ++ if (cam->csi_in_use) { ++ int csi_bit = (cam->ipu_id << 1) | cam->csi; ++ ++ clear_bit(csi_bit, &csi_in_use); ++ cam->csi_in_use = 0; ++ } ++ } ++ ++ 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("%s: %x ipu%d/csi%d\n", __func__, ioctlnr, cam->ipu_id, cam->csi); ++ 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 ++ */ ++ /* XXX: workaround for gstreamer */ ++ case VIDIOC_TRY_FMT: { ++ struct v4l2_format *sf = arg; ++ pr_debug(" case VIDIOC_TRY_FMT\n"); ++ retval = mxc_v4l2_s_fmt(cam, sf, true); ++ break; ++ } ++ case VIDIOC_S_FMT: { ++ struct v4l2_format *sf = arg; ++ pr_debug(" case VIDIOC_S_FMT\n"); ++ retval = mxc_v4l2_s_fmt(cam, sf, false); ++ 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"); ++ if (e->index > 0) { ++ retval = -EINVAL; ++ break; ++ } ++ *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_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_SEND_COMMAND: { ++ retval = mxc_v4l2_send_command(cam, arg); ++ break; ++ } ++ ++ /* XXX: workaround for gstreamer */ ++/* 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("%s\n", __func__); ++ 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("%s:pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__, ++ 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("%s\n", __func__); ++ ++ 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("%s\n", __func__); ++ ++ 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, mipi_camera, def_input; ++ int ret = 0; ++ struct v4l2_device *v4l2_dev; ++ static int camera_id; ++ ++ pr_debug("%s\n", __func__); ++ ++ 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; ++ } ++ ++ ret = of_property_read_u32(np, "mipi_camera", &mipi_camera); ++ if (ret) ++ mipi_camera = 0; ++ ++ ret = of_property_read_u32(np, "default_input", &def_input); ++ if (ret || (def_input != 0 && def_input != 1)) ++ def_input = 0; ++ ++ /* 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); ++ INIT_DELAYED_WORK(&cam->power_down_work, power_down_callback); ++ ++ 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; ++ ++ v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL); ++ if (!v4l2_dev) { ++ dev_err(&pdev->dev, "failed to allocate v4l2_dev structure\n"); ++ video_device_release(cam->video_dev); ++ return -ENOMEM; ++ } ++ ++ if (v4l2_device_register(&pdev->dev, v4l2_dev) < 0) { ++ dev_err(&pdev->dev, "register v4l2 device failed\n"); ++ video_device_release(cam->video_dev); ++ kfree(v4l2_dev); ++ return -ENODEV; ++ } ++ cam->video_dev->v4l2_dev = v4l2_dev; ++ ++ 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->mipi_camera = mipi_camera; ++ cam->mclk_source = mclk_source; ++ cam->mclk_on[cam->mclk_source] = false; ++ cam->current_input = def_input; ++ ++ 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->dummy_frame.vaddress = dma_alloc_coherent(0, ++ SZ_8M, &cam->dummy_frame.paddress, ++ GFP_DMA | GFP_KERNEL); ++ if (cam->dummy_frame.vaddress == 0) ++ pr_err("ERROR: v4l2 capture: Allocate dummy frame " ++ "failed.\n"); ++ cam->dummy_frame.buffer.length = SZ_8M; ++ ++ cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL); ++ cam->self->module = THIS_MODULE; ++ sprintf(cam->self->name, "mxc_v4l2_cap%d", camera_id++); ++ 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) ++{ ++ int err; ++ ++ /* 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; ++ } ++ ++ err = init_camera_struct(cam, pdev); ++ if (err) ++ return err; ++ 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) ++ < 0) { ++ kfree(cam); ++ cam = NULL; ++ pr_err("ERROR: v4l2 capture: video_register_device failed\n"); ++ return -1; ++ } ++ ++ pr_info("V4L2 device '%s' on IPU%d_CSI%d registered as %s\n", ++ cam->video_dev->name, ++ cam->ipu_id + 1, cam->csi, ++ video_device_node_name(cam->video_dev)); ++ ++ 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 { ++ struct v4l2_device *v4l2_dev = cam->video_dev->v4l2_dev; ++ 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); ++ ++ 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; ++ } ++ ++ mxc_free_frame_buf(cam); ++ kfree(cam); ++ ++ v4l2_device_unregister(v4l2_dev); ++ kfree(v4l2_dev); ++ } ++ ++ 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("%s\n", __func__); ++ ++ 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("%s\n", __func__); ++ ++ 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) { ++ if ((cam->overlay_on == true) || (cam->capture_on == true)) ++ 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("%s:slave.name = %s, master.name = %s\n", __func__, ++ slave->name, slave->u.slave->master->name); ++ ++ if (slave == NULL) { ++ pr_err("ERROR: v4l2 capture: slave parameter not valid.\n"); ++ return -1; ++ } ++ ++ if ((sdata->ipu_id != cam->ipu_id) || (sdata->csi != cam->csi) || (sdata->mipi_camera != cam->mipi_camera)) { ++ pr_info("%s: ipu(%d:%d)/csi(%d:%d)/mipi(%d:%d) doesn't match\n", __func__, ++ sdata->ipu_id, cam->ipu_id, sdata->csi, cam->csi, sdata->mipi_camera, cam->mipi_camera); ++ 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++) { ++ pr_err("%s: %x\n", __func__, 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); ++ ++ pr_info("%s: ipu%d:/csi%d %s attached %s:%s\n", __func__, ++ cam->ipu_id, cam->csi, cam->mipi_camera ? "mipi" : "parallel", ++ slave->name, slave->u.slave->master->name); ++ 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("%s\n", __func__); ++ ++ 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); ++} ++ ++DEFINE_MUTEX(camera_common_mutex); ++ ++void mxc_camera_common_lock(void) ++{ ++ mutex_lock(&camera_common_mutex); ++} ++EXPORT_SYMBOL(mxc_camera_common_lock); ++ ++void mxc_camera_common_unlock(void) ++{ ++ mutex_unlock(&camera_common_mutex); ++} ++EXPORT_SYMBOL(mxc_camera_common_unlock); ++ ++/*! ++ * Entry point for the V4L2 ++ * ++ * @return Error code indicating success or failure ++ */ ++static __init int camera_init(void) ++{ ++ u8 err = 0; ++ ++ pr_debug("%s\n", __func__); ++ ++ /* 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("%s\n", __func__); ++ ++ 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.72.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h linux-3.14.72/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 2016-06-19 22:11:55.177148406 +0200 +@@ -0,0 +1,358 @@ ++/* ++ * 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 ++ */ ++ ++/*! ++ * @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 ++#include "v4l2-int-device.h" ++ ++ ++#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; ++ struct delayed_work power_down_work; ++ int power_on; ++ ++ /* 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; ++ struct v4l2_format input_fmt; /* camera in */ ++ bool bswapenable; ++ 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; ++ bool ipu_enable_csi_called; ++ bool mipi_pixelclk_enabled; ++ struct ipu_chan *ipu_chan; ++ struct ipu_chan *ipu_chan_rot; ++ int overlay_pid; ++ int capture_pid; ++ bool low_power; ++ wait_queue_head_t power_queue; ++ unsigned int ipu_id; ++ unsigned int csi; ++ unsigned mipi_camera; ++ int csi_in_use; ++ 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; ++ void *csi_soc; ++ 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 additional_data { ++ u32 map_sizeimage; ++}; ++ ++struct sensor_data { ++ const struct additional_data *adata; ++ struct v4l2_int_device *v4l2_int_device; ++ struct i2c_client *i2c_client; ++ struct v4l2_pix_format pix; ++ struct v4l2_sensor_dimension spix; ++ 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 ipu_id; ++ int csi; ++ int last_reg; ++ unsigned mipi_camera; ++ unsigned virtual_channel; /* Used with mipi */ ++ ++ void (*io_init)(void); ++}; ++ ++void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi); ++void mxc_camera_common_lock(void); ++void mxc_camera_common_unlock(void); ++ ++static inline int cam_ipu_enable_csi(cam_data *cam) ++{ ++ int ret = ipu_enable_csi(cam->ipu, cam->csi); ++ if (!ret) ++ cam->ipu_enable_csi_called = 1; ++ return ret; ++} ++ ++static inline int cam_ipu_disable_csi(cam_data *cam) ++{ ++ if (!cam->ipu_enable_csi_called) ++ return 0; ++ cam->ipu_enable_csi_called = 0; ++ return ipu_disable_csi(cam->ipu, cam->csi); ++} ++ ++static inline int cam_mipi_csi2_enable(cam_data *cam, struct mipi_fields *mf) ++{ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ struct sensor_data *sensor; ++ ++ if (!cam->sensor) ++ return 0; ++ sensor = cam->sensor->priv; ++ if (!sensor) ++ return 0; ++ if (!sensor->mipi_camera) ++ return 0; ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (!mipi_csi2_info) { ++// printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++// __func__, __FILE__); ++// return -EPERM; ++ return 0; ++ } ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ mf->en = true; ++ mf->vc = 0;//sensor->virtual_channel; ++ mf->id = mipi_csi2_get_datatype(mipi_csi2_info); ++ if (!mipi_csi2_pixelclk_enable(mipi_csi2_info)) ++ cam->mipi_pixelclk_enabled = 1; ++ return 0; ++ } ++ mf->en = false; ++ mf->vc = 0; ++ mf->id = 0; ++#endif ++ return 0; ++} ++ ++static inline int cam_mipi_csi2_disable(cam_data *cam) ++{ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ ++ if (!cam->mipi_pixelclk_enabled) ++ return 0; ++ cam->mipi_pixelclk_enabled = 0; ++ ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (!mipi_csi2_info) { ++// printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++// __func__, __FILE__); ++// return -EPERM; ++ return 0; ++ } ++ if (mipi_csi2_get_status(mipi_csi2_info)) ++ mipi_csi2_pixelclk_disable(mipi_csi2_info); ++#endif ++ return 0; ++} ++#endif /* __MXC_V4L2_CAPTURE_H__ */ +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/capture/ov5640.c linux-3.14.72/drivers/media/platform/mxc/capture/ov5640.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ov5640.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ov5640.c 2016-06-19 22:11:55.177148406 +0200 +@@ -0,0 +1,1958 @@ ++/* ++ * Copyright (C) 2012-2015 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 "v4l2-int-device.h" ++#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[] = { ++ {"ov564x", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, ov5640_id); ++ ++static struct i2c_driver ov5640_i2c_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ov564x", ++ }, ++ .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 */ ++static 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 = "ov564x", ++ .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; ++ struct sensor_data *sensor = &ov5640_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; ++ } ++ 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, "ipu_id", ++ &sensor->ipu_id); ++ if (retval) { ++ dev_err(dev, "ipu_id 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 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.72.orig/drivers/media/platform/mxc/capture/ov5640_mipi.c linux-3.14.72/drivers/media/platform/mxc/capture/ov5640_mipi.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ov5640_mipi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ov5640_mipi.c 2016-06-19 22:11:55.177148406 +0200 +@@ -0,0 +1,2231 @@ ++/* ++ * Copyright (C) 2011-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., ++ * 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 "v4l2-int-device.h" ++#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 ++}; ++ ++static int ov5640_framerates[] = { ++ [ov5640_15_fps] = 15, ++ [ov5640_30_fps] = 30, ++}; ++ ++/* 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); ++ pr_debug("ov5640_mipi_camera_powerdown: powerdown=%x, power_gp=0x%x\n", enable, pwn_gpio); ++ 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; ++ } ++ pr_debug("reg=%x,val=%x\n", reg, val); ++ return 0; ++} ++ ++static s32 ov5640_read_reg(u16 reg, u8 *val) ++{ ++ struct sensor_data *sensor = &ov5640_data; ++ struct i2c_client *client = sensor->i2c_client; ++ struct i2c_msg msgs[2]; ++ u8 buf[2]; ++ int ret; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].addr = client->addr; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = 1; ++ msgs[1].buf = buf; ++ ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if (ret < 0) { ++ pr_err("%s(mipi):reg=%x ret=%d\n", __func__, reg, ret); ++ return ret; ++ } ++ *val = buf[0]; ++ pr_debug("%s(mipi):reg=%x,val=%x\n", __func__, reg, buf[0]); ++ return buf[0]; ++} ++ ++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); ++} ++ ++static const int sclk_rdiv_map[] = {1, 2, 4, 8}; ++ ++int OV5640_get_sysclk(void) ++{ ++ /* calculate sysclk */ ++ int tmp; ++ unsigned Multiplier, PreDiv, SysDiv, Pll_rdiv, Bit_div2x = 1; ++ unsigned div, sclk_rdiv, sysclk; ++ u8 temp; ++ ++ tmp = ov5640_read_reg(0x3034, &temp); ++ if (tmp < 0) ++ return tmp; ++ tmp &= 0x0f; ++ if (tmp == 8 || tmp == 10) ++ Bit_div2x = tmp / 2; ++ ++ tmp = ov5640_read_reg(0x3035, &temp); ++ if (tmp < 0) ++ return tmp; ++ SysDiv = tmp >> 4; ++ if (SysDiv == 0) ++ SysDiv = 16; ++ ++ tmp = ov5640_read_reg(0x3036, &temp); ++ if (tmp < 0) ++ return tmp; ++ Multiplier = tmp; ++ ++ tmp = ov5640_read_reg(0x3037, &temp); ++ if (tmp < 0) ++ return tmp; ++ PreDiv = tmp & 0x0f; ++ Pll_rdiv = ((tmp >> 4) & 0x01) + 1; ++ ++ tmp = ov5640_read_reg(0x3108, &temp); ++ if (tmp < 0) ++ return tmp; ++ sclk_rdiv = sclk_rdiv_map[tmp & 0x03]; ++ ++ sysclk = ov5640_data.mclk / 10000 * Multiplier; ++ div = PreDiv * SysDiv * Pll_rdiv * Bit_div2x * sclk_rdiv; ++ if (!div) { ++ pr_err("%s:Error divide by 0, (%d * %d * %d * %d * %d)\n", ++ __func__, PreDiv, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv); ++ return -EINVAL; ++ } ++ if (!sysclk) { ++ pr_err("%s:Error 0 clk, ov5640_data.mclk=%d, Multiplier=%d\n", ++ __func__, ov5640_data.mclk, Multiplier); ++ return -EINVAL; ++ } ++ sysclk /= div; ++ pr_debug("%s: sysclk(%d) = %d / 10000 * %d / (%d * %d * %d * %d * %d)\n", ++ __func__, sysclk, ov5640_data.mclk, Multiplier, ++ PreDiv, SysDiv, Pll_rdiv, 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 */ ++ light_freq = 60; ++ } ++ } ++ 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 ov5640_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 ((ov5640_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, 2); ++ ++ /*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.virtual_channel); ++ ++ /* 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 = 0; ++ ++ /* wait for mipi sensor ready */ ++ while (1) { ++ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); ++ if (mipi_reg != 0x200) ++ break; ++ if (i++ >= 20) { ++ pr_err("mipi csi2 can not receive sensor clk! %x\n", mipi_reg); ++ return -1; ++ } ++ msleep(10); ++ } ++ ++ i = 0; ++ /* wait for mipi stable */ ++ while (1) { ++ mipi_reg = mipi_csi2_get_error1(mipi_csi2_info); ++ if (!mipi_reg) ++ break; ++ if (i++ >= 20) { ++ pr_err("mipi csi2 can not receive data correctly!\n"); ++ return -1; ++ } ++ msleep(10); ++ } ++ ++ } ++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; ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ f->fmt.pix = sensor->pix; ++ pr_debug("%s: %dx%d\n", __func__, sensor->pix.width, sensor->pix.height); ++ break; ++ ++ case V4L2_BUF_TYPE_SENSOR: ++ pr_debug("%s: left=%d, top=%d, %dx%d\n", __func__, ++ sensor->spix.left, sensor->spix.top, ++ sensor->spix.swidth, sensor->spix.sheight); ++ f->fmt.spix = sensor->spix; ++ break; ++ ++ case V4L2_BUF_TYPE_PRIVATE: ++ break; ++ ++ default: ++ f->fmt.pix = sensor->pix; ++ break; ++ } ++ ++ 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 = 0; ++ ++ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; ++ fival->discrete.numerator = 1; ++ ++ 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 ++ && fival->index == count++) { ++ 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_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_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_mipi", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &ov5640_slave, ++ }, ++}; ++ ++static ssize_t show_reg(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 val; ++ s32 rval = ov5640_read_reg(ov5640_data.last_reg, &val); ++ ++ return sprintf(buf, "ov5640[0x%04x]=0x%02x\n",ov5640_data.last_reg, rval); ++} ++static ssize_t set_reg(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int regnum, value; ++ int num_parsed = sscanf(buf, "%04x=%02x", ®num, &value); ++ if (1 <= num_parsed) { ++ if (0xffff < (unsigned)regnum){ ++ pr_err("%s:invalid regnum %x\n", __func__, regnum); ++ return 0; ++ } ++ ov5640_data.last_reg = regnum; ++ } ++ if (2 == num_parsed) { ++ if (0xff < (unsigned)value) { ++ pr_err("%s:invalid value %x\n", __func__, value); ++ return 0; ++ } ++ ov5640_write_reg(ov5640_data.last_reg, value); ++ } ++ return count; ++} ++static DEVICE_ATTR(ov5640_reg, S_IRUGO|S_IWUGO, show_reg, set_reg); ++ ++/*! ++ * 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; ++ struct sensor_data *sensor = &ov5640_data; ++ ++ /* 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) { ++ dev_warn(dev, "request of pwn_gpio failed"); ++ 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) { ++ dev_warn(dev, "request of ov5640_mipi_reset failed"); ++ return retval; ++ } ++ ++ /* Set initial values for the sensor struct. */ ++ memset(&ov5640_data, 0, sizeof(ov5640_data)); ++ ++ sensor->mipi_camera = 1; ++ 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, "ipu_id", ++ &sensor->ipu_id); ++ if (retval) { ++ dev_err(dev, "ipu_id 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; ++ } ++ ++ sensor->virtual_channel = sensor->csi | (sensor->ipu_id << 1); ++ ov5640_standby(1); ++ ++ ov5640_int_device.priv = &ov5640_data; ++ retval = v4l2_int_device_register(&ov5640_int_device); ++ ++// clk_disable_unprepare(ov5640_data.sensor_clk); ++ ++ if (device_create_file(dev, &dev_attr_ov5640_reg)) ++ dev_err(dev, "%s: error creating ov5640_reg entry\n", __func__); ++ 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.72.orig/drivers/media/platform/mxc/capture/ov5642.c linux-3.14.72/drivers/media/platform/mxc/capture/ov5642.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ov5642.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ov5642.c 2016-06-19 22:11:55.181148143 +0200 +@@ -0,0 +1,6294 @@ ++/* ++ * Copyright (C) 2012-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., ++ * 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 "v4l2-int-device.h" ++#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 ++ ++/* OV5642 Camera Auto Focus Registers */ ++#define REG_CMD_MAIN 0x3024 ++#define REG_STA_FOCUS 0x3027 ++#define REG_STA_ZONE 0x3026 ++#define REG_CMD_TAG 0x3025 ++#define REG_CMD_PARA3 0x5082 ++#define REG_CMD_PARA2 0x5083 ++#define REG_CMD_PARA1 0x5084 ++#define REG_CMD_PARA0 0x5085 ++ ++ ++/* OV5642 Auto Focus Commands and Responses */ ++#define S_STARTUP 0xFA ++#define S_FIRWARE 0xFF ++#define S_STARTUP 0xFA ++#define S_ERROR 0xFE ++#define S_DRVICERR 0xEE ++#define S_IDLE 0x00 ++#define S_FOCUSING 0x01 ++#define S_FOCUSED 0x02 ++#define S_CAPTURE 0x12 ++#define S_STEP 0x20 ++ ++/*OV5642 AWB Registers*/ ++#define REG_AWB_MANUAL 0x3406 ++#define REG_AWB_R_GAIN_HIGH 0x3400 ++#define REG_AWB_R_GAIN_LOW 0x3401 ++#define REG_AWB_G_GAIN_HIGH 0x3402 ++#define REG_AWB_G_GAIN_LOW 0x3403 ++#define REG_AWB_B_GAIN_HIGH 0x3404 ++#define REG_AWB_B_GAIN_LOW 0x3405 ++ ++#define CMD_ENABLE_OVERLAY 0x01 ++#define CMD_DISABLE_OVERLAY 0x02 ++#define CMD_SINGLE_FOCUS_MODE 0x03 ++#define CMD_CONST_FOCUS_MODE 0x04 ++#define CMD_STEP_FOCUS_MODE 0x05 ++#define CMD_PAUSE 0x06 ++#define CMD_IDLE_MODE 0x08 ++#define CMD_SET_ZONE_MODE 0x10 ++#define CMD_UPDATE_ZONE_MODE 0x12 ++#define CMD_MOTOR_MODE 0x20 ++#define CMD_SCAN_MODE 0x30 ++ ++#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_af_firmware[] = { ++ {0x3000, 0x20, 0, 0},{0x8000, 0x02, 0, 0},{0x8001, 0x00, 0, 0}, ++ {0x8002, 0x06, 0, 0},{0x8003, 0x02, 0, 0},{0x8004, 0x0b, 0, 0}, ++ {0x8005, 0x44, 0, 0},{0x8006, 0x78, 0, 0},{0x8007, 0x7f, 0, 0}, ++ {0x8008, 0xe4, 0, 0},{0x8009, 0xf6, 0, 0},{0x800a, 0xd8, 0, 0}, ++ {0x800b, 0xfd, 0, 0},{0x800c, 0x75, 0, 0},{0x800d, 0x81, 0, 0}, ++ {0x800e, 0x7d, 0, 0},{0x800f, 0x02, 0, 0},{0x8010, 0x13, 0, 0}, ++ {0x8011, 0xb6, 0, 0},{0x8012, 0x00, 0, 0},{0x8013, 0x02, 0, 0}, ++ {0x8014, 0x12, 0, 0},{0x8015, 0xe1, 0, 0},{0x8016, 0xe0, 0, 0}, ++ {0x8017, 0xf5, 0, 0},{0x8018, 0x71, 0, 0},{0x8019, 0xa3, 0, 0}, ++ {0x801a, 0xe0, 0, 0},{0x801b, 0xf5, 0, 0},{0x801c, 0x72, 0, 0}, ++ {0x801d, 0xae, 0, 0},{0x801e, 0x69, 0, 0},{0x801f, 0xe4, 0, 0}, ++ {0x8020, 0x85, 0, 0},{0x8021, 0x6a, 0, 0},{0x8022, 0x55, 0, 0}, ++ {0x8023, 0x8e, 0, 0},{0x8024, 0x54, 0, 0},{0x8025, 0xf5, 0, 0}, ++ {0x8026, 0x53, 0, 0},{0x8027, 0xf5, 0, 0},{0x8028, 0x52, 0, 0}, ++ {0x8029, 0xab, 0, 0},{0x802a, 0x55, 0, 0},{0x802b, 0xaa, 0, 0}, ++ {0x802c, 0x54, 0, 0},{0x802d, 0xa9, 0, 0},{0x802e, 0x53, 0, 0}, ++ {0x802f, 0xa8, 0, 0},{0x8030, 0x52, 0, 0},{0x8031, 0xaf, 0, 0}, ++ {0x8032, 0x2c, 0, 0},{0x8033, 0xfc, 0, 0},{0x8034, 0xfd, 0, 0}, ++ {0x8035, 0xfe, 0, 0},{0x8036, 0x12, 0, 0},{0x8037, 0x08, 0, 0}, ++ {0x8038, 0x7f, 0, 0},{0x8039, 0x8f, 0, 0},{0x803a, 0x55, 0, 0}, ++ {0x803b, 0x8e, 0, 0},{0x803c, 0x54, 0, 0},{0x803d, 0x8d, 0, 0}, ++ {0x803e, 0x53, 0, 0},{0x803f, 0x8c, 0, 0},{0x8040, 0x52, 0, 0}, ++ {0x8041, 0xaf, 0, 0},{0x8042, 0x55, 0, 0},{0x8043, 0xae, 0, 0}, ++ {0x8044, 0x54, 0, 0},{0x8045, 0xad, 0, 0},{0x8046, 0x53, 0, 0}, ++ {0x8047, 0xac, 0, 0},{0x8048, 0x52, 0, 0},{0x8049, 0x8f, 0, 0}, ++ {0x804a, 0x2b, 0, 0},{0x804b, 0x8e, 0, 0},{0x804c, 0x2a, 0, 0}, ++ {0x804d, 0x8d, 0, 0},{0x804e, 0x29, 0, 0},{0x804f, 0x8c, 0, 0}, ++ {0x8050, 0x28, 0, 0},{0x8051, 0xae, 0, 0},{0x8052, 0x6b, 0, 0}, ++ {0x8053, 0xe4, 0, 0},{0x8054, 0x85, 0, 0},{0x8055, 0x6c, 0, 0}, ++ {0x8056, 0x55, 0, 0},{0x8057, 0x8e, 0, 0},{0x8058, 0x54, 0, 0}, ++ {0x8059, 0xf5, 0, 0},{0x805a, 0x53, 0, 0},{0x805b, 0xf5, 0, 0}, ++ {0x805c, 0x52, 0, 0},{0x805d, 0xab, 0, 0},{0x805e, 0x55, 0, 0}, ++ {0x805f, 0xaa, 0, 0},{0x8060, 0x54, 0, 0},{0x8061, 0xa9, 0, 0}, ++ {0x8062, 0x53, 0, 0},{0x8063, 0xa8, 0, 0},{0x8064, 0x52, 0, 0}, ++ {0x8065, 0xaf, 0, 0},{0x8066, 0x2d, 0, 0},{0x8067, 0xfc, 0, 0}, ++ {0x8068, 0xfd, 0, 0},{0x8069, 0xfe, 0, 0},{0x806a, 0x12, 0, 0}, ++ {0x806b, 0x08, 0, 0},{0x806c, 0x7f, 0, 0},{0x806d, 0x8f, 0, 0}, ++ {0x806e, 0x55, 0, 0},{0x806f, 0x8e, 0, 0},{0x8070, 0x54, 0, 0}, ++ {0x8071, 0x8d, 0, 0},{0x8072, 0x53, 0, 0},{0x8073, 0x8c, 0, 0}, ++ {0x8074, 0x52, 0, 0},{0x8075, 0xe5, 0, 0},{0x8076, 0x2b, 0, 0}, ++ {0x8077, 0x25, 0, 0},{0x8078, 0x55, 0, 0},{0x8079, 0xf5, 0, 0}, ++ {0x807a, 0x2b, 0, 0},{0x807b, 0xe5, 0, 0},{0x807c, 0x2a, 0, 0}, ++ {0x807d, 0x35, 0, 0},{0x807e, 0x54, 0, 0},{0x807f, 0xf5, 0, 0}, ++ {0x8080, 0x2a, 0, 0},{0x8081, 0xe5, 0, 0},{0x8082, 0x29, 0, 0}, ++ {0x8083, 0x35, 0, 0},{0x8084, 0x53, 0, 0},{0x8085, 0xf5, 0, 0}, ++ {0x8086, 0x29, 0, 0},{0x8087, 0xe5, 0, 0},{0x8088, 0x28, 0, 0}, ++ {0x8089, 0x35, 0, 0},{0x808a, 0x52, 0, 0},{0x808b, 0xf5, 0, 0}, ++ {0x808c, 0x28, 0, 0},{0x808d, 0xae, 0, 0},{0x808e, 0x6d, 0, 0}, ++ {0x808f, 0xe4, 0, 0},{0x8090, 0x85, 0, 0},{0x8091, 0x6e, 0, 0}, ++ {0x8092, 0x55, 0, 0},{0x8093, 0x8e, 0, 0},{0x8094, 0x54, 0, 0}, ++ {0x8095, 0xf5, 0, 0},{0x8096, 0x53, 0, 0},{0x8097, 0xf5, 0, 0}, ++ {0x8098, 0x52, 0, 0},{0x8099, 0xab, 0, 0},{0x809a, 0x55, 0, 0}, ++ {0x809b, 0xaa, 0, 0},{0x809c, 0x54, 0, 0},{0x809d, 0xa9, 0, 0}, ++ {0x809e, 0x53, 0, 0},{0x809f, 0xa8, 0, 0},{0x80a0, 0x52, 0, 0}, ++ {0x80a1, 0xaf, 0, 0},{0x80a2, 0x2e, 0, 0},{0x80a3, 0xfc, 0, 0}, ++ {0x80a4, 0xfd, 0, 0},{0x80a5, 0xfe, 0, 0},{0x80a6, 0x12, 0, 0}, ++ {0x80a7, 0x08, 0, 0},{0x80a8, 0x7f, 0, 0},{0x80a9, 0x8f, 0, 0}, ++ {0x80aa, 0x55, 0, 0},{0x80ab, 0x8e, 0, 0},{0x80ac, 0x54, 0, 0}, ++ {0x80ad, 0x8d, 0, 0},{0x80ae, 0x53, 0, 0},{0x80af, 0x8c, 0, 0}, ++ {0x80b0, 0x52, 0, 0},{0x80b1, 0xe5, 0, 0},{0x80b2, 0x2b, 0, 0}, ++ {0x80b3, 0x25, 0, 0},{0x80b4, 0x55, 0, 0},{0x80b5, 0xf5, 0, 0}, ++ {0x80b6, 0x2b, 0, 0},{0x80b7, 0xe5, 0, 0},{0x80b8, 0x2a, 0, 0}, ++ {0x80b9, 0x35, 0, 0},{0x80ba, 0x54, 0, 0},{0x80bb, 0xf5, 0, 0}, ++ {0x80bc, 0x2a, 0, 0},{0x80bd, 0xe5, 0, 0},{0x80be, 0x29, 0, 0}, ++ {0x80bf, 0x35, 0, 0},{0x80c0, 0x53, 0, 0},{0x80c1, 0xf5, 0, 0}, ++ {0x80c2, 0x29, 0, 0},{0x80c3, 0xe5, 0, 0},{0x80c4, 0x28, 0, 0}, ++ {0x80c5, 0x35, 0, 0},{0x80c6, 0x52, 0, 0},{0x80c7, 0xf5, 0, 0}, ++ {0x80c8, 0x28, 0, 0},{0x80c9, 0xae, 0, 0},{0x80ca, 0x6f, 0, 0}, ++ {0x80cb, 0xe4, 0, 0},{0x80cc, 0x85, 0, 0},{0x80cd, 0x70, 0, 0}, ++ {0x80ce, 0x55, 0, 0},{0x80cf, 0x8e, 0, 0},{0x80d0, 0x54, 0, 0}, ++ {0x80d1, 0xf5, 0, 0},{0x80d2, 0x53, 0, 0},{0x80d3, 0xf5, 0, 0}, ++ {0x80d4, 0x52, 0, 0},{0x80d5, 0xab, 0, 0},{0x80d6, 0x55, 0, 0}, ++ {0x80d7, 0xaa, 0, 0},{0x80d8, 0x54, 0, 0},{0x80d9, 0xa9, 0, 0}, ++ {0x80da, 0x53, 0, 0},{0x80db, 0xa8, 0, 0},{0x80dc, 0x52, 0, 0}, ++ {0x80dd, 0xaf, 0, 0},{0x80de, 0x2f, 0, 0},{0x80df, 0xfc, 0, 0}, ++ {0x80e0, 0xfd, 0, 0},{0x80e1, 0xfe, 0, 0},{0x80e2, 0x12, 0, 0}, ++ {0x80e3, 0x08, 0, 0},{0x80e4, 0x7f, 0, 0},{0x80e5, 0x8f, 0, 0}, ++ {0x80e6, 0x55, 0, 0},{0x80e7, 0x8e, 0, 0},{0x80e8, 0x54, 0, 0}, ++ {0x80e9, 0x8d, 0, 0},{0x80ea, 0x53, 0, 0},{0x80eb, 0x8c, 0, 0}, ++ {0x80ec, 0x52, 0, 0},{0x80ed, 0xe5, 0, 0},{0x80ee, 0x2b, 0, 0}, ++ {0x80ef, 0x25, 0, 0},{0x80f0, 0x55, 0, 0},{0x80f1, 0xf5, 0, 0}, ++ {0x80f2, 0x2b, 0, 0},{0x80f3, 0xe5, 0, 0},{0x80f4, 0x2a, 0, 0}, ++ {0x80f5, 0x35, 0, 0},{0x80f6, 0x54, 0, 0},{0x80f7, 0xf5, 0, 0}, ++ {0x80f8, 0x2a, 0, 0},{0x80f9, 0xe5, 0, 0},{0x80fa, 0x29, 0, 0}, ++ {0x80fb, 0x35, 0, 0},{0x80fc, 0x53, 0, 0},{0x80fd, 0xf5, 0, 0}, ++ {0x80fe, 0x29, 0, 0},{0x80ff, 0xe5, 0, 0},{0x8100, 0x28, 0, 0}, ++ {0x8101, 0x35, 0, 0},{0x8102, 0x52, 0, 0},{0x8103, 0xf5, 0, 0}, ++ {0x8104, 0x28, 0, 0},{0x8105, 0xae, 0, 0},{0x8106, 0x71, 0, 0}, ++ {0x8107, 0xe4, 0, 0},{0x8108, 0x85, 0, 0},{0x8109, 0x72, 0, 0}, ++ {0x810a, 0x55, 0, 0},{0x810b, 0x8e, 0, 0},{0x810c, 0x54, 0, 0}, ++ {0x810d, 0xf5, 0, 0},{0x810e, 0x53, 0, 0},{0x810f, 0xf5, 0, 0}, ++ {0x8110, 0x52, 0, 0},{0x8111, 0xab, 0, 0},{0x8112, 0x55, 0, 0}, ++ {0x8113, 0xaa, 0, 0},{0x8114, 0x54, 0, 0},{0x8115, 0xa9, 0, 0}, ++ {0x8116, 0x53, 0, 0},{0x8117, 0xa8, 0, 0},{0x8118, 0x52, 0, 0}, ++ {0x8119, 0xaf, 0, 0},{0x811a, 0x30, 0, 0},{0x811b, 0xfc, 0, 0}, ++ {0x811c, 0xfd, 0, 0},{0x811d, 0xfe, 0, 0},{0x811e, 0x12, 0, 0}, ++ {0x811f, 0x08, 0, 0},{0x8120, 0x7f, 0, 0},{0x8121, 0x8f, 0, 0}, ++ {0x8122, 0x55, 0, 0},{0x8123, 0x8e, 0, 0},{0x8124, 0x54, 0, 0}, ++ {0x8125, 0x8d, 0, 0},{0x8126, 0x53, 0, 0},{0x8127, 0x8c, 0, 0}, ++ {0x8128, 0x52, 0, 0},{0x8129, 0xe5, 0, 0},{0x812a, 0x2b, 0, 0}, ++ {0x812b, 0x25, 0, 0},{0x812c, 0x55, 0, 0},{0x812d, 0xf5, 0, 0}, ++ {0x812e, 0x2b, 0, 0},{0x812f, 0xe5, 0, 0},{0x8130, 0x2a, 0, 0}, ++ {0x8131, 0x35, 0, 0},{0x8132, 0x54, 0, 0},{0x8133, 0xf5, 0, 0}, ++ {0x8134, 0x2a, 0, 0},{0x8135, 0xe5, 0, 0},{0x8136, 0x29, 0, 0}, ++ {0x8137, 0x35, 0, 0},{0x8138, 0x53, 0, 0},{0x8139, 0xf5, 0, 0}, ++ {0x813a, 0x29, 0, 0},{0x813b, 0xe5, 0, 0},{0x813c, 0x28, 0, 0}, ++ {0x813d, 0x35, 0, 0},{0x813e, 0x52, 0, 0},{0x813f, 0xf5, 0, 0}, ++ {0x8140, 0x28, 0, 0},{0x8141, 0x22, 0, 0},{0x8142, 0xab, 0, 0}, ++ {0x8143, 0x0d, 0, 0},{0x8144, 0xaa, 0, 0},{0x8145, 0x0c, 0, 0}, ++ {0x8146, 0xa9, 0, 0},{0x8147, 0x0b, 0, 0},{0x8148, 0xa8, 0, 0}, ++ {0x8149, 0x0a, 0, 0},{0x814a, 0xfc, 0, 0},{0x814b, 0xfd, 0, 0}, ++ {0x814c, 0xfe, 0, 0},{0x814d, 0x12, 0, 0},{0x814e, 0x08, 0, 0}, ++ {0x814f, 0x7f, 0, 0},{0x8150, 0x8f, 0, 0},{0x8151, 0x0d, 0, 0}, ++ {0x8152, 0x8e, 0, 0},{0x8153, 0x0c, 0, 0},{0x8154, 0x8d, 0, 0}, ++ {0x8155, 0x0b, 0, 0},{0x8156, 0x8c, 0, 0},{0x8157, 0x0a, 0, 0}, ++ {0x8158, 0x7b, 0, 0},{0x8159, 0x40, 0, 0},{0x815a, 0xe4, 0, 0}, ++ {0x815b, 0xfa, 0, 0},{0x815c, 0xf9, 0, 0},{0x815d, 0xf8, 0, 0}, ++ {0x815e, 0x12, 0, 0},{0x815f, 0x09, 0, 0},{0x8160, 0x0a, 0, 0}, ++ {0x8161, 0x8f, 0, 0},{0x8162, 0x0d, 0, 0},{0x8163, 0x8e, 0, 0}, ++ {0x8164, 0x0c, 0, 0},{0x8165, 0x8d, 0, 0},{0x8166, 0x0b, 0, 0}, ++ {0x8167, 0x8c, 0, 0},{0x8168, 0x0a, 0, 0},{0x8169, 0x22, 0, 0}, ++ {0x816a, 0xd2, 0, 0},{0x816b, 0x29, 0, 0},{0x816c, 0x90, 0, 0}, ++ {0x816d, 0x30, 0, 0},{0x816e, 0x1b, 0, 0},{0x816f, 0xe5, 0, 0}, ++ {0x8170, 0x25, 0, 0},{0x8171, 0xf0, 0, 0},{0x8172, 0x22, 0, 0}, ++ {0x8173, 0xfe, 0, 0},{0x8174, 0xe4, 0, 0},{0x8175, 0xfc, 0, 0}, ++ {0x8176, 0xfd, 0, 0},{0x8177, 0xe5, 0, 0},{0x8178, 0x3f, 0, 0}, ++ {0x8179, 0x2f, 0, 0},{0x817a, 0xf5, 0, 0},{0x817b, 0x3f, 0, 0}, ++ {0x817c, 0xe5, 0, 0},{0x817d, 0x3e, 0, 0},{0x817e, 0x3e, 0, 0}, ++ {0x817f, 0xf5, 0, 0},{0x8180, 0x3e, 0, 0},{0x8181, 0xed, 0, 0}, ++ {0x8182, 0x35, 0, 0},{0x8183, 0x3d, 0, 0},{0x8184, 0xf5, 0, 0}, ++ {0x8185, 0x3d, 0, 0},{0x8186, 0xec, 0, 0},{0x8187, 0x35, 0, 0}, ++ {0x8188, 0x3c, 0, 0},{0x8189, 0xf5, 0, 0},{0x818a, 0x3c, 0, 0}, ++ {0x818b, 0xaf, 0, 0},{0x818c, 0x3f, 0, 0},{0x818d, 0xae, 0, 0}, ++ {0x818e, 0x3e, 0, 0},{0x818f, 0xfc, 0, 0},{0x8190, 0xad, 0, 0}, ++ {0x8191, 0x3d, 0, 0},{0x8192, 0x78, 0, 0},{0x8193, 0x08, 0, 0}, ++ {0x8194, 0x12, 0, 0},{0x8195, 0x09, 0, 0},{0x8196, 0xaf, 0, 0}, ++ {0x8197, 0x8f, 0, 0},{0x8198, 0x3f, 0, 0},{0x8199, 0x8e, 0, 0}, ++ {0x819a, 0x3e, 0, 0},{0x819b, 0x8d, 0, 0},{0x819c, 0x3d, 0, 0}, ++ {0x819d, 0x8c, 0, 0},{0x819e, 0x3c, 0, 0},{0x819f, 0x22, 0, 0}, ++ {0x81a0, 0xe5, 0, 0},{0x81a1, 0x49, 0, 0},{0x81a2, 0x25, 0, 0}, ++ {0x81a3, 0x7b, 0, 0},{0x81a4, 0xf5, 0, 0},{0x81a5, 0x82, 0, 0}, ++ {0x81a6, 0xe4, 0, 0},{0x81a7, 0x35, 0, 0},{0x81a8, 0x48, 0, 0}, ++ {0x81a9, 0xf5, 0, 0},{0x81aa, 0x83, 0, 0},{0x81ab, 0xe4, 0, 0}, ++ {0x81ac, 0x93, 0, 0},{0x81ad, 0xff, 0, 0},{0x81ae, 0x85, 0, 0}, ++ {0x81af, 0x49, 0, 0},{0x81b0, 0x82, 0, 0},{0x81b1, 0x85, 0, 0}, ++ {0x81b2, 0x48, 0, 0},{0x81b3, 0x83, 0, 0},{0x81b4, 0xe4, 0, 0}, ++ {0x81b5, 0x93, 0, 0},{0x81b6, 0xfd, 0, 0},{0x81b7, 0xc3, 0, 0}, ++ {0x81b8, 0xef, 0, 0},{0x81b9, 0x9d, 0, 0},{0x81ba, 0xff, 0, 0}, ++ {0x81bb, 0xe4, 0, 0},{0x81bc, 0x94, 0, 0},{0x81bd, 0x00, 0, 0}, ++ {0x81be, 0x22, 0, 0},{0x81bf, 0xe5, 0, 0},{0x81c0, 0x0b, 0, 0}, ++ {0x81c1, 0x24, 0, 0},{0x81c2, 0x01, 0, 0},{0x81c3, 0xff, 0, 0}, ++ {0x81c4, 0xe4, 0, 0},{0x81c5, 0x33, 0, 0},{0x81c6, 0xfe, 0, 0}, ++ {0x81c7, 0x22, 0, 0},{0x81c8, 0xaf, 0, 0},{0x81c9, 0x2b, 0, 0}, ++ {0x81ca, 0xae, 0, 0},{0x81cb, 0x2a, 0, 0},{0x81cc, 0xad, 0, 0}, ++ {0x81cd, 0x29, 0, 0},{0x81ce, 0xac, 0, 0},{0x81cf, 0x28, 0, 0}, ++ {0x81d0, 0x78, 0, 0},{0x81d1, 0x06, 0, 0},{0x81d2, 0x12, 0, 0}, ++ {0x81d3, 0x09, 0, 0},{0x81d4, 0x9c, 0, 0},{0x81d5, 0x8f, 0, 0}, ++ {0x81d6, 0x2b, 0, 0},{0x81d7, 0x8e, 0, 0},{0x81d8, 0x2a, 0, 0}, ++ {0x81d9, 0x8d, 0, 0},{0x81da, 0x29, 0, 0},{0x81db, 0x8c, 0, 0}, ++ {0x81dc, 0x28, 0, 0},{0x81dd, 0xd3, 0, 0},{0x81de, 0xe5, 0, 0}, ++ {0x81df, 0x29, 0, 0},{0x81e0, 0x94, 0, 0},{0x81e1, 0x00, 0, 0}, ++ {0x81e2, 0xe5, 0, 0},{0x81e3, 0x28, 0, 0},{0x81e4, 0x94, 0, 0}, ++ {0x81e5, 0x00, 0, 0},{0x81e6, 0x22, 0, 0},{0x81e7, 0x12, 0, 0}, ++ {0x81e8, 0x08, 0, 0},{0x81e9, 0x7f, 0, 0},{0x81ea, 0x8f, 0, 0}, ++ {0x81eb, 0x68, 0, 0},{0x81ec, 0x8e, 0, 0},{0x81ed, 0x67, 0, 0}, ++ {0x81ee, 0x8d, 0, 0},{0x81ef, 0x66, 0, 0},{0x81f0, 0x8c, 0, 0}, ++ {0x81f1, 0x65, 0, 0},{0x81f2, 0xaf, 0, 0},{0x81f3, 0x68, 0, 0}, ++ {0x81f4, 0xae, 0, 0},{0x81f5, 0x67, 0, 0},{0x81f6, 0xad, 0, 0}, ++ {0x81f7, 0x66, 0, 0},{0x81f8, 0xac, 0, 0},{0x81f9, 0x65, 0, 0}, ++ {0x81fa, 0x22, 0, 0},{0x81fb, 0xe0, 0, 0},{0x81fc, 0x44, 0, 0}, ++ {0x81fd, 0x01, 0, 0},{0x81fe, 0xf0, 0, 0},{0x81ff, 0xe0, 0, 0}, ++ {0x8200, 0x44, 0, 0},{0x8201, 0x02, 0, 0},{0x8202, 0xf0, 0, 0}, ++ {0x8203, 0xe0, 0, 0},{0x8204, 0x44, 0, 0},{0x8205, 0x04, 0, 0}, ++ {0x8206, 0xf0, 0, 0},{0x8207, 0x22, 0, 0},{0x8208, 0xd2, 0, 0}, ++ {0x8209, 0x09, 0, 0},{0x820a, 0x90, 0, 0},{0x820b, 0x30, 0, 0}, ++ {0x820c, 0x18, 0, 0},{0x820d, 0xe5, 0, 0},{0x820e, 0x21, 0, 0}, ++ {0x820f, 0xf0, 0, 0},{0x8210, 0x22, 0, 0},{0x8211, 0xe4, 0, 0}, ++ {0x8212, 0x85, 0, 0},{0x8213, 0x11, 0, 0},{0x8214, 0x0d, 0, 0}, ++ {0x8215, 0x85, 0, 0},{0x8216, 0x10, 0, 0},{0x8217, 0x0c, 0, 0}, ++ {0x8218, 0xf5, 0, 0},{0x8219, 0x0b, 0, 0},{0x821a, 0xf5, 0, 0}, ++ {0x821b, 0x0a, 0, 0},{0x821c, 0xab, 0, 0},{0x821d, 0x0d, 0, 0}, ++ {0x821e, 0xaa, 0, 0},{0x821f, 0x0c, 0, 0},{0x8220, 0xa9, 0, 0}, ++ {0x8221, 0x0b, 0, 0},{0x8222, 0xa8, 0, 0},{0x8223, 0x0a, 0, 0}, ++ {0x8224, 0x22, 0, 0},{0x8225, 0x90, 0, 0},{0x8226, 0x30, 0, 0}, ++ {0x8227, 0x42, 0, 0},{0x8228, 0xe0, 0, 0},{0x8229, 0xf5, 0, 0}, ++ {0x822a, 0x22, 0, 0},{0x822b, 0x75, 0, 0},{0x822c, 0x51, 0, 0}, ++ {0x822d, 0x0a, 0, 0},{0x822e, 0x22, 0, 0},{0x822f, 0xf5, 0, 0}, ++ {0x8230, 0x82, 0, 0},{0x8231, 0xe4, 0, 0},{0x8232, 0x3a, 0, 0}, ++ {0x8233, 0xf5, 0, 0},{0x8234, 0x83, 0, 0},{0x8235, 0x02, 0, 0}, ++ {0x8236, 0x09, 0, 0},{0x8237, 0xc2, 0, 0},{0x8238, 0x8f, 0, 0}, ++ {0x8239, 0x0a, 0, 0},{0x823a, 0x74, 0, 0},{0x823b, 0x4a, 0, 0}, ++ {0x823c, 0x2f, 0, 0},{0x823d, 0xf8, 0, 0},{0x823e, 0xe6, 0, 0}, ++ {0x823f, 0x22, 0, 0},{0x8240, 0xc2, 0, 0},{0x8241, 0x07, 0, 0}, ++ {0x8242, 0xc2, 0, 0},{0x8243, 0x06, 0, 0},{0x8244, 0xc2, 0, 0}, ++ {0x8245, 0x02, 0, 0},{0x8246, 0xc2, 0, 0},{0x8247, 0x01, 0, 0}, ++ {0x8248, 0xc2, 0, 0},{0x8249, 0x00, 0, 0},{0x824a, 0xc2, 0, 0}, ++ {0x824b, 0x03, 0, 0},{0x824c, 0xd2, 0, 0},{0x824d, 0x04, 0, 0}, ++ {0x824e, 0x22, 0, 0},{0x824f, 0xf5, 0, 0},{0x8250, 0x82, 0, 0}, ++ {0x8251, 0xe4, 0, 0},{0x8252, 0x35, 0, 0},{0x8253, 0x48, 0, 0}, ++ {0x8254, 0xf5, 0, 0},{0x8255, 0x83, 0, 0},{0x8256, 0xe4, 0, 0}, ++ {0x8257, 0x22, 0, 0},{0x8258, 0x8e, 0, 0},{0x8259, 0x67, 0, 0}, ++ {0x825a, 0x8f, 0, 0},{0x825b, 0x68, 0, 0},{0x825c, 0x85, 0, 0}, ++ {0x825d, 0x68, 0, 0},{0x825e, 0x64, 0, 0},{0x825f, 0xe5, 0, 0}, ++ {0x8260, 0x68, 0, 0},{0x8261, 0xae, 0, 0},{0x8262, 0x67, 0, 0}, ++ {0x8263, 0x78, 0, 0},{0x8264, 0x06, 0, 0},{0x8265, 0x22, 0, 0}, ++ {0x8266, 0xe5, 0, 0},{0x8267, 0x16, 0, 0},{0x8268, 0x25, 0, 0}, ++ {0x8269, 0xe0, 0, 0},{0x826a, 0x25, 0, 0},{0x826b, 0xe0, 0, 0}, ++ {0x826c, 0x22, 0, 0},{0x826d, 0x12, 0, 0},{0x826e, 0x09, 0, 0}, ++ {0x826f, 0x0a, 0, 0},{0x8270, 0x8f, 0, 0},{0x8271, 0x68, 0, 0}, ++ {0x8272, 0x8e, 0, 0},{0x8273, 0x67, 0, 0},{0x8274, 0x8d, 0, 0}, ++ {0x8275, 0x66, 0, 0},{0x8276, 0x8c, 0, 0},{0x8277, 0x65, 0, 0}, ++ {0x8278, 0x22, 0, 0},{0x8279, 0xe4, 0, 0},{0x827a, 0x85, 0, 0}, ++ {0x827b, 0x0f, 0, 0},{0x827c, 0x0d, 0, 0},{0x827d, 0x85, 0, 0}, ++ {0x827e, 0x0e, 0, 0},{0x827f, 0x0c, 0, 0},{0x8280, 0xf5, 0, 0}, ++ {0x8281, 0x0b, 0, 0},{0x8282, 0xf5, 0, 0},{0x8283, 0x0a, 0, 0}, ++ {0x8284, 0x22, 0, 0},{0x8285, 0x90, 0, 0},{0x8286, 0x11, 0, 0}, ++ {0x8287, 0xdd, 0, 0},{0x8288, 0xe4, 0, 0},{0x8289, 0x93, 0, 0}, ++ {0x828a, 0xff, 0, 0},{0x828b, 0x90, 0, 0},{0x828c, 0x30, 0, 0}, ++ {0x828d, 0x0a, 0, 0},{0x828e, 0xe0, 0, 0},{0x828f, 0x22, 0, 0}, ++ {0x8290, 0xc2, 0, 0},{0x8291, 0x02, 0, 0},{0x8292, 0xc2, 0, 0}, ++ {0x8293, 0x01, 0, 0},{0x8294, 0xd2, 0, 0},{0x8295, 0x00, 0, 0}, ++ {0x8296, 0xc2, 0, 0},{0x8297, 0x03, 0, 0},{0x8298, 0xc2, 0, 0}, ++ {0x8299, 0x04, 0, 0},{0x829a, 0x22, 0, 0},{0x829b, 0x85, 0, 0}, ++ {0x829c, 0x0e, 0, 0},{0x829d, 0x64, 0, 0},{0x829e, 0xe5, 0, 0}, ++ {0x829f, 0x0e, 0, 0},{0x82a0, 0xae, 0, 0},{0x82a1, 0x0d, 0, 0}, ++ {0x82a2, 0x78, 0, 0},{0x82a3, 0x06, 0, 0},{0x82a4, 0x22, 0, 0}, ++ {0x82a5, 0xd2, 0, 0},{0x82a6, 0x02, 0, 0},{0x82a7, 0xd2, 0, 0}, ++ {0x82a8, 0x01, 0, 0},{0x82a9, 0xc2, 0, 0},{0x82aa, 0x00, 0, 0}, ++ {0x82ab, 0x22, 0, 0},{0x82ac, 0xd3, 0, 0},{0x82ad, 0xe5, 0, 0}, ++ {0x82ae, 0x68, 0, 0},{0x82af, 0x94, 0, 0},{0x82b0, 0xff, 0, 0}, ++ {0x82b1, 0xe5, 0, 0},{0x82b2, 0x67, 0, 0},{0x82b3, 0x94, 0, 0}, ++ {0x82b4, 0x00, 0, 0},{0x82b5, 0x22, 0, 0},{0x82b6, 0x30, 0, 0}, ++ {0x82b7, 0x18, 0, 0},{0x82b8, 0x50, 0, 0},{0x82b9, 0x20, 0, 0}, ++ {0x82ba, 0x19, 0, 0},{0x82bb, 0x4d, 0, 0},{0x82bc, 0x75, 0, 0}, ++ {0x82bd, 0x0a, 0, 0},{0x82be, 0x02, 0, 0},{0x82bf, 0x74, 0, 0}, ++ {0x82c0, 0x4a, 0, 0},{0x82c1, 0x25, 0, 0},{0x82c2, 0x0a, 0, 0}, ++ {0x82c3, 0xf8, 0, 0},{0x82c4, 0xe6, 0, 0},{0x82c5, 0xff, 0, 0}, ++ {0x82c6, 0xe5, 0, 0},{0x82c7, 0x4a, 0, 0},{0x82c8, 0xd3, 0, 0}, ++ {0x82c9, 0x9f, 0, 0},{0x82ca, 0x40, 0, 0},{0x82cb, 0x04, 0, 0}, ++ {0x82cc, 0x7f, 0, 0},{0x82cd, 0x00, 0, 0},{0x82ce, 0x80, 0, 0}, ++ {0x82cf, 0x02, 0, 0},{0x82d0, 0xaf, 0, 0},{0x82d1, 0x0a, 0, 0}, ++ {0x82d2, 0x12, 0, 0},{0x82d3, 0x02, 0, 0},{0x82d4, 0x38, 0, 0}, ++ {0x82d5, 0xff, 0, 0},{0x82d6, 0xe5, 0, 0},{0x82d7, 0x4b, 0, 0}, ++ {0x82d8, 0xd3, 0, 0},{0x82d9, 0x9f, 0, 0},{0x82da, 0x40, 0, 0}, ++ {0x82db, 0x04, 0, 0},{0x82dc, 0x7f, 0, 0},{0x82dd, 0x01, 0, 0}, ++ {0x82de, 0x80, 0, 0},{0x82df, 0x02, 0, 0},{0x82e0, 0xaf, 0, 0}, ++ {0x82e1, 0x0a, 0, 0},{0x82e2, 0x12, 0, 0},{0x82e3, 0x02, 0, 0}, ++ {0x82e4, 0x38, 0, 0},{0x82e5, 0xff, 0, 0},{0x82e6, 0xe5, 0, 0}, ++ {0x82e7, 0x4d, 0, 0},{0x82e8, 0xd3, 0, 0},{0x82e9, 0x9f, 0, 0}, ++ {0x82ea, 0x40, 0, 0},{0x82eb, 0x04, 0, 0},{0x82ec, 0x7f, 0, 0}, ++ {0x82ed, 0x03, 0, 0},{0x82ee, 0x80, 0, 0},{0x82ef, 0x02, 0, 0}, ++ {0x82f0, 0xaf, 0, 0},{0x82f1, 0x0a, 0, 0},{0x82f2, 0x12, 0, 0}, ++ {0x82f3, 0x02, 0, 0},{0x82f4, 0x38, 0, 0},{0x82f5, 0xff, 0, 0}, ++ {0x82f6, 0xe5, 0, 0},{0x82f7, 0x4e, 0, 0},{0x82f8, 0xd3, 0, 0}, ++ {0x82f9, 0x9f, 0, 0},{0x82fa, 0x40, 0, 0},{0x82fb, 0x04, 0, 0}, ++ {0x82fc, 0x7f, 0, 0},{0x82fd, 0x04, 0, 0},{0x82fe, 0x80, 0, 0}, ++ {0x82ff, 0x02, 0, 0},{0x8300, 0xaf, 0, 0},{0x8301, 0x0a, 0, 0}, ++ {0x8302, 0x12, 0, 0},{0x8303, 0x02, 0, 0},{0x8304, 0x38, 0, 0}, ++ {0x8305, 0xf5, 0, 0},{0x8306, 0x0b, 0, 0},{0x8307, 0x80, 0, 0}, ++ {0x8308, 0x06, 0, 0},{0x8309, 0x85, 0, 0},{0x830a, 0x78, 0, 0}, ++ {0x830b, 0x0a, 0, 0},{0x830c, 0x85, 0, 0},{0x830d, 0x4f, 0, 0}, ++ {0x830e, 0x0b, 0, 0},{0x830f, 0x7f, 0, 0},{0x8310, 0x01, 0, 0}, ++ {0x8311, 0xe4, 0, 0},{0x8312, 0xfe, 0, 0},{0x8313, 0x74, 0, 0}, ++ {0x8314, 0x4a, 0, 0},{0x8315, 0x25, 0, 0},{0x8316, 0x0a, 0, 0}, ++ {0x8317, 0xf8, 0, 0},{0x8318, 0xe6, 0, 0},{0x8319, 0xfd, 0, 0}, ++ {0x831a, 0xe5, 0, 0},{0x831b, 0x0b, 0, 0},{0x831c, 0xc3, 0, 0}, ++ {0x831d, 0x9d, 0, 0},{0x831e, 0x50, 0, 0},{0x831f, 0x04, 0, 0}, ++ {0x8320, 0x7d, 0, 0},{0x8321, 0x01, 0, 0},{0x8322, 0x80, 0, 0}, ++ {0x8323, 0x02, 0, 0},{0x8324, 0x7d, 0, 0},{0x8325, 0xff, 0, 0}, ++ {0x8326, 0xac, 0, 0},{0x8327, 0x0b, 0, 0},{0x8328, 0xe5, 0, 0}, ++ {0x8329, 0x4e, 0, 0},{0x832a, 0xb5, 0, 0},{0x832b, 0x0b, 0, 0}, ++ {0x832c, 0x03, 0, 0},{0x832d, 0xd3, 0, 0},{0x832e, 0x80, 0, 0}, ++ {0x832f, 0x01, 0, 0},{0x8330, 0xc3, 0, 0},{0x8331, 0x92, 0, 0}, ++ {0x8332, 0x1f, 0, 0},{0x8333, 0xe5, 0, 0},{0x8334, 0x4d, 0, 0}, ++ {0x8335, 0xb5, 0, 0},{0x8336, 0x0b, 0, 0},{0x8337, 0x03, 0, 0}, ++ {0x8338, 0xd3, 0, 0},{0x8339, 0x80, 0, 0},{0x833a, 0x01, 0, 0}, ++ {0x833b, 0xc3, 0, 0},{0x833c, 0x92, 0, 0},{0x833d, 0x1e, 0, 0}, ++ {0x833e, 0xe5, 0, 0},{0x833f, 0x4c, 0, 0},{0x8340, 0xb5, 0, 0}, ++ {0x8341, 0x0b, 0, 0},{0x8342, 0x03, 0, 0},{0x8343, 0xd3, 0, 0}, ++ {0x8344, 0x80, 0, 0},{0x8345, 0x01, 0, 0},{0x8346, 0xc3, 0, 0}, ++ {0x8347, 0x92, 0, 0},{0x8348, 0x1d, 0, 0},{0x8349, 0xe5, 0, 0}, ++ {0x834a, 0x4b, 0, 0},{0x834b, 0xb5, 0, 0},{0x834c, 0x0b, 0, 0}, ++ {0x834d, 0x03, 0, 0},{0x834e, 0xd3, 0, 0},{0x834f, 0x80, 0, 0}, ++ {0x8350, 0x01, 0, 0},{0x8351, 0xc3, 0, 0},{0x8352, 0x92, 0, 0}, ++ {0x8353, 0x1c, 0, 0},{0x8354, 0xe5, 0, 0},{0x8355, 0x4a, 0, 0}, ++ {0x8356, 0xb5, 0, 0},{0x8357, 0x0b, 0, 0},{0x8358, 0x03, 0, 0}, ++ {0x8359, 0xd3, 0, 0},{0x835a, 0x80, 0, 0},{0x835b, 0x01, 0, 0}, ++ {0x835c, 0xc3, 0, 0},{0x835d, 0x92, 0, 0},{0x835e, 0x1b, 0, 0}, ++ {0x835f, 0xe5, 0, 0},{0x8360, 0x30, 0, 0},{0x8361, 0xd3, 0, 0}, ++ {0x8362, 0x94, 0, 0},{0x8363, 0x00, 0, 0},{0x8364, 0x40, 0, 0}, ++ {0x8365, 0x04, 0, 0},{0x8366, 0xa2, 0, 0},{0x8367, 0x1f, 0, 0}, ++ {0x8368, 0x80, 0, 0},{0x8369, 0x01, 0, 0},{0x836a, 0xc3, 0, 0}, ++ {0x836b, 0x92, 0, 0},{0x836c, 0x1f, 0, 0},{0x836d, 0xe5, 0, 0}, ++ {0x836e, 0x2f, 0, 0},{0x836f, 0xd3, 0, 0},{0x8370, 0x94, 0, 0}, ++ {0x8371, 0x00, 0, 0},{0x8372, 0x40, 0, 0},{0x8373, 0x04, 0, 0}, ++ {0x8374, 0xa2, 0, 0},{0x8375, 0x1e, 0, 0},{0x8376, 0x80, 0, 0}, ++ {0x8377, 0x01, 0, 0},{0x8378, 0xc3, 0, 0},{0x8379, 0x92, 0, 0}, ++ {0x837a, 0x1e, 0, 0},{0x837b, 0xe5, 0, 0},{0x837c, 0x2e, 0, 0}, ++ {0x837d, 0xd3, 0, 0},{0x837e, 0x94, 0, 0},{0x837f, 0x00, 0, 0}, ++ {0x8380, 0x40, 0, 0},{0x8381, 0x04, 0, 0},{0x8382, 0xa2, 0, 0}, ++ {0x8383, 0x1d, 0, 0},{0x8384, 0x80, 0, 0},{0x8385, 0x01, 0, 0}, ++ {0x8386, 0xc3, 0, 0},{0x8387, 0x92, 0, 0},{0x8388, 0x1d, 0, 0}, ++ {0x8389, 0xe5, 0, 0},{0x838a, 0x2d, 0, 0},{0x838b, 0xd3, 0, 0}, ++ {0x838c, 0x94, 0, 0},{0x838d, 0x00, 0, 0},{0x838e, 0x40, 0, 0}, ++ {0x838f, 0x04, 0, 0},{0x8390, 0xa2, 0, 0},{0x8391, 0x1c, 0, 0}, ++ {0x8392, 0x80, 0, 0},{0x8393, 0x01, 0, 0},{0x8394, 0xc3, 0, 0}, ++ {0x8395, 0x92, 0, 0},{0x8396, 0x1c, 0, 0},{0x8397, 0xe5, 0, 0}, ++ {0x8398, 0x2c, 0, 0},{0x8399, 0xd3, 0, 0},{0x839a, 0x94, 0, 0}, ++ {0x839b, 0x00, 0, 0},{0x839c, 0x40, 0, 0},{0x839d, 0x04, 0, 0}, ++ {0x839e, 0xa2, 0, 0},{0x839f, 0x1b, 0, 0},{0x83a0, 0x80, 0, 0}, ++ {0x83a1, 0x01, 0, 0},{0x83a2, 0xc3, 0, 0},{0x83a3, 0x92, 0, 0}, ++ {0x83a4, 0x1b, 0, 0},{0x83a5, 0xe5, 0, 0},{0x83a6, 0x23, 0, 0}, ++ {0x83a7, 0x54, 0, 0},{0x83a8, 0xf8, 0, 0},{0x83a9, 0x70, 0, 0}, ++ {0x83aa, 0x43, 0, 0},{0x83ab, 0xbf, 0, 0},{0x83ac, 0x01, 0, 0}, ++ {0x83ad, 0x08, 0, 0},{0x83ae, 0xed, 0, 0},{0x83af, 0xf4, 0, 0}, ++ {0x83b0, 0x04, 0, 0},{0x83b1, 0xfd, 0, 0},{0x83b2, 0x7f, 0, 0}, ++ {0x83b3, 0x02, 0, 0},{0x83b4, 0x80, 0, 0},{0x83b5, 0x06, 0, 0}, ++ {0x83b6, 0xbf, 0, 0},{0x83b7, 0x02, 0, 0},{0x83b8, 0x02, 0, 0}, ++ {0x83b9, 0x7f, 0, 0},{0x83ba, 0x01, 0, 0},{0x83bb, 0x0e, 0, 0}, ++ {0x83bc, 0xd3, 0, 0},{0x83bd, 0xed, 0, 0},{0x83be, 0x64, 0, 0}, ++ {0x83bf, 0x80, 0, 0},{0x83c0, 0x94, 0, 0},{0x83c1, 0x80, 0, 0}, ++ {0x83c2, 0x40, 0, 0},{0x83c3, 0x12, 0, 0},{0x83c4, 0xec, 0, 0}, ++ {0x83c5, 0x2e, 0, 0},{0x83c6, 0xf5, 0, 0},{0x83c7, 0x0b, 0, 0}, ++ {0x83c8, 0xc3, 0, 0},{0x83c9, 0x95, 0, 0},{0x83ca, 0x7b, 0, 0}, ++ {0x83cb, 0x50, 0, 0},{0x83cc, 0x03, 0, 0},{0x83cd, 0x02, 0, 0}, ++ {0x83ce, 0x03, 0, 0},{0x83cf, 0x28, 0, 0},{0x83d0, 0x7d, 0, 0}, ++ {0x83d1, 0xff, 0, 0},{0x83d2, 0xe4, 0, 0},{0x83d3, 0xff, 0, 0}, ++ {0x83d4, 0x80, 0, 0},{0x83d5, 0x11, 0, 0},{0x83d6, 0xec, 0, 0}, ++ {0x83d7, 0xd3, 0, 0},{0x83d8, 0x9e, 0, 0},{0x83d9, 0x50, 0, 0}, ++ {0x83da, 0x0b, 0, 0},{0x83db, 0x7d, 0, 0},{0x83dc, 0x01, 0, 0}, ++ {0x83dd, 0xe4, 0, 0},{0x83de, 0xff, 0, 0},{0x83df, 0xec, 0, 0}, ++ {0x83e0, 0x2e, 0, 0},{0x83e1, 0xf5, 0, 0},{0x83e2, 0x0b, 0, 0}, ++ {0x83e3, 0x02, 0, 0},{0x83e4, 0x03, 0, 0},{0x83e5, 0x28, 0, 0}, ++ {0x83e6, 0xc3, 0, 0},{0x83e7, 0xec, 0, 0},{0x83e8, 0x9e, 0, 0}, ++ {0x83e9, 0xf5, 0, 0},{0x83ea, 0x0b, 0, 0},{0x83eb, 0x02, 0, 0}, ++ {0x83ec, 0x03, 0, 0},{0x83ed, 0x28, 0, 0},{0x83ee, 0x12, 0, 0}, ++ {0x83ef, 0x01, 0, 0},{0x83f0, 0xbf, 0, 0},{0x83f1, 0xe5, 0, 0}, ++ {0x83f2, 0x4e, 0, 0},{0x83f3, 0xb5, 0, 0},{0x83f4, 0x07, 0, 0}, ++ {0x83f5, 0x07, 0, 0},{0x83f6, 0xe4, 0, 0},{0x83f7, 0xb5, 0, 0}, ++ {0x83f8, 0x06, 0, 0},{0x83f9, 0x03, 0, 0},{0x83fa, 0xd3, 0, 0}, ++ {0x83fb, 0x80, 0, 0},{0x83fc, 0x02, 0, 0},{0x83fd, 0xa2, 0, 0}, ++ {0x83fe, 0x1f, 0, 0},{0x83ff, 0x92, 0, 0},{0x8400, 0x1f, 0, 0}, ++ {0x8401, 0xe5, 0, 0},{0x8402, 0x4d, 0, 0},{0x8403, 0xb5, 0, 0}, ++ {0x8404, 0x07, 0, 0},{0x8405, 0x07, 0, 0},{0x8406, 0xe4, 0, 0}, ++ {0x8407, 0xb5, 0, 0},{0x8408, 0x06, 0, 0},{0x8409, 0x03, 0, 0}, ++ {0x840a, 0xd3, 0, 0},{0x840b, 0x80, 0, 0},{0x840c, 0x02, 0, 0}, ++ {0x840d, 0xa2, 0, 0},{0x840e, 0x1e, 0, 0},{0x840f, 0x92, 0, 0}, ++ {0x8410, 0x1e, 0, 0},{0x8411, 0x12, 0, 0},{0x8412, 0x01, 0, 0}, ++ {0x8413, 0xbf, 0, 0},{0x8414, 0xe5, 0, 0},{0x8415, 0x4c, 0, 0}, ++ {0x8416, 0xb5, 0, 0},{0x8417, 0x07, 0, 0},{0x8418, 0x07, 0, 0}, ++ {0x8419, 0xe4, 0, 0},{0x841a, 0xb5, 0, 0},{0x841b, 0x06, 0, 0}, ++ {0x841c, 0x03, 0, 0},{0x841d, 0xd3, 0, 0},{0x841e, 0x80, 0, 0}, ++ {0x841f, 0x02, 0, 0},{0x8420, 0xa2, 0, 0},{0x8421, 0x1d, 0, 0}, ++ {0x8422, 0x92, 0, 0},{0x8423, 0x1d, 0, 0},{0x8424, 0xe5, 0, 0}, ++ {0x8425, 0x4b, 0, 0},{0x8426, 0xb5, 0, 0},{0x8427, 0x07, 0, 0}, ++ {0x8428, 0x07, 0, 0},{0x8429, 0xe4, 0, 0},{0x842a, 0xb5, 0, 0}, ++ {0x842b, 0x06, 0, 0},{0x842c, 0x03, 0, 0},{0x842d, 0xd3, 0, 0}, ++ {0x842e, 0x80, 0, 0},{0x842f, 0x02, 0, 0},{0x8430, 0xa2, 0, 0}, ++ {0x8431, 0x1c, 0, 0},{0x8432, 0x92, 0, 0},{0x8433, 0x1c, 0, 0}, ++ {0x8434, 0x12, 0, 0},{0x8435, 0x01, 0, 0},{0x8436, 0xbf, 0, 0}, ++ {0x8437, 0xe5, 0, 0},{0x8438, 0x4a, 0, 0},{0x8439, 0xb5, 0, 0}, ++ {0x843a, 0x07, 0, 0},{0x843b, 0x07, 0, 0},{0x843c, 0xe4, 0, 0}, ++ {0x843d, 0xb5, 0, 0},{0x843e, 0x06, 0, 0},{0x843f, 0x03, 0, 0}, ++ {0x8440, 0xd3, 0, 0},{0x8441, 0x80, 0, 0},{0x8442, 0x02, 0, 0}, ++ {0x8443, 0xa2, 0, 0},{0x8444, 0x1b, 0, 0},{0x8445, 0x92, 0, 0}, ++ {0x8446, 0x1b, 0, 0},{0x8447, 0xe5, 0, 0},{0x8448, 0x4e, 0, 0}, ++ {0x8449, 0x12, 0, 0},{0x844a, 0x01, 0, 0},{0x844b, 0xc1, 0, 0}, ++ {0x844c, 0xad, 0, 0},{0x844d, 0x0b, 0, 0},{0x844e, 0x7c, 0, 0}, ++ {0x844f, 0x00, 0, 0},{0x8450, 0xef, 0, 0},{0x8451, 0xb5, 0, 0}, ++ {0x8452, 0x05, 0, 0},{0x8453, 0x07, 0, 0},{0x8454, 0xec, 0, 0}, ++ {0x8455, 0xb5, 0, 0},{0x8456, 0x06, 0, 0},{0x8457, 0x03, 0, 0}, ++ {0x8458, 0xd3, 0, 0},{0x8459, 0x80, 0, 0},{0x845a, 0x02, 0, 0}, ++ {0x845b, 0xa2, 0, 0},{0x845c, 0x1f, 0, 0},{0x845d, 0x92, 0, 0}, ++ {0x845e, 0x1f, 0, 0},{0x845f, 0xe5, 0, 0},{0x8460, 0x4d, 0, 0}, ++ {0x8461, 0x12, 0, 0},{0x8462, 0x01, 0, 0},{0x8463, 0xc1, 0, 0}, ++ {0x8464, 0xef, 0, 0},{0x8465, 0xb5, 0, 0},{0x8466, 0x05, 0, 0}, ++ {0x8467, 0x07, 0, 0},{0x8468, 0xee, 0, 0},{0x8469, 0xb5, 0, 0}, ++ {0x846a, 0x04, 0, 0},{0x846b, 0x03, 0, 0},{0x846c, 0xd3, 0, 0}, ++ {0x846d, 0x80, 0, 0},{0x846e, 0x02, 0, 0},{0x846f, 0xa2, 0, 0}, ++ {0x8470, 0x1e, 0, 0},{0x8471, 0x92, 0, 0},{0x8472, 0x1e, 0, 0}, ++ {0x8473, 0xe5, 0, 0},{0x8474, 0x4c, 0, 0},{0x8475, 0x12, 0, 0}, ++ {0x8476, 0x01, 0, 0},{0x8477, 0xc1, 0, 0},{0x8478, 0xad, 0, 0}, ++ {0x8479, 0x0b, 0, 0},{0x847a, 0x7c, 0, 0},{0x847b, 0x00, 0, 0}, ++ {0x847c, 0xef, 0, 0},{0x847d, 0xb5, 0, 0},{0x847e, 0x05, 0, 0}, ++ {0x847f, 0x07, 0, 0},{0x8480, 0xec, 0, 0},{0x8481, 0xb5, 0, 0}, ++ {0x8482, 0x06, 0, 0},{0x8483, 0x03, 0, 0},{0x8484, 0xd3, 0, 0}, ++ {0x8485, 0x80, 0, 0},{0x8486, 0x02, 0, 0},{0x8487, 0xa2, 0, 0}, ++ {0x8488, 0x1d, 0, 0},{0x8489, 0x92, 0, 0},{0x848a, 0x1d, 0, 0}, ++ {0x848b, 0xe5, 0, 0},{0x848c, 0x4b, 0, 0},{0x848d, 0x12, 0, 0}, ++ {0x848e, 0x01, 0, 0},{0x848f, 0xc1, 0, 0},{0x8490, 0xef, 0, 0}, ++ {0x8491, 0xb5, 0, 0},{0x8492, 0x05, 0, 0},{0x8493, 0x07, 0, 0}, ++ {0x8494, 0xee, 0, 0},{0x8495, 0xb5, 0, 0},{0x8496, 0x04, 0, 0}, ++ {0x8497, 0x03, 0, 0},{0x8498, 0xd3, 0, 0},{0x8499, 0x80, 0, 0}, ++ {0x849a, 0x02, 0, 0},{0x849b, 0xa2, 0, 0},{0x849c, 0x1c, 0, 0}, ++ {0x849d, 0x92, 0, 0},{0x849e, 0x1c, 0, 0},{0x849f, 0xe5, 0, 0}, ++ {0x84a0, 0x4a, 0, 0},{0x84a1, 0x12, 0, 0},{0x84a2, 0x01, 0, 0}, ++ {0x84a3, 0xc1, 0, 0},{0x84a4, 0x7c, 0, 0},{0x84a5, 0x00, 0, 0}, ++ {0x84a6, 0xef, 0, 0},{0x84a7, 0xb5, 0, 0},{0x84a8, 0x0b, 0, 0}, ++ {0x84a9, 0x07, 0, 0},{0x84aa, 0xec, 0, 0},{0x84ab, 0xb5, 0, 0}, ++ {0x84ac, 0x06, 0, 0},{0x84ad, 0x03, 0, 0},{0x84ae, 0xd3, 0, 0}, ++ {0x84af, 0x80, 0, 0},{0x84b0, 0x02, 0, 0},{0x84b1, 0xa2, 0, 0}, ++ {0x84b2, 0x1b, 0, 0},{0x84b3, 0x92, 0, 0},{0x84b4, 0x1b, 0, 0}, ++ {0x84b5, 0xe5, 0, 0},{0x84b6, 0x30, 0, 0},{0x84b7, 0xd3, 0, 0}, ++ {0x84b8, 0x94, 0, 0},{0x84b9, 0x00, 0, 0},{0x84ba, 0x40, 0, 0}, ++ {0x84bb, 0x04, 0, 0},{0x84bc, 0xa2, 0, 0},{0x84bd, 0x1f, 0, 0}, ++ {0x84be, 0x80, 0, 0},{0x84bf, 0x01, 0, 0},{0x84c0, 0xc3, 0, 0}, ++ {0x84c1, 0x92, 0, 0},{0x84c2, 0x1f, 0, 0},{0x84c3, 0xe5, 0, 0}, ++ {0x84c4, 0x2f, 0, 0},{0x84c5, 0xd3, 0, 0},{0x84c6, 0x94, 0, 0}, ++ {0x84c7, 0x00, 0, 0},{0x84c8, 0x40, 0, 0},{0x84c9, 0x04, 0, 0}, ++ {0x84ca, 0xa2, 0, 0},{0x84cb, 0x1e, 0, 0},{0x84cc, 0x80, 0, 0}, ++ {0x84cd, 0x01, 0, 0},{0x84ce, 0xc3, 0, 0},{0x84cf, 0x92, 0, 0}, ++ {0x84d0, 0x1e, 0, 0},{0x84d1, 0xe5, 0, 0},{0x84d2, 0x2e, 0, 0}, ++ {0x84d3, 0xd3, 0, 0},{0x84d4, 0x94, 0, 0},{0x84d5, 0x00, 0, 0}, ++ {0x84d6, 0x40, 0, 0},{0x84d7, 0x04, 0, 0},{0x84d8, 0xa2, 0, 0}, ++ {0x84d9, 0x1d, 0, 0},{0x84da, 0x80, 0, 0},{0x84db, 0x01, 0, 0}, ++ {0x84dc, 0xc3, 0, 0},{0x84dd, 0x92, 0, 0},{0x84de, 0x1d, 0, 0}, ++ {0x84df, 0xe5, 0, 0},{0x84e0, 0x2d, 0, 0},{0x84e1, 0xd3, 0, 0}, ++ {0x84e2, 0x94, 0, 0},{0x84e3, 0x00, 0, 0},{0x84e4, 0x40, 0, 0}, ++ {0x84e5, 0x04, 0, 0},{0x84e6, 0xa2, 0, 0},{0x84e7, 0x1c, 0, 0}, ++ {0x84e8, 0x80, 0, 0},{0x84e9, 0x01, 0, 0},{0x84ea, 0xc3, 0, 0}, ++ {0x84eb, 0x92, 0, 0},{0x84ec, 0x1c, 0, 0},{0x84ed, 0xe5, 0, 0}, ++ {0x84ee, 0x2c, 0, 0},{0x84ef, 0xd3, 0, 0},{0x84f0, 0x94, 0, 0}, ++ {0x84f1, 0x00, 0, 0},{0x84f2, 0x40, 0, 0},{0x84f3, 0x04, 0, 0}, ++ {0x84f4, 0xa2, 0, 0},{0x84f5, 0x1b, 0, 0},{0x84f6, 0x80, 0, 0}, ++ {0x84f7, 0x01, 0, 0},{0x84f8, 0xc3, 0, 0},{0x84f9, 0x92, 0, 0}, ++ {0x84fa, 0x1b, 0, 0},{0x84fb, 0x85, 0, 0},{0x84fc, 0x0a, 0, 0}, ++ {0x84fd, 0x78, 0, 0},{0x84fe, 0xe5, 0, 0},{0x84ff, 0x7c, 0, 0}, ++ {0x8500, 0xb5, 0, 0},{0x8501, 0x0b, 0, 0},{0x8502, 0x03, 0, 0}, ++ {0x8503, 0x02, 0, 0},{0x8504, 0x15, 0, 0},{0x8505, 0x18, 0, 0}, ++ {0x8506, 0x85, 0, 0},{0x8507, 0x0b, 0, 0},{0x8508, 0x0c, 0, 0}, ++ {0x8509, 0x12, 0, 0},{0x850a, 0x0f, 0, 0},{0x850b, 0x11, 0, 0}, ++ {0x850c, 0xd2, 0, 0},{0x850d, 0x02, 0, 0},{0x850e, 0xc2, 0, 0}, ++ {0x850f, 0x01, 0, 0},{0x8510, 0xd2, 0, 0},{0x8511, 0x00, 0, 0}, ++ {0x8512, 0x75, 0, 0},{0x8513, 0x31, 0, 0},{0x8514, 0x03, 0, 0}, ++ {0x8515, 0x22, 0, 0},{0x8516, 0xe5, 0, 0},{0x8517, 0x7d, 0, 0}, ++ {0x8518, 0x24, 0, 0},{0x8519, 0xfe, 0, 0},{0x851a, 0x60, 0, 0}, ++ {0x851b, 0x27, 0, 0},{0x851c, 0x14, 0, 0},{0x851d, 0x60, 0, 0}, ++ {0x851e, 0x31, 0, 0},{0x851f, 0x24, 0, 0},{0x8520, 0xf8, 0, 0}, ++ {0x8521, 0x60, 0, 0},{0x8522, 0x3a, 0, 0},{0x8523, 0x14, 0, 0}, ++ {0x8524, 0x60, 0, 0},{0x8525, 0x4b, 0, 0},{0x8526, 0x14, 0, 0}, ++ {0x8527, 0x60, 0, 0},{0x8528, 0x59, 0, 0},{0x8529, 0x14, 0, 0}, ++ {0x852a, 0x60, 0, 0},{0x852b, 0x6a, 0, 0},{0x852c, 0x24, 0, 0}, ++ {0x852d, 0xfd, 0, 0},{0x852e, 0x70, 0, 0},{0x852f, 0x03, 0, 0}, ++ {0x8530, 0x02, 0, 0},{0x8531, 0x05, 0, 0},{0x8532, 0xcb, 0, 0}, ++ {0x8533, 0x24, 0, 0},{0x8534, 0x10, 0, 0},{0x8535, 0x60, 0, 0}, ++ {0x8536, 0x03, 0, 0},{0x8537, 0x02, 0, 0},{0x8538, 0x06, 0, 0}, ++ {0x8539, 0xc6, 0, 0},{0x853a, 0xe4, 0, 0},{0x853b, 0xf5, 0, 0}, ++ {0x853c, 0x0a, 0, 0},{0x853d, 0x12, 0, 0},{0x853e, 0x10, 0, 0}, ++ {0x853f, 0xb5, 0, 0},{0x8540, 0x02, 0, 0},{0x8541, 0x06, 0, 0}, ++ {0x8542, 0xaf, 0, 0},{0x8543, 0x75, 0, 0},{0x8544, 0x0a, 0, 0}, ++ {0x8545, 0x01, 0, 0},{0x8546, 0x12, 0, 0},{0x8547, 0x06, 0, 0}, ++ {0x8548, 0xc7, 0, 0},{0x8549, 0xc2, 0, 0},{0x854a, 0x3a, 0, 0}, ++ {0x854b, 0xd2, 0, 0},{0x854c, 0x39, 0, 0},{0x854d, 0x02, 0, 0}, ++ {0x854e, 0x06, 0, 0},{0x854f, 0xc0, 0, 0},{0x8550, 0x75, 0, 0}, ++ {0x8551, 0x0a, 0, 0},{0x8552, 0x02, 0, 0},{0x8553, 0x12, 0, 0}, ++ {0x8554, 0x06, 0, 0},{0x8555, 0xc7, 0, 0},{0x8556, 0xd2, 0, 0}, ++ {0x8557, 0x3a, 0, 0},{0x8558, 0xc2, 0, 0},{0x8559, 0x39, 0, 0}, ++ {0x855a, 0x02, 0, 0},{0x855b, 0x06, 0, 0},{0x855c, 0xc0, 0, 0}, ++ {0x855d, 0x30, 0, 0},{0x855e, 0x36, 0, 0},{0x855f, 0x0c, 0, 0}, ++ {0x8560, 0x20, 0, 0},{0x8561, 0x3a, 0, 0},{0x8562, 0x03, 0, 0}, ++ {0x8563, 0x30, 0, 0},{0x8564, 0x39, 0, 0},{0x8565, 0x06, 0, 0}, ++ {0x8566, 0xe4, 0, 0},{0x8567, 0xf5, 0, 0},{0x8568, 0x0a, 0, 0}, ++ {0x8569, 0x12, 0, 0},{0x856a, 0x12, 0, 0},{0x856b, 0x92, 0, 0}, ++ {0x856c, 0xd2, 0, 0},{0x856d, 0x18, 0, 0},{0x856e, 0xc2, 0, 0}, ++ {0x856f, 0x19, 0, 0},{0x8570, 0x22, 0, 0},{0x8571, 0x30, 0, 0}, ++ {0x8572, 0x36, 0, 0},{0x8573, 0x09, 0, 0},{0x8574, 0x20, 0, 0}, ++ {0x8575, 0x3a, 0, 0},{0x8576, 0x03, 0, 0},{0x8577, 0x30, 0, 0}, ++ {0x8578, 0x39, 0, 0},{0x8579, 0x03, 0, 0},{0x857a, 0x12, 0, 0}, ++ {0x857b, 0x06, 0, 0},{0x857c, 0xd8, 0, 0},{0x857d, 0xd2, 0, 0}, ++ {0x857e, 0x18, 0, 0},{0x857f, 0xd2, 0, 0},{0x8580, 0x19, 0, 0}, ++ {0x8581, 0x22, 0, 0},{0x8582, 0x30, 0, 0},{0x8583, 0x36, 0, 0}, ++ {0x8584, 0x0c, 0, 0},{0x8585, 0x20, 0, 0},{0x8586, 0x3a, 0, 0}, ++ {0x8587, 0x03, 0, 0},{0x8588, 0x30, 0, 0},{0x8589, 0x39, 0, 0}, ++ {0x858a, 0x06, 0, 0},{0x858b, 0x75, 0, 0},{0x858c, 0x0a, 0, 0}, ++ {0x858d, 0x02, 0, 0},{0x858e, 0x12, 0, 0},{0x858f, 0x12, 0, 0}, ++ {0x8590, 0x92, 0, 0},{0x8591, 0xc2, 0, 0},{0x8592, 0x18, 0, 0}, ++ {0x8593, 0xd2, 0, 0},{0x8594, 0x19, 0, 0},{0x8595, 0x22, 0, 0}, ++ {0x8596, 0x20, 0, 0},{0x8597, 0x3a, 0, 0},{0x8598, 0x06, 0, 0}, ++ {0x8599, 0x20, 0, 0},{0x859a, 0x39, 0, 0},{0x859b, 0x03, 0, 0}, ++ {0x859c, 0x02, 0, 0},{0x859d, 0x06, 0, 0},{0x859e, 0xc6, 0, 0}, ++ {0x859f, 0xe5, 0, 0},{0x85a0, 0x78, 0, 0},{0x85a1, 0xd3, 0, 0}, ++ {0x85a2, 0x94, 0, 0},{0x85a3, 0x03, 0, 0},{0x85a4, 0x40, 0, 0}, ++ {0x85a5, 0x04, 0, 0},{0x85a6, 0x7f, 0, 0},{0x85a7, 0x00, 0, 0}, ++ {0x85a8, 0x80, 0, 0},{0x85a9, 0x04, 0, 0},{0x85aa, 0xe5, 0, 0}, ++ {0x85ab, 0x78, 0, 0},{0x85ac, 0x04, 0, 0},{0x85ad, 0xff, 0, 0}, ++ {0x85ae, 0x8f, 0, 0},{0x85af, 0x78, 0, 0},{0x85b0, 0x30, 0, 0}, ++ {0x85b1, 0x18, 0, 0},{0x85b2, 0x06, 0, 0},{0x85b3, 0x30, 0, 0}, ++ {0x85b4, 0x19, 0, 0},{0x85b5, 0x03, 0, 0},{0x85b6, 0x12, 0, 0}, ++ {0x85b7, 0x06, 0, 0},{0x85b8, 0xd8, 0, 0},{0x85b9, 0x30, 0, 0}, ++ {0x85ba, 0x18, 0, 0},{0x85bb, 0x03, 0, 0},{0x85bc, 0x02, 0, 0}, ++ {0x85bd, 0x06, 0, 0},{0x85be, 0xc6, 0, 0},{0x85bf, 0x20, 0, 0}, ++ {0x85c0, 0x19, 0, 0},{0x85c1, 0x03, 0, 0},{0x85c2, 0x02, 0, 0}, ++ {0x85c3, 0x06, 0, 0},{0x85c4, 0xc6, 0, 0},{0x85c5, 0x75, 0, 0}, ++ {0x85c6, 0x0a, 0, 0},{0x85c7, 0x02, 0, 0},{0x85c8, 0x02, 0, 0}, ++ {0x85c9, 0x12, 0, 0},{0x85ca, 0x92, 0, 0},{0x85cb, 0xe5, 0, 0}, ++ {0x85cc, 0x67, 0, 0},{0x85cd, 0xd3, 0, 0},{0x85ce, 0x94, 0, 0}, ++ {0x85cf, 0x38, 0, 0},{0x85d0, 0x40, 0, 0},{0x85d1, 0x04, 0, 0}, ++ {0x85d2, 0x7f, 0, 0},{0x85d3, 0x34, 0, 0},{0x85d4, 0x80, 0, 0}, ++ {0x85d5, 0x02, 0, 0},{0x85d6, 0xaf, 0, 0},{0x85d7, 0x67, 0, 0}, ++ {0x85d8, 0x8f, 0, 0},{0x85d9, 0x67, 0, 0},{0x85da, 0xe5, 0, 0}, ++ {0x85db, 0x67, 0, 0},{0x85dc, 0xc3, 0, 0},{0x85dd, 0x94, 0, 0}, ++ {0x85de, 0x08, 0, 0},{0x85df, 0x50, 0, 0},{0x85e0, 0x04, 0, 0}, ++ {0x85e1, 0x7f, 0, 0},{0x85e2, 0x08, 0, 0},{0x85e3, 0x80, 0, 0}, ++ {0x85e4, 0x02, 0, 0},{0x85e5, 0xaf, 0, 0},{0x85e6, 0x67, 0, 0}, ++ {0x85e7, 0x8f, 0, 0},{0x85e8, 0x67, 0, 0},{0x85e9, 0xe5, 0, 0}, ++ {0x85ea, 0x68, 0, 0},{0x85eb, 0xd3, 0, 0},{0x85ec, 0x94, 0, 0}, ++ {0x85ed, 0x2a, 0, 0},{0x85ee, 0x40, 0, 0},{0x85ef, 0x04, 0, 0}, ++ {0x85f0, 0x7f, 0, 0},{0x85f1, 0x2a, 0, 0},{0x85f2, 0x80, 0, 0}, ++ {0x85f3, 0x02, 0, 0},{0x85f4, 0xaf, 0, 0},{0x85f5, 0x68, 0, 0}, ++ {0x85f6, 0x8f, 0, 0},{0x85f7, 0x68, 0, 0},{0x85f8, 0xe5, 0, 0}, ++ {0x85f9, 0x68, 0, 0},{0x85fa, 0xc3, 0, 0},{0x85fb, 0x94, 0, 0}, ++ {0x85fc, 0x06, 0, 0},{0x85fd, 0x50, 0, 0},{0x85fe, 0x04, 0, 0}, ++ {0x85ff, 0x7f, 0, 0},{0x8600, 0x06, 0, 0},{0x8601, 0x80, 0, 0}, ++ {0x8602, 0x02, 0, 0},{0x8603, 0xaf, 0, 0},{0x8604, 0x68, 0, 0}, ++ {0x8605, 0x8f, 0, 0},{0x8606, 0x68, 0, 0},{0x8607, 0xaf, 0, 0}, ++ {0x8608, 0x67, 0, 0},{0x8609, 0xef, 0, 0},{0x860a, 0x24, 0, 0}, ++ {0x860b, 0xf8, 0, 0},{0x860c, 0xff, 0, 0},{0x860d, 0xe4, 0, 0}, ++ {0x860e, 0x34, 0, 0},{0x860f, 0xff, 0, 0},{0x8610, 0xfe, 0, 0}, ++ {0x8611, 0xe4, 0, 0},{0x8612, 0x8f, 0, 0},{0x8613, 0x3f, 0, 0}, ++ {0x8614, 0x8e, 0, 0},{0x8615, 0x3e, 0, 0},{0x8616, 0xf5, 0, 0}, ++ {0x8617, 0x3d, 0, 0},{0x8618, 0xf5, 0, 0},{0x8619, 0x3c, 0, 0}, ++ {0x861a, 0xac, 0, 0},{0x861b, 0x3c, 0, 0},{0x861c, 0x12, 0, 0}, ++ {0x861d, 0x01, 0, 0},{0x861e, 0x90, 0, 0},{0x861f, 0xaf, 0, 0}, ++ {0x8620, 0x68, 0, 0},{0x8621, 0xef, 0, 0},{0x8622, 0x24, 0, 0}, ++ {0x8623, 0xfa, 0, 0},{0x8624, 0xff, 0, 0},{0x8625, 0xe4, 0, 0}, ++ {0x8626, 0x34, 0, 0},{0x8627, 0xff, 0, 0},{0x8628, 0x12, 0, 0}, ++ {0x8629, 0x01, 0, 0},{0x862a, 0x73, 0, 0},{0x862b, 0xaf, 0, 0}, ++ {0x862c, 0x67, 0, 0},{0x862d, 0xef, 0, 0},{0x862e, 0x24, 0, 0}, ++ {0x862f, 0x08, 0, 0},{0x8630, 0xff, 0, 0},{0x8631, 0xe4, 0, 0}, ++ {0x8632, 0x33, 0, 0},{0x8633, 0x12, 0, 0},{0x8634, 0x01, 0, 0}, ++ {0x8635, 0x73, 0, 0},{0x8636, 0xaf, 0, 0},{0x8637, 0x68, 0, 0}, ++ {0x8638, 0xef, 0, 0},{0x8639, 0x24, 0, 0},{0x863a, 0x06, 0, 0}, ++ {0x863b, 0xff, 0, 0},{0x863c, 0xe4, 0, 0},{0x863d, 0x33, 0, 0}, ++ {0x863e, 0xfe, 0, 0},{0x863f, 0xe4, 0, 0},{0x8640, 0xfc, 0, 0}, ++ {0x8641, 0xfd, 0, 0},{0x8642, 0xe5, 0, 0},{0x8643, 0x3f, 0, 0}, ++ {0x8644, 0x2f, 0, 0},{0x8645, 0xf5, 0, 0},{0x8646, 0x3f, 0, 0}, ++ {0x8647, 0xe5, 0, 0},{0x8648, 0x3e, 0, 0},{0x8649, 0x3e, 0, 0}, ++ {0x864a, 0xf5, 0, 0},{0x864b, 0x3e, 0, 0},{0x864c, 0xed, 0, 0}, ++ {0x864d, 0x35, 0, 0},{0x864e, 0x3d, 0, 0},{0x864f, 0xf5, 0, 0}, ++ {0x8650, 0x3d, 0, 0},{0x8651, 0xec, 0, 0},{0x8652, 0x35, 0, 0}, ++ {0x8653, 0x3c, 0, 0},{0x8654, 0xf5, 0, 0},{0x8655, 0x3c, 0, 0}, ++ {0x8656, 0xe4, 0, 0},{0x8657, 0x25, 0, 0},{0x8658, 0x3f, 0, 0}, ++ {0x8659, 0xf5, 0, 0},{0x865a, 0x37, 0, 0},{0x865b, 0xe4, 0, 0}, ++ {0x865c, 0x35, 0, 0},{0x865d, 0x3e, 0, 0},{0x865e, 0xf5, 0, 0}, ++ {0x865f, 0x36, 0, 0},{0x8660, 0xe4, 0, 0},{0x8661, 0x35, 0, 0}, ++ {0x8662, 0x3d, 0, 0},{0x8663, 0xf5, 0, 0},{0x8664, 0x35, 0, 0}, ++ {0x8665, 0xe5, 0, 0},{0x8666, 0x3c, 0, 0},{0x8667, 0x34, 0, 0}, ++ {0x8668, 0x08, 0, 0},{0x8669, 0xf5, 0, 0},{0x866a, 0x34, 0, 0}, ++ {0x866b, 0xe4, 0, 0},{0x866c, 0x25, 0, 0},{0x866d, 0x3f, 0, 0}, ++ {0x866e, 0xf5, 0, 0},{0x866f, 0x3b, 0, 0},{0x8670, 0xe4, 0, 0}, ++ {0x8671, 0x35, 0, 0},{0x8672, 0x3e, 0, 0},{0x8673, 0xf5, 0, 0}, ++ {0x8674, 0x3a, 0, 0},{0x8675, 0xe5, 0, 0},{0x8676, 0x3d, 0, 0}, ++ {0x8677, 0x34, 0, 0},{0x8678, 0x06, 0, 0},{0x8679, 0xf5, 0, 0}, ++ {0x867a, 0x39, 0, 0},{0x867b, 0xe4, 0, 0},{0x867c, 0x35, 0, 0}, ++ {0x867d, 0x3c, 0, 0},{0x867e, 0xf5, 0, 0},{0x867f, 0x38, 0, 0}, ++ {0x8680, 0xe5, 0, 0},{0x8681, 0x3f, 0, 0},{0x8682, 0x24, 0, 0}, ++ {0x8683, 0xfa, 0, 0},{0x8684, 0xf5, 0, 0},{0x8685, 0x43, 0, 0}, ++ {0x8686, 0xe5, 0, 0},{0x8687, 0x3e, 0, 0},{0x8688, 0x34, 0, 0}, ++ {0x8689, 0xff, 0, 0},{0x868a, 0xf5, 0, 0},{0x868b, 0x42, 0, 0}, ++ {0x868c, 0xe5, 0, 0},{0x868d, 0x3d, 0, 0},{0x868e, 0x34, 0, 0}, ++ {0x868f, 0xff, 0, 0},{0x8690, 0xf5, 0, 0},{0x8691, 0x41, 0, 0}, ++ {0x8692, 0xe5, 0, 0},{0x8693, 0x3c, 0, 0},{0x8694, 0x34, 0, 0}, ++ {0x8695, 0xff, 0, 0},{0x8696, 0xf5, 0, 0},{0x8697, 0x40, 0, 0}, ++ {0x8698, 0xe4, 0, 0},{0x8699, 0x25, 0, 0},{0x869a, 0x3f, 0, 0}, ++ {0x869b, 0xf5, 0, 0},{0x869c, 0x47, 0, 0},{0x869d, 0xe5, 0, 0}, ++ {0x869e, 0x3e, 0, 0},{0x869f, 0x34, 0, 0},{0x86a0, 0xf8, 0, 0}, ++ {0x86a1, 0xf5, 0, 0},{0x86a2, 0x46, 0, 0},{0x86a3, 0xe5, 0, 0}, ++ {0x86a4, 0x3d, 0, 0},{0x86a5, 0x34, 0, 0},{0x86a6, 0xff, 0, 0}, ++ {0x86a7, 0xf5, 0, 0},{0x86a8, 0x45, 0, 0},{0x86a9, 0xe5, 0, 0}, ++ {0x86aa, 0x3c, 0, 0},{0x86ab, 0x34, 0, 0},{0x86ac, 0xff, 0, 0}, ++ {0x86ad, 0xf5, 0, 0},{0x86ae, 0x44, 0, 0},{0x86af, 0x75, 0, 0}, ++ {0x86b0, 0x78, 0, 0},{0x86b1, 0x02, 0, 0},{0x86b2, 0x75, 0, 0}, ++ {0x86b3, 0x0a, 0, 0},{0x86b4, 0x01, 0, 0},{0x86b5, 0x12, 0, 0}, ++ {0x86b6, 0x12, 0, 0},{0x86b7, 0x92, 0, 0},{0x86b8, 0xd2, 0, 0}, ++ {0x86b9, 0x18, 0, 0},{0x86ba, 0xd2, 0, 0},{0x86bb, 0x19, 0, 0}, ++ {0x86bc, 0xc2, 0, 0},{0x86bd, 0x3a, 0, 0},{0x86be, 0xc2, 0, 0}, ++ {0x86bf, 0x39, 0, 0},{0x86c0, 0xd2, 0, 0},{0x86c1, 0x1a, 0, 0}, ++ {0x86c2, 0xd2, 0, 0},{0x86c3, 0x36, 0, 0},{0x86c4, 0xd2, 0, 0}, ++ {0x86c5, 0x30, 0, 0},{0x86c6, 0x22, 0, 0},{0x86c7, 0x12, 0, 0}, ++ {0x86c8, 0x10, 0, 0},{0x86c9, 0xb5, 0, 0},{0x86ca, 0x75, 0, 0}, ++ {0x86cb, 0x78, 0, 0},{0x86cc, 0x02, 0, 0},{0x86cd, 0xe4, 0, 0}, ++ {0x86ce, 0xf5, 0, 0},{0x86cf, 0x0a, 0, 0},{0x86d0, 0x12, 0, 0}, ++ {0x86d1, 0x12, 0, 0},{0x86d2, 0x92, 0, 0},{0x86d3, 0xd2, 0, 0}, ++ {0x86d4, 0x18, 0, 0},{0x86d5, 0xc2, 0, 0},{0x86d6, 0x19, 0, 0}, ++ {0x86d7, 0x22, 0, 0},{0x86d8, 0x75, 0, 0},{0x86d9, 0x0a, 0, 0}, ++ {0x86da, 0x01, 0, 0},{0x86db, 0x12, 0, 0},{0x86dc, 0x12, 0, 0}, ++ {0x86dd, 0x92, 0, 0},{0x86de, 0x22, 0, 0},{0x86df, 0x90, 0, 0}, ++ {0x86e0, 0x38, 0, 0},{0x86e1, 0x04, 0, 0},{0x86e2, 0xe0, 0, 0}, ++ {0x86e3, 0xfe, 0, 0},{0x86e4, 0xa3, 0, 0},{0x86e5, 0xe0, 0, 0}, ++ {0x86e6, 0xfd, 0, 0},{0x86e7, 0xed, 0, 0},{0x86e8, 0xff, 0, 0}, ++ {0x86e9, 0xee, 0, 0},{0x86ea, 0x54, 0, 0},{0x86eb, 0x0f, 0, 0}, ++ {0x86ec, 0xf5, 0, 0},{0x86ed, 0x0e, 0, 0},{0x86ee, 0x8f, 0, 0}, ++ {0x86ef, 0x0f, 0, 0},{0x86f0, 0xa3, 0, 0},{0x86f1, 0xe0, 0, 0}, ++ {0x86f2, 0xfe, 0, 0},{0x86f3, 0xa3, 0, 0},{0x86f4, 0xe0, 0, 0}, ++ {0x86f5, 0xfd, 0, 0},{0x86f6, 0xed, 0, 0},{0x86f7, 0xff, 0, 0}, ++ {0x86f8, 0xee, 0, 0},{0x86f9, 0x54, 0, 0},{0x86fa, 0x07, 0, 0}, ++ {0x86fb, 0xf5, 0, 0},{0x86fc, 0x10, 0, 0},{0x86fd, 0x8f, 0, 0}, ++ {0x86fe, 0x11, 0, 0},{0x86ff, 0xe5, 0, 0},{0x8700, 0x0e, 0, 0}, ++ {0x8701, 0xc4, 0, 0},{0x8702, 0xf8, 0, 0},{0x8703, 0x54, 0, 0}, ++ {0x8704, 0xf0, 0, 0},{0x8705, 0xc8, 0, 0},{0x8706, 0x68, 0, 0}, ++ {0x8707, 0xf5, 0, 0},{0x8708, 0x0e, 0, 0},{0x8709, 0xe5, 0, 0}, ++ {0x870a, 0x0f, 0, 0},{0x870b, 0xc4, 0, 0},{0x870c, 0x54, 0, 0}, ++ {0x870d, 0x0f, 0, 0},{0x870e, 0x48, 0, 0},{0x870f, 0xf5, 0, 0}, ++ {0x8710, 0x0f, 0, 0},{0x8711, 0xe5, 0, 0},{0x8712, 0x10, 0, 0}, ++ {0x8713, 0xc4, 0, 0},{0x8714, 0xf8, 0, 0},{0x8715, 0x54, 0, 0}, ++ {0x8716, 0xf0, 0, 0},{0x8717, 0xc8, 0, 0},{0x8718, 0x68, 0, 0}, ++ {0x8719, 0xf5, 0, 0},{0x871a, 0x10, 0, 0},{0x871b, 0xe5, 0, 0}, ++ {0x871c, 0x11, 0, 0},{0x871d, 0xc4, 0, 0},{0x871e, 0x54, 0, 0}, ++ {0x871f, 0x0f, 0, 0},{0x8720, 0x48, 0, 0},{0x8721, 0xf5, 0, 0}, ++ {0x8722, 0x11, 0, 0},{0x8723, 0xe4, 0, 0},{0x8724, 0xf5, 0, 0}, ++ {0x8725, 0x17, 0, 0},{0x8726, 0x75, 0, 0},{0x8727, 0x16, 0, 0}, ++ {0x8728, 0x04, 0, 0},{0x8729, 0x12, 0, 0},{0x872a, 0x02, 0, 0}, ++ {0x872b, 0x66, 0, 0},{0x872c, 0x24, 0, 0},{0x872d, 0x34, 0, 0}, ++ {0x872e, 0xf8, 0, 0},{0x872f, 0xe6, 0, 0},{0x8730, 0xf5, 0, 0}, ++ {0x8731, 0x12, 0, 0},{0x8732, 0x12, 0, 0},{0x8733, 0x02, 0, 0}, ++ {0x8734, 0x66, 0, 0},{0x8735, 0x24, 0, 0},{0x8736, 0x35, 0, 0}, ++ {0x8737, 0xf8, 0, 0},{0x8738, 0xe6, 0, 0},{0x8739, 0xf5, 0, 0}, ++ {0x873a, 0x14, 0, 0},{0x873b, 0x12, 0, 0},{0x873c, 0x02, 0, 0}, ++ {0x873d, 0x66, 0, 0},{0x873e, 0x24, 0, 0},{0x873f, 0x36, 0, 0}, ++ {0x8740, 0xf8, 0, 0},{0x8741, 0xe6, 0, 0},{0x8742, 0xf5, 0, 0}, ++ {0x8743, 0x13, 0, 0},{0x8744, 0x12, 0, 0},{0x8745, 0x02, 0, 0}, ++ {0x8746, 0x66, 0, 0},{0x8747, 0x24, 0, 0},{0x8748, 0x37, 0, 0}, ++ {0x8749, 0xf8, 0, 0},{0x874a, 0xe6, 0, 0},{0x874b, 0xf5, 0, 0}, ++ {0x874c, 0x15, 0, 0},{0x874d, 0x12, 0, 0},{0x874e, 0x02, 0, 0}, ++ {0x874f, 0x79, 0, 0},{0x8750, 0xaf, 0, 0},{0x8751, 0x12, 0, 0}, ++ {0x8752, 0x12, 0, 0},{0x8753, 0x01, 0, 0},{0x8754, 0x42, 0, 0}, ++ {0x8755, 0x8f, 0, 0},{0x8756, 0x12, 0, 0},{0x8757, 0x12, 0, 0}, ++ {0x8758, 0x02, 0, 0},{0x8759, 0x79, 0, 0},{0x875a, 0xaf, 0, 0}, ++ {0x875b, 0x13, 0, 0},{0x875c, 0x12, 0, 0},{0x875d, 0x01, 0, 0}, ++ {0x875e, 0x42, 0, 0},{0x875f, 0x8f, 0, 0},{0x8760, 0x13, 0, 0}, ++ {0x8761, 0x12, 0, 0},{0x8762, 0x02, 0, 0},{0x8763, 0x11, 0, 0}, ++ {0x8764, 0xaf, 0, 0},{0x8765, 0x14, 0, 0},{0x8766, 0xfc, 0, 0}, ++ {0x8767, 0xfd, 0, 0},{0x8768, 0xfe, 0, 0},{0x8769, 0x12, 0, 0}, ++ {0x876a, 0x08, 0, 0},{0x876b, 0x7f, 0, 0},{0x876c, 0x12, 0, 0}, ++ {0x876d, 0x01, 0, 0},{0x876e, 0x61, 0, 0},{0x876f, 0x7b, 0, 0}, ++ {0x8770, 0x30, 0, 0},{0x8771, 0x12, 0, 0},{0x8772, 0x01, 0, 0}, ++ {0x8773, 0x5a, 0, 0},{0x8774, 0x8f, 0, 0},{0x8775, 0x14, 0, 0}, ++ {0x8776, 0x12, 0, 0},{0x8777, 0x02, 0, 0},{0x8778, 0x11, 0, 0}, ++ {0x8779, 0xaf, 0, 0},{0x877a, 0x15, 0, 0},{0x877b, 0xfc, 0, 0}, ++ {0x877c, 0xfd, 0, 0},{0x877d, 0xfe, 0, 0},{0x877e, 0x12, 0, 0}, ++ {0x877f, 0x08, 0, 0},{0x8780, 0x7f, 0, 0},{0x8781, 0x12, 0, 0}, ++ {0x8782, 0x01, 0, 0},{0x8783, 0x61, 0, 0},{0x8784, 0xe4, 0, 0}, ++ {0x8785, 0x7b, 0, 0},{0x8786, 0x30, 0, 0},{0x8787, 0x12, 0, 0}, ++ {0x8788, 0x01, 0, 0},{0x8789, 0x5b, 0, 0},{0x878a, 0x8f, 0, 0}, ++ {0x878b, 0x15, 0, 0},{0x878c, 0xc3, 0, 0},{0x878d, 0xe5, 0, 0}, ++ {0x878e, 0x13, 0, 0},{0x878f, 0x95, 0, 0},{0x8790, 0x12, 0, 0}, ++ {0x8791, 0xff, 0, 0},{0x8792, 0x0f, 0, 0},{0x8793, 0xef, 0, 0}, ++ {0x8794, 0xc3, 0, 0},{0x8795, 0x13, 0, 0},{0x8796, 0xff, 0, 0}, ++ {0x8797, 0xc3, 0, 0},{0x8798, 0x94, 0, 0},{0x8799, 0x04, 0, 0}, ++ {0x879a, 0x50, 0, 0},{0x879b, 0x27, 0, 0},{0x879c, 0xe5, 0, 0}, ++ {0x879d, 0x12, 0, 0},{0x879e, 0x9f, 0, 0},{0x879f, 0x40, 0, 0}, ++ {0x87a0, 0x06, 0, 0},{0x87a1, 0xe5, 0, 0},{0x87a2, 0x12, 0, 0}, ++ {0x87a3, 0x9f, 0, 0},{0x87a4, 0xfe, 0, 0},{0x87a5, 0x80, 0, 0}, ++ {0x87a6, 0x02, 0, 0},{0x87a7, 0x7e, 0, 0},{0x87a8, 0x00, 0, 0}, ++ {0x87a9, 0x8e, 0, 0},{0x87aa, 0x12, 0, 0},{0x87ab, 0xef, 0, 0}, ++ {0x87ac, 0xfd, 0, 0},{0x87ad, 0xe5, 0, 0},{0x87ae, 0x13, 0, 0}, ++ {0x87af, 0x2d, 0, 0},{0x87b0, 0xfd, 0, 0},{0x87b1, 0xe4, 0, 0}, ++ {0x87b2, 0x33, 0, 0},{0x87b3, 0xfc, 0, 0},{0x87b4, 0xc3, 0, 0}, ++ {0x87b5, 0xed, 0, 0},{0x87b6, 0x95, 0, 0},{0x87b7, 0x0f, 0, 0}, ++ {0x87b8, 0xec, 0, 0},{0x87b9, 0x95, 0, 0},{0x87ba, 0x0e, 0, 0}, ++ {0x87bb, 0x50, 0, 0},{0x87bc, 0x02, 0, 0},{0x87bd, 0x80, 0, 0}, ++ {0x87be, 0x02, 0, 0},{0x87bf, 0xad, 0, 0},{0x87c0, 0x0f, 0, 0}, ++ {0x87c1, 0x8d, 0, 0},{0x87c2, 0x13, 0, 0},{0x87c3, 0xc3, 0, 0}, ++ {0x87c4, 0xe5, 0, 0},{0x87c5, 0x15, 0, 0},{0x87c6, 0x95, 0, 0}, ++ {0x87c7, 0x14, 0, 0},{0x87c8, 0xff, 0, 0},{0x87c9, 0xc3, 0, 0}, ++ {0x87ca, 0x94, 0, 0},{0x87cb, 0x04, 0, 0},{0x87cc, 0x50, 0, 0}, ++ {0x87cd, 0x29, 0, 0},{0x87ce, 0xe5, 0, 0},{0x87cf, 0x14, 0, 0}, ++ {0x87d0, 0x9f, 0, 0},{0x87d1, 0x40, 0, 0},{0x87d2, 0x06, 0, 0}, ++ {0x87d3, 0xe5, 0, 0},{0x87d4, 0x14, 0, 0},{0x87d5, 0x9f, 0, 0}, ++ {0x87d6, 0xfe, 0, 0},{0x87d7, 0x80, 0, 0},{0x87d8, 0x02, 0, 0}, ++ {0x87d9, 0x7e, 0, 0},{0x87da, 0x00, 0, 0},{0x87db, 0x8e, 0, 0}, ++ {0x87dc, 0x14, 0, 0},{0x87dd, 0xef, 0, 0},{0x87de, 0xfd, 0, 0}, ++ {0x87df, 0xe5, 0, 0},{0x87e0, 0x15, 0, 0},{0x87e1, 0x2d, 0, 0}, ++ {0x87e2, 0xfd, 0, 0},{0x87e3, 0xe4, 0, 0},{0x87e4, 0x33, 0, 0}, ++ {0x87e5, 0xfc, 0, 0},{0x87e6, 0xc3, 0, 0},{0x87e7, 0xed, 0, 0}, ++ {0x87e8, 0x95, 0, 0},{0x87e9, 0x11, 0, 0},{0x87ea, 0xec, 0, 0}, ++ {0x87eb, 0x95, 0, 0},{0x87ec, 0x10, 0, 0},{0x87ed, 0x50, 0, 0}, ++ {0x87ee, 0x04, 0, 0},{0x87ef, 0xaf, 0, 0},{0x87f0, 0x05, 0, 0}, ++ {0x87f1, 0x80, 0, 0},{0x87f2, 0x02, 0, 0},{0x87f3, 0xaf, 0, 0}, ++ {0x87f4, 0x11, 0, 0},{0x87f5, 0x8f, 0, 0},{0x87f6, 0x15, 0, 0}, ++ {0x87f7, 0xe5, 0, 0},{0x87f8, 0x15, 0, 0},{0x87f9, 0xd3, 0, 0}, ++ {0x87fa, 0x95, 0, 0},{0x87fb, 0x17, 0, 0},{0x87fc, 0x40, 0, 0}, ++ {0x87fd, 0x04, 0, 0},{0x87fe, 0xaf, 0, 0},{0x87ff, 0x15, 0, 0}, ++ {0x8800, 0x80, 0, 0},{0x8801, 0x02, 0, 0},{0x8802, 0xaf, 0, 0}, ++ {0x8803, 0x17, 0, 0},{0x8804, 0x8f, 0, 0},{0x8805, 0x17, 0, 0}, ++ {0x8806, 0xd3, 0, 0},{0x8807, 0xe5, 0, 0},{0x8808, 0x16, 0, 0}, ++ {0x8809, 0x64, 0, 0},{0x880a, 0x80, 0, 0},{0x880b, 0x94, 0, 0}, ++ {0x880c, 0x80, 0, 0},{0x880d, 0x40, 0, 0},{0x880e, 0x04, 0, 0}, ++ {0x880f, 0xaf, 0, 0},{0x8810, 0x15, 0, 0},{0x8811, 0x80, 0, 0}, ++ {0x8812, 0x02, 0, 0},{0x8813, 0xaf, 0, 0},{0x8814, 0x17, 0, 0}, ++ {0x8815, 0x8f, 0, 0},{0x8816, 0x15, 0, 0},{0x8817, 0xe5, 0, 0}, ++ {0x8818, 0x16, 0, 0},{0x8819, 0xfd, 0, 0},{0x881a, 0x33, 0, 0}, ++ {0x881b, 0x95, 0, 0},{0x881c, 0xe0, 0, 0},{0x881d, 0xfc, 0, 0}, ++ {0x881e, 0xed, 0, 0},{0x881f, 0xae, 0, 0},{0x8820, 0x04, 0, 0}, ++ {0x8821, 0x78, 0, 0},{0x8822, 0x02, 0, 0},{0x8823, 0xc3, 0, 0}, ++ {0x8824, 0x33, 0, 0},{0x8825, 0xce, 0, 0},{0x8826, 0x33, 0, 0}, ++ {0x8827, 0xce, 0, 0},{0x8828, 0xd8, 0, 0},{0x8829, 0xf9, 0, 0}, ++ {0x882a, 0xff, 0, 0},{0x882b, 0x24, 0, 0},{0x882c, 0x01, 0, 0}, ++ {0x882d, 0xfb, 0, 0},{0x882e, 0xee, 0, 0},{0x882f, 0x34, 0, 0}, ++ {0x8830, 0x60, 0, 0},{0x8831, 0x8b, 0, 0},{0x8832, 0x82, 0, 0}, ++ {0x8833, 0xf5, 0, 0},{0x8834, 0x83, 0, 0},{0x8835, 0xe5, 0, 0}, ++ {0x8836, 0x12, 0, 0},{0x8837, 0xf0, 0, 0},{0x8838, 0xef, 0, 0}, ++ {0x8839, 0x24, 0, 0},{0x883a, 0x02, 0, 0},{0x883b, 0xff, 0, 0}, ++ {0x883c, 0xee, 0, 0},{0x883d, 0x34, 0, 0},{0x883e, 0x60, 0, 0}, ++ {0x883f, 0x8f, 0, 0},{0x8840, 0x82, 0, 0},{0x8841, 0xf5, 0, 0}, ++ {0x8842, 0x83, 0, 0},{0x8843, 0xe5, 0, 0},{0x8844, 0x14, 0, 0}, ++ {0x8845, 0xf0, 0, 0},{0x8846, 0xed, 0, 0},{0x8847, 0xae, 0, 0}, ++ {0x8848, 0x04, 0, 0},{0x8849, 0x78, 0, 0},{0x884a, 0x02, 0, 0}, ++ {0x884b, 0xc3, 0, 0},{0x884c, 0x33, 0, 0},{0x884d, 0xce, 0, 0}, ++ {0x884e, 0x33, 0, 0},{0x884f, 0xce, 0, 0},{0x8850, 0xd8, 0, 0}, ++ {0x8851, 0xf9, 0, 0},{0x8852, 0xff, 0, 0},{0x8853, 0x24, 0, 0}, ++ {0x8854, 0x03, 0, 0},{0x8855, 0xfd, 0, 0},{0x8856, 0xee, 0, 0}, ++ {0x8857, 0x34, 0, 0},{0x8858, 0x60, 0, 0},{0x8859, 0x8d, 0, 0}, ++ {0x885a, 0x82, 0, 0},{0x885b, 0xf5, 0, 0},{0x885c, 0x83, 0, 0}, ++ {0x885d, 0xe5, 0, 0},{0x885e, 0x13, 0, 0},{0x885f, 0xf0, 0, 0}, ++ {0x8860, 0xef, 0, 0},{0x8861, 0x24, 0, 0},{0x8862, 0x04, 0, 0}, ++ {0x8863, 0xff, 0, 0},{0x8864, 0xee, 0, 0},{0x8865, 0x34, 0, 0}, ++ {0x8866, 0x60, 0, 0},{0x8867, 0x8f, 0, 0},{0x8868, 0x82, 0, 0}, ++ {0x8869, 0xf5, 0, 0},{0x886a, 0x83, 0, 0},{0x886b, 0xe5, 0, 0}, ++ {0x886c, 0x15, 0, 0},{0x886d, 0xf0, 0, 0},{0x886e, 0x15, 0, 0}, ++ {0x886f, 0x16, 0, 0},{0x8870, 0xc3, 0, 0},{0x8871, 0xe5, 0, 0}, ++ {0x8872, 0x16, 0, 0},{0x8873, 0x64, 0, 0},{0x8874, 0x80, 0, 0}, ++ {0x8875, 0x94, 0, 0},{0x8876, 0x80, 0, 0},{0x8877, 0x40, 0, 0}, ++ {0x8878, 0x03, 0, 0},{0x8879, 0x02, 0, 0},{0x887a, 0x07, 0, 0}, ++ {0x887b, 0x29, 0, 0},{0x887c, 0xc2, 0, 0},{0x887d, 0x30, 0, 0}, ++ {0x887e, 0x22, 0, 0},{0x887f, 0xe8, 0, 0},{0x8880, 0x8f, 0, 0}, ++ {0x8881, 0xf0, 0, 0},{0x8882, 0xa4, 0, 0},{0x8883, 0xcc, 0, 0}, ++ {0x8884, 0x8b, 0, 0},{0x8885, 0xf0, 0, 0},{0x8886, 0xa4, 0, 0}, ++ {0x8887, 0x2c, 0, 0},{0x8888, 0xfc, 0, 0},{0x8889, 0xe9, 0, 0}, ++ {0x888a, 0x8e, 0, 0},{0x888b, 0xf0, 0, 0},{0x888c, 0xa4, 0, 0}, ++ {0x888d, 0x2c, 0, 0},{0x888e, 0xfc, 0, 0},{0x888f, 0x8a, 0, 0}, ++ {0x8890, 0xf0, 0, 0},{0x8891, 0xed, 0, 0},{0x8892, 0xa4, 0, 0}, ++ {0x8893, 0x2c, 0, 0},{0x8894, 0xfc, 0, 0},{0x8895, 0xea, 0, 0}, ++ {0x8896, 0x8e, 0, 0},{0x8897, 0xf0, 0, 0},{0x8898, 0xa4, 0, 0}, ++ {0x8899, 0xcd, 0, 0},{0x889a, 0xa8, 0, 0},{0x889b, 0xf0, 0, 0}, ++ {0x889c, 0x8b, 0, 0},{0x889d, 0xf0, 0, 0},{0x889e, 0xa4, 0, 0}, ++ {0x889f, 0x2d, 0, 0},{0x88a0, 0xcc, 0, 0},{0x88a1, 0x38, 0, 0}, ++ {0x88a2, 0x25, 0, 0},{0x88a3, 0xf0, 0, 0},{0x88a4, 0xfd, 0, 0}, ++ {0x88a5, 0xe9, 0, 0},{0x88a6, 0x8f, 0, 0},{0x88a7, 0xf0, 0, 0}, ++ {0x88a8, 0xa4, 0, 0},{0x88a9, 0x2c, 0, 0},{0x88aa, 0xcd, 0, 0}, ++ {0x88ab, 0x35, 0, 0},{0x88ac, 0xf0, 0, 0},{0x88ad, 0xfc, 0, 0}, ++ {0x88ae, 0xeb, 0, 0},{0x88af, 0x8e, 0, 0},{0x88b0, 0xf0, 0, 0}, ++ {0x88b1, 0xa4, 0, 0},{0x88b2, 0xfe, 0, 0},{0x88b3, 0xa9, 0, 0}, ++ {0x88b4, 0xf0, 0, 0},{0x88b5, 0xeb, 0, 0},{0x88b6, 0x8f, 0, 0}, ++ {0x88b7, 0xf0, 0, 0},{0x88b8, 0xa4, 0, 0},{0x88b9, 0xcf, 0, 0}, ++ {0x88ba, 0xc5, 0, 0},{0x88bb, 0xf0, 0, 0},{0x88bc, 0x2e, 0, 0}, ++ {0x88bd, 0xcd, 0, 0},{0x88be, 0x39, 0, 0},{0x88bf, 0xfe, 0, 0}, ++ {0x88c0, 0xe4, 0, 0},{0x88c1, 0x3c, 0, 0},{0x88c2, 0xfc, 0, 0}, ++ {0x88c3, 0xea, 0, 0},{0x88c4, 0xa4, 0, 0},{0x88c5, 0x2d, 0, 0}, ++ {0x88c6, 0xce, 0, 0},{0x88c7, 0x35, 0, 0},{0x88c8, 0xf0, 0, 0}, ++ {0x88c9, 0xfd, 0, 0},{0x88ca, 0xe4, 0, 0},{0x88cb, 0x3c, 0, 0}, ++ {0x88cc, 0xfc, 0, 0},{0x88cd, 0x22, 0, 0},{0x88ce, 0x75, 0, 0}, ++ {0x88cf, 0xf0, 0, 0},{0x88d0, 0x08, 0, 0},{0x88d1, 0x75, 0, 0}, ++ {0x88d2, 0x82, 0, 0},{0x88d3, 0x00, 0, 0},{0x88d4, 0xef, 0, 0}, ++ {0x88d5, 0x2f, 0, 0},{0x88d6, 0xff, 0, 0},{0x88d7, 0xee, 0, 0}, ++ {0x88d8, 0x33, 0, 0},{0x88d9, 0xfe, 0, 0},{0x88da, 0xcd, 0, 0}, ++ {0x88db, 0x33, 0, 0},{0x88dc, 0xcd, 0, 0},{0x88dd, 0xcc, 0, 0}, ++ {0x88de, 0x33, 0, 0},{0x88df, 0xcc, 0, 0},{0x88e0, 0xc5, 0, 0}, ++ {0x88e1, 0x82, 0, 0},{0x88e2, 0x33, 0, 0},{0x88e3, 0xc5, 0, 0}, ++ {0x88e4, 0x82, 0, 0},{0x88e5, 0x9b, 0, 0},{0x88e6, 0xed, 0, 0}, ++ {0x88e7, 0x9a, 0, 0},{0x88e8, 0xec, 0, 0},{0x88e9, 0x99, 0, 0}, ++ {0x88ea, 0xe5, 0, 0},{0x88eb, 0x82, 0, 0},{0x88ec, 0x98, 0, 0}, ++ {0x88ed, 0x40, 0, 0},{0x88ee, 0x0c, 0, 0},{0x88ef, 0xf5, 0, 0}, ++ {0x88f0, 0x82, 0, 0},{0x88f1, 0xee, 0, 0},{0x88f2, 0x9b, 0, 0}, ++ {0x88f3, 0xfe, 0, 0},{0x88f4, 0xed, 0, 0},{0x88f5, 0x9a, 0, 0}, ++ {0x88f6, 0xfd, 0, 0},{0x88f7, 0xec, 0, 0},{0x88f8, 0x99, 0, 0}, ++ {0x88f9, 0xfc, 0, 0},{0x88fa, 0x0f, 0, 0},{0x88fb, 0xd5, 0, 0}, ++ {0x88fc, 0xf0, 0, 0},{0x88fd, 0xd6, 0, 0},{0x88fe, 0xe4, 0, 0}, ++ {0x88ff, 0xce, 0, 0},{0x8900, 0xfb, 0, 0},{0x8901, 0xe4, 0, 0}, ++ {0x8902, 0xcd, 0, 0},{0x8903, 0xfa, 0, 0},{0x8904, 0xe4, 0, 0}, ++ {0x8905, 0xcc, 0, 0},{0x8906, 0xf9, 0, 0},{0x8907, 0xa8, 0, 0}, ++ {0x8908, 0x82, 0, 0},{0x8909, 0x22, 0, 0},{0x890a, 0xb8, 0, 0}, ++ {0x890b, 0x00, 0, 0},{0x890c, 0xc1, 0, 0},{0x890d, 0xb9, 0, 0}, ++ {0x890e, 0x00, 0, 0},{0x890f, 0x59, 0, 0},{0x8910, 0xba, 0, 0}, ++ {0x8911, 0x00, 0, 0},{0x8912, 0x2d, 0, 0},{0x8913, 0xec, 0, 0}, ++ {0x8914, 0x8b, 0, 0},{0x8915, 0xf0, 0, 0},{0x8916, 0x84, 0, 0}, ++ {0x8917, 0xcf, 0, 0},{0x8918, 0xce, 0, 0},{0x8919, 0xcd, 0, 0}, ++ {0x891a, 0xfc, 0, 0},{0x891b, 0xe5, 0, 0},{0x891c, 0xf0, 0, 0}, ++ {0x891d, 0xcb, 0, 0},{0x891e, 0xf9, 0, 0},{0x891f, 0x78, 0, 0}, ++ {0x8920, 0x18, 0, 0},{0x8921, 0xef, 0, 0},{0x8922, 0x2f, 0, 0}, ++ {0x8923, 0xff, 0, 0},{0x8924, 0xee, 0, 0},{0x8925, 0x33, 0, 0}, ++ {0x8926, 0xfe, 0, 0},{0x8927, 0xed, 0, 0},{0x8928, 0x33, 0, 0}, ++ {0x8929, 0xfd, 0, 0},{0x892a, 0xec, 0, 0},{0x892b, 0x33, 0, 0}, ++ {0x892c, 0xfc, 0, 0},{0x892d, 0xeb, 0, 0},{0x892e, 0x33, 0, 0}, ++ {0x892f, 0xfb, 0, 0},{0x8930, 0x10, 0, 0},{0x8931, 0xd7, 0, 0}, ++ {0x8932, 0x03, 0, 0},{0x8933, 0x99, 0, 0},{0x8934, 0x40, 0, 0}, ++ {0x8935, 0x04, 0, 0},{0x8936, 0xeb, 0, 0},{0x8937, 0x99, 0, 0}, ++ {0x8938, 0xfb, 0, 0},{0x8939, 0x0f, 0, 0},{0x893a, 0xd8, 0, 0}, ++ {0x893b, 0xe5, 0, 0},{0x893c, 0xe4, 0, 0},{0x893d, 0xf9, 0, 0}, ++ {0x893e, 0xfa, 0, 0},{0x893f, 0x22, 0, 0},{0x8940, 0x78, 0, 0}, ++ {0x8941, 0x18, 0, 0},{0x8942, 0xef, 0, 0},{0x8943, 0x2f, 0, 0}, ++ {0x8944, 0xff, 0, 0},{0x8945, 0xee, 0, 0},{0x8946, 0x33, 0, 0}, ++ {0x8947, 0xfe, 0, 0},{0x8948, 0xed, 0, 0},{0x8949, 0x33, 0, 0}, ++ {0x894a, 0xfd, 0, 0},{0x894b, 0xec, 0, 0},{0x894c, 0x33, 0, 0}, ++ {0x894d, 0xfc, 0, 0},{0x894e, 0xc9, 0, 0},{0x894f, 0x33, 0, 0}, ++ {0x8950, 0xc9, 0, 0},{0x8951, 0x10, 0, 0},{0x8952, 0xd7, 0, 0}, ++ {0x8953, 0x05, 0, 0},{0x8954, 0x9b, 0, 0},{0x8955, 0xe9, 0, 0}, ++ {0x8956, 0x9a, 0, 0},{0x8957, 0x40, 0, 0},{0x8958, 0x07, 0, 0}, ++ {0x8959, 0xec, 0, 0},{0x895a, 0x9b, 0, 0},{0x895b, 0xfc, 0, 0}, ++ {0x895c, 0xe9, 0, 0},{0x895d, 0x9a, 0, 0},{0x895e, 0xf9, 0, 0}, ++ {0x895f, 0x0f, 0, 0},{0x8960, 0xd8, 0, 0},{0x8961, 0xe0, 0, 0}, ++ {0x8962, 0xe4, 0, 0},{0x8963, 0xc9, 0, 0},{0x8964, 0xfa, 0, 0}, ++ {0x8965, 0xe4, 0, 0},{0x8966, 0xcc, 0, 0},{0x8967, 0xfb, 0, 0}, ++ {0x8968, 0x22, 0, 0},{0x8969, 0x75, 0, 0},{0x896a, 0xf0, 0, 0}, ++ {0x896b, 0x10, 0, 0},{0x896c, 0xef, 0, 0},{0x896d, 0x2f, 0, 0}, ++ {0x896e, 0xff, 0, 0},{0x896f, 0xee, 0, 0},{0x8970, 0x33, 0, 0}, ++ {0x8971, 0xfe, 0, 0},{0x8972, 0xed, 0, 0},{0x8973, 0x33, 0, 0}, ++ {0x8974, 0xfd, 0, 0},{0x8975, 0xcc, 0, 0},{0x8976, 0x33, 0, 0}, ++ {0x8977, 0xcc, 0, 0},{0x8978, 0xc8, 0, 0},{0x8979, 0x33, 0, 0}, ++ {0x897a, 0xc8, 0, 0},{0x897b, 0x10, 0, 0},{0x897c, 0xd7, 0, 0}, ++ {0x897d, 0x07, 0, 0},{0x897e, 0x9b, 0, 0},{0x897f, 0xec, 0, 0}, ++ {0x8980, 0x9a, 0, 0},{0x8981, 0xe8, 0, 0},{0x8982, 0x99, 0, 0}, ++ {0x8983, 0x40, 0, 0},{0x8984, 0x0a, 0, 0},{0x8985, 0xed, 0, 0}, ++ {0x8986, 0x9b, 0, 0},{0x8987, 0xfd, 0, 0},{0x8988, 0xec, 0, 0}, ++ {0x8989, 0x9a, 0, 0},{0x898a, 0xfc, 0, 0},{0x898b, 0xe8, 0, 0}, ++ {0x898c, 0x99, 0, 0},{0x898d, 0xf8, 0, 0},{0x898e, 0x0f, 0, 0}, ++ {0x898f, 0xd5, 0, 0},{0x8990, 0xf0, 0, 0},{0x8991, 0xda, 0, 0}, ++ {0x8992, 0xe4, 0, 0},{0x8993, 0xcd, 0, 0},{0x8994, 0xfb, 0, 0}, ++ {0x8995, 0xe4, 0, 0},{0x8996, 0xcc, 0, 0},{0x8997, 0xfa, 0, 0}, ++ {0x8998, 0xe4, 0, 0},{0x8999, 0xc8, 0, 0},{0x899a, 0xf9, 0, 0}, ++ {0x899b, 0x22, 0, 0},{0x899c, 0xe8, 0, 0},{0x899d, 0x60, 0, 0}, ++ {0x899e, 0x0f, 0, 0},{0x899f, 0xec, 0, 0},{0x89a0, 0xc3, 0, 0}, ++ {0x89a1, 0x13, 0, 0},{0x89a2, 0xfc, 0, 0},{0x89a3, 0xed, 0, 0}, ++ {0x89a4, 0x13, 0, 0},{0x89a5, 0xfd, 0, 0},{0x89a6, 0xee, 0, 0}, ++ {0x89a7, 0x13, 0, 0},{0x89a8, 0xfe, 0, 0},{0x89a9, 0xef, 0, 0}, ++ {0x89aa, 0x13, 0, 0},{0x89ab, 0xff, 0, 0},{0x89ac, 0xd8, 0, 0}, ++ {0x89ad, 0xf1, 0, 0},{0x89ae, 0x22, 0, 0},{0x89af, 0xe8, 0, 0}, ++ {0x89b0, 0x60, 0, 0},{0x89b1, 0x0f, 0, 0},{0x89b2, 0xef, 0, 0}, ++ {0x89b3, 0xc3, 0, 0},{0x89b4, 0x33, 0, 0},{0x89b5, 0xff, 0, 0}, ++ {0x89b6, 0xee, 0, 0},{0x89b7, 0x33, 0, 0},{0x89b8, 0xfe, 0, 0}, ++ {0x89b9, 0xed, 0, 0},{0x89ba, 0x33, 0, 0},{0x89bb, 0xfd, 0, 0}, ++ {0x89bc, 0xec, 0, 0},{0x89bd, 0x33, 0, 0},{0x89be, 0xfc, 0, 0}, ++ {0x89bf, 0xd8, 0, 0},{0x89c0, 0xf1, 0, 0},{0x89c1, 0x22, 0, 0}, ++ {0x89c2, 0xe4, 0, 0},{0x89c3, 0x93, 0, 0},{0x89c4, 0xfc, 0, 0}, ++ {0x89c5, 0x74, 0, 0},{0x89c6, 0x01, 0, 0},{0x89c7, 0x93, 0, 0}, ++ {0x89c8, 0xfd, 0, 0},{0x89c9, 0x74, 0, 0},{0x89ca, 0x02, 0, 0}, ++ {0x89cb, 0x93, 0, 0},{0x89cc, 0xfe, 0, 0},{0x89cd, 0x74, 0, 0}, ++ {0x89ce, 0x03, 0, 0},{0x89cf, 0x93, 0, 0},{0x89d0, 0xff, 0, 0}, ++ {0x89d1, 0x22, 0, 0},{0x89d2, 0xd0, 0, 0},{0x89d3, 0x83, 0, 0}, ++ {0x89d4, 0xd0, 0, 0},{0x89d5, 0x82, 0, 0},{0x89d6, 0xf8, 0, 0}, ++ {0x89d7, 0xe4, 0, 0},{0x89d8, 0x93, 0, 0},{0x89d9, 0x70, 0, 0}, ++ {0x89da, 0x12, 0, 0},{0x89db, 0x74, 0, 0},{0x89dc, 0x01, 0, 0}, ++ {0x89dd, 0x93, 0, 0},{0x89de, 0x70, 0, 0},{0x89df, 0x0d, 0, 0}, ++ {0x89e0, 0xa3, 0, 0},{0x89e1, 0xa3, 0, 0},{0x89e2, 0x93, 0, 0}, ++ {0x89e3, 0xf8, 0, 0},{0x89e4, 0x74, 0, 0},{0x89e5, 0x01, 0, 0}, ++ {0x89e6, 0x93, 0, 0},{0x89e7, 0xf5, 0, 0},{0x89e8, 0x82, 0, 0}, ++ {0x89e9, 0x88, 0, 0},{0x89ea, 0x83, 0, 0},{0x89eb, 0xe4, 0, 0}, ++ {0x89ec, 0x73, 0, 0},{0x89ed, 0x74, 0, 0},{0x89ee, 0x02, 0, 0}, ++ {0x89ef, 0x93, 0, 0},{0x89f0, 0x68, 0, 0},{0x89f1, 0x60, 0, 0}, ++ {0x89f2, 0xef, 0, 0},{0x89f3, 0xa3, 0, 0},{0x89f4, 0xa3, 0, 0}, ++ {0x89f5, 0xa3, 0, 0},{0x89f6, 0x80, 0, 0},{0x89f7, 0xdf, 0, 0}, ++ {0x89f8, 0x75, 0, 0},{0x89f9, 0x12, 0, 0},{0x89fa, 0x0a, 0, 0}, ++ {0x89fb, 0xa2, 0, 0},{0x89fc, 0xaf, 0, 0},{0x89fd, 0x92, 0, 0}, ++ {0x89fe, 0x32, 0, 0},{0x89ff, 0xc2, 0, 0},{0x8a00, 0xaf, 0, 0}, ++ {0x8a01, 0xc2, 0, 0},{0x8a02, 0x33, 0, 0},{0x8a03, 0x12, 0, 0}, ++ {0x8a04, 0x01, 0, 0},{0x8a05, 0x6a, 0, 0},{0x8a06, 0x12, 0, 0}, ++ {0x8a07, 0x02, 0, 0},{0x8a08, 0x08, 0, 0},{0x8a09, 0x12, 0, 0}, ++ {0x8a0a, 0x01, 0, 0},{0x8a0b, 0x6a, 0, 0},{0x8a0c, 0x75, 0, 0}, ++ {0x8a0d, 0x51, 0, 0},{0x8a0e, 0x05, 0, 0},{0x8a0f, 0xaf, 0, 0}, ++ {0x8a10, 0x51, 0, 0},{0x8a11, 0x15, 0, 0},{0x8a12, 0x51, 0, 0}, ++ {0x8a13, 0xef, 0, 0},{0x8a14, 0x70, 0, 0},{0x8a15, 0xf9, 0, 0}, ++ {0x8a16, 0xd2, 0, 0},{0x8a17, 0x28, 0, 0},{0x8a18, 0x12, 0, 0}, ++ {0x8a19, 0x01, 0, 0},{0x8a1a, 0x6c, 0, 0},{0x8a1b, 0x75, 0, 0}, ++ {0x8a1c, 0x51, 0, 0},{0x8a1d, 0x0a, 0, 0},{0x8a1e, 0xaf, 0, 0}, ++ {0x8a1f, 0x51, 0, 0},{0x8a20, 0x15, 0, 0},{0x8a21, 0x51, 0, 0}, ++ {0x8a22, 0xef, 0, 0},{0x8a23, 0x70, 0, 0},{0x8a24, 0xf9, 0, 0}, ++ {0x8a25, 0xc2, 0, 0},{0x8a26, 0x29, 0, 0},{0x8a27, 0x12, 0, 0}, ++ {0x8a28, 0x01, 0, 0},{0x8a29, 0x6c, 0, 0},{0x8a2a, 0x75, 0, 0}, ++ {0x8a2b, 0x51, 0, 0},{0x8a2c, 0x05, 0, 0},{0x8a2d, 0xaf, 0, 0}, ++ {0x8a2e, 0x51, 0, 0},{0x8a2f, 0x15, 0, 0},{0x8a30, 0x51, 0, 0}, ++ {0x8a31, 0xef, 0, 0},{0x8a32, 0x70, 0, 0},{0x8a33, 0xf9, 0, 0}, ++ {0x8a34, 0xc2, 0, 0},{0x8a35, 0x28, 0, 0},{0x8a36, 0x12, 0, 0}, ++ {0x8a37, 0x01, 0, 0},{0x8a38, 0x6c, 0, 0},{0x8a39, 0x75, 0, 0}, ++ {0x8a3a, 0x51, 0, 0},{0x8a3b, 0x05, 0, 0},{0x8a3c, 0xaf, 0, 0}, ++ {0x8a3d, 0x51, 0, 0},{0x8a3e, 0x15, 0, 0},{0x8a3f, 0x51, 0, 0}, ++ {0x8a40, 0xef, 0, 0},{0x8a41, 0x70, 0, 0},{0x8a42, 0xf9, 0, 0}, ++ {0x8a43, 0x75, 0, 0},{0x8a44, 0x13, 0, 0},{0x8a45, 0x18, 0, 0}, ++ {0x8a46, 0x12, 0, 0},{0x8a47, 0x0b, 0, 0},{0x8a48, 0x38, 0, 0}, ++ {0x8a49, 0x75, 0, 0},{0x8a4a, 0x51, 0, 0},{0x8a4b, 0x0a, 0, 0}, ++ {0x8a4c, 0xaf, 0, 0},{0x8a4d, 0x51, 0, 0},{0x8a4e, 0x15, 0, 0}, ++ {0x8a4f, 0x51, 0, 0},{0x8a50, 0xef, 0, 0},{0x8a51, 0x70, 0, 0}, ++ {0x8a52, 0xf9, 0, 0},{0x8a53, 0xd2, 0, 0},{0x8a54, 0x28, 0, 0}, ++ {0x8a55, 0x12, 0, 0},{0x8a56, 0x01, 0, 0},{0x8a57, 0x6c, 0, 0}, ++ {0x8a58, 0x12, 0, 0},{0x8a59, 0x02, 0, 0},{0x8a5a, 0x25, 0, 0}, ++ {0x8a5b, 0xaf, 0, 0},{0x8a5c, 0x51, 0, 0},{0x8a5d, 0x15, 0, 0}, ++ {0x8a5e, 0x51, 0, 0},{0x8a5f, 0xef, 0, 0},{0x8a60, 0x70, 0, 0}, ++ {0x8a61, 0xf9, 0, 0},{0x8a62, 0xc2, 0, 0},{0x8a63, 0x28, 0, 0}, ++ {0x8a64, 0x12, 0, 0},{0x8a65, 0x01, 0, 0},{0x8a66, 0x6c, 0, 0}, ++ {0x8a67, 0x75, 0, 0},{0x8a68, 0x51, 0, 0},{0x8a69, 0x0a, 0, 0}, ++ {0x8a6a, 0xaf, 0, 0},{0x8a6b, 0x51, 0, 0},{0x8a6c, 0x15, 0, 0}, ++ {0x8a6d, 0x51, 0, 0},{0x8a6e, 0xef, 0, 0},{0x8a6f, 0x70, 0, 0}, ++ {0x8a70, 0xf9, 0, 0},{0x8a71, 0x30, 0, 0},{0x8a72, 0x11, 0, 0}, ++ {0x8a73, 0x03, 0, 0},{0x8a74, 0x02, 0, 0},{0x8a75, 0x0a, 0, 0}, ++ {0x8a76, 0xef, 0, 0},{0x8a77, 0x12, 0, 0},{0x8a78, 0x01, 0, 0}, ++ {0x8a79, 0x6a, 0, 0},{0x8a7a, 0x12, 0, 0},{0x8a7b, 0x02, 0, 0}, ++ {0x8a7c, 0x08, 0, 0},{0x8a7d, 0xe5, 0, 0},{0x8a7e, 0x10, 0, 0}, ++ {0x8a7f, 0xf5, 0, 0},{0x8a80, 0x13, 0, 0},{0x8a81, 0x12, 0, 0}, ++ {0x8a82, 0x0b, 0, 0},{0x8a83, 0x38, 0, 0},{0x8a84, 0x75, 0, 0}, ++ {0x8a85, 0x51, 0, 0},{0x8a86, 0x0a, 0, 0},{0x8a87, 0xaf, 0, 0}, ++ {0x8a88, 0x51, 0, 0},{0x8a89, 0x15, 0, 0},{0x8a8a, 0x51, 0, 0}, ++ {0x8a8b, 0xef, 0, 0},{0x8a8c, 0x70, 0, 0},{0x8a8d, 0xf9, 0, 0}, ++ {0x8a8e, 0xd2, 0, 0},{0x8a8f, 0x28, 0, 0},{0x8a90, 0x12, 0, 0}, ++ {0x8a91, 0x01, 0, 0},{0x8a92, 0x6c, 0, 0},{0x8a93, 0x12, 0, 0}, ++ {0x8a94, 0x02, 0, 0},{0x8a95, 0x25, 0, 0},{0x8a96, 0xaf, 0, 0}, ++ {0x8a97, 0x51, 0, 0},{0x8a98, 0x15, 0, 0},{0x8a99, 0x51, 0, 0}, ++ {0x8a9a, 0xef, 0, 0},{0x8a9b, 0x70, 0, 0},{0x8a9c, 0xf9, 0, 0}, ++ {0x8a9d, 0xc2, 0, 0},{0x8a9e, 0x28, 0, 0},{0x8a9f, 0x12, 0, 0}, ++ {0x8aa0, 0x01, 0, 0},{0x8aa1, 0x6c, 0, 0},{0x8aa2, 0x75, 0, 0}, ++ {0x8aa3, 0x51, 0, 0},{0x8aa4, 0x0a, 0, 0},{0x8aa5, 0xaf, 0, 0}, ++ {0x8aa6, 0x51, 0, 0},{0x8aa7, 0x15, 0, 0},{0x8aa8, 0x51, 0, 0}, ++ {0x8aa9, 0xef, 0, 0},{0x8aaa, 0x70, 0, 0},{0x8aab, 0xf9, 0, 0}, ++ {0x8aac, 0x30, 0, 0},{0x8aad, 0x11, 0, 0},{0x8aae, 0x04, 0, 0}, ++ {0x8aaf, 0x15, 0, 0},{0x8ab0, 0x12, 0, 0},{0x8ab1, 0x80, 0, 0}, ++ {0x8ab2, 0x45, 0, 0},{0x8ab3, 0x12, 0, 0},{0x8ab4, 0x01, 0, 0}, ++ {0x8ab5, 0x6a, 0, 0},{0x8ab6, 0x12, 0, 0},{0x8ab7, 0x02, 0, 0}, ++ {0x8ab8, 0x08, 0, 0},{0x8ab9, 0x85, 0, 0},{0x8aba, 0x11, 0, 0}, ++ {0x8abb, 0x13, 0, 0},{0x8abc, 0x12, 0, 0},{0x8abd, 0x13, 0, 0}, ++ {0x8abe, 0x72, 0, 0},{0x8abf, 0xc2, 0, 0},{0x8ac0, 0x09, 0, 0}, ++ {0x8ac1, 0x12, 0, 0},{0x8ac2, 0x02, 0, 0},{0x8ac3, 0x0a, 0, 0}, ++ {0x8ac4, 0x75, 0, 0},{0x8ac5, 0x51, 0, 0},{0x8ac6, 0x0a, 0, 0}, ++ {0x8ac7, 0xaf, 0, 0},{0x8ac8, 0x51, 0, 0},{0x8ac9, 0x15, 0, 0}, ++ {0x8aca, 0x51, 0, 0},{0x8acb, 0xef, 0, 0},{0x8acc, 0x70, 0, 0}, ++ {0x8acd, 0xf9, 0, 0},{0x8ace, 0xd2, 0, 0},{0x8acf, 0x28, 0, 0}, ++ {0x8ad0, 0x12, 0, 0},{0x8ad1, 0x01, 0, 0},{0x8ad2, 0x6c, 0, 0}, ++ {0x8ad3, 0x12, 0, 0},{0x8ad4, 0x02, 0, 0},{0x8ad5, 0x25, 0, 0}, ++ {0x8ad6, 0xaf, 0, 0},{0x8ad7, 0x51, 0, 0},{0x8ad8, 0x15, 0, 0}, ++ {0x8ad9, 0x51, 0, 0},{0x8ada, 0xef, 0, 0},{0x8adb, 0x70, 0, 0}, ++ {0x8adc, 0xf9, 0, 0},{0x8add, 0xc2, 0, 0},{0x8ade, 0x28, 0, 0}, ++ {0x8adf, 0x12, 0, 0},{0x8ae0, 0x01, 0, 0},{0x8ae1, 0x6c, 0, 0}, ++ {0x8ae2, 0x75, 0, 0},{0x8ae3, 0x51, 0, 0},{0x8ae4, 0x0a, 0, 0}, ++ {0x8ae5, 0xaf, 0, 0},{0x8ae6, 0x51, 0, 0},{0x8ae7, 0x15, 0, 0}, ++ {0x8ae8, 0x51, 0, 0},{0x8ae9, 0xef, 0, 0},{0x8aea, 0x70, 0, 0}, ++ {0x8aeb, 0xf9, 0, 0},{0x8aec, 0x30, 0, 0},{0x8aed, 0x11, 0, 0}, ++ {0x8aee, 0x06, 0, 0},{0x8aef, 0x15, 0, 0},{0x8af0, 0x12, 0, 0}, ++ {0x8af1, 0xd2, 0, 0},{0x8af2, 0x33, 0, 0},{0x8af3, 0x80, 0, 0}, ++ {0x8af4, 0x03, 0, 0},{0x8af5, 0xe4, 0, 0},{0x8af6, 0xf5, 0, 0}, ++ {0x8af7, 0x12, 0, 0},{0x8af8, 0x12, 0, 0},{0x8af9, 0x01, 0, 0}, ++ {0x8afa, 0x6a, 0, 0},{0x8afb, 0x12, 0, 0},{0x8afc, 0x02, 0, 0}, ++ {0x8afd, 0x08, 0, 0},{0x8afe, 0xc2, 0, 0},{0x8aff, 0x29, 0, 0}, ++ {0x8b00, 0x12, 0, 0},{0x8b01, 0x01, 0, 0},{0x8b02, 0x6c, 0, 0}, ++ {0x8b03, 0x75, 0, 0},{0x8b04, 0x51, 0, 0},{0x8b05, 0x05, 0, 0}, ++ {0x8b06, 0xaf, 0, 0},{0x8b07, 0x51, 0, 0},{0x8b08, 0x15, 0, 0}, ++ {0x8b09, 0x51, 0, 0},{0x8b0a, 0xef, 0, 0},{0x8b0b, 0x70, 0, 0}, ++ {0x8b0c, 0xf9, 0, 0},{0x8b0d, 0xd2, 0, 0},{0x8b0e, 0x28, 0, 0}, ++ {0x8b0f, 0x12, 0, 0},{0x8b10, 0x01, 0, 0},{0x8b11, 0x6c, 0, 0}, ++ {0x8b12, 0x75, 0, 0},{0x8b13, 0x51, 0, 0},{0x8b14, 0x05, 0, 0}, ++ {0x8b15, 0xaf, 0, 0},{0x8b16, 0x51, 0, 0},{0x8b17, 0x15, 0, 0}, ++ {0x8b18, 0x51, 0, 0},{0x8b19, 0xef, 0, 0},{0x8b1a, 0x70, 0, 0}, ++ {0x8b1b, 0xf9, 0, 0},{0x8b1c, 0x12, 0, 0},{0x8b1d, 0x01, 0, 0}, ++ {0x8b1e, 0x6a, 0, 0},{0x8b1f, 0x75, 0, 0},{0x8b20, 0x51, 0, 0}, ++ {0x8b21, 0x05, 0, 0},{0x8b22, 0xaf, 0, 0},{0x8b23, 0x51, 0, 0}, ++ {0x8b24, 0x15, 0, 0},{0x8b25, 0x51, 0, 0},{0x8b26, 0xef, 0, 0}, ++ {0x8b27, 0x70, 0, 0},{0x8b28, 0xf9, 0, 0},{0x8b29, 0xa2, 0, 0}, ++ {0x8b2a, 0x32, 0, 0},{0x8b2b, 0x92, 0, 0},{0x8b2c, 0xaf, 0, 0}, ++ {0x8b2d, 0xe5, 0, 0},{0x8b2e, 0x12, 0, 0},{0x8b2f, 0xd3, 0, 0}, ++ {0x8b30, 0x94, 0, 0},{0x8b31, 0x00, 0, 0},{0x8b32, 0x40, 0, 0}, ++ {0x8b33, 0x03, 0, 0},{0x8b34, 0x02, 0, 0},{0x8b35, 0x09, 0, 0}, ++ {0x8b36, 0xff, 0, 0},{0x8b37, 0x22, 0, 0},{0x8b38, 0x12, 0, 0}, ++ {0x8b39, 0x13, 0, 0},{0x8b3a, 0x72, 0, 0},{0x8b3b, 0xc2, 0, 0}, ++ {0x8b3c, 0x09, 0, 0},{0x8b3d, 0x90, 0, 0},{0x8b3e, 0x30, 0, 0}, ++ {0x8b3f, 0x18, 0, 0},{0x8b40, 0xe5, 0, 0},{0x8b41, 0x21, 0, 0}, ++ {0x8b42, 0xf0, 0, 0},{0x8b43, 0x22, 0, 0},{0x8b44, 0xc0, 0, 0}, ++ {0x8b45, 0xe0, 0, 0},{0x8b46, 0xc0, 0, 0},{0x8b47, 0xf0, 0, 0}, ++ {0x8b48, 0xc0, 0, 0},{0x8b49, 0x83, 0, 0},{0x8b4a, 0xc0, 0, 0}, ++ {0x8b4b, 0x82, 0, 0},{0x8b4c, 0xc0, 0, 0},{0x8b4d, 0xd0, 0, 0}, ++ {0x8b4e, 0x75, 0, 0},{0x8b4f, 0xd0, 0, 0},{0x8b50, 0x00, 0, 0}, ++ {0x8b51, 0xc0, 0, 0},{0x8b52, 0x00, 0, 0},{0x8b53, 0xc0, 0, 0}, ++ {0x8b54, 0x01, 0, 0},{0x8b55, 0xc0, 0, 0},{0x8b56, 0x02, 0, 0}, ++ {0x8b57, 0xc0, 0, 0},{0x8b58, 0x03, 0, 0},{0x8b59, 0xc0, 0, 0}, ++ {0x8b5a, 0x04, 0, 0},{0x8b5b, 0xc0, 0, 0},{0x8b5c, 0x05, 0, 0}, ++ {0x8b5d, 0xc0, 0, 0},{0x8b5e, 0x06, 0, 0},{0x8b5f, 0xc0, 0, 0}, ++ {0x8b60, 0x07, 0, 0},{0x8b61, 0x90, 0, 0},{0x8b62, 0x3f, 0, 0}, ++ {0x8b63, 0x0c, 0, 0},{0x8b64, 0xe0, 0, 0},{0x8b65, 0xf5, 0, 0}, ++ {0x8b66, 0x08, 0, 0},{0x8b67, 0xe5, 0, 0},{0x8b68, 0x08, 0, 0}, ++ {0x8b69, 0x20, 0, 0},{0x8b6a, 0xe3, 0, 0},{0x8b6b, 0x03, 0, 0}, ++ {0x8b6c, 0x02, 0, 0},{0x8b6d, 0x0b, 0, 0},{0x8b6e, 0xf5, 0, 0}, ++ {0x8b6f, 0x30, 0, 0},{0x8b70, 0x35, 0, 0},{0x8b71, 0x03, 0, 0}, ++ {0x8b72, 0x02, 0, 0},{0x8b73, 0x0b, 0, 0},{0x8b74, 0xf5, 0, 0}, ++ {0x8b75, 0x90, 0, 0},{0x8b76, 0x60, 0, 0},{0x8b77, 0x16, 0, 0}, ++ {0x8b78, 0xe0, 0, 0},{0x8b79, 0xf5, 0, 0},{0x8b7a, 0x69, 0, 0}, ++ {0x8b7b, 0xa3, 0, 0},{0x8b7c, 0xe0, 0, 0},{0x8b7d, 0xf5, 0, 0}, ++ {0x8b7e, 0x6a, 0, 0},{0x8b7f, 0x90, 0, 0},{0x8b80, 0x60, 0, 0}, ++ {0x8b81, 0x1e, 0, 0},{0x8b82, 0xe0, 0, 0},{0x8b83, 0xf5, 0, 0}, ++ {0x8b84, 0x6b, 0, 0},{0x8b85, 0xa3, 0, 0},{0x8b86, 0xe0, 0, 0}, ++ {0x8b87, 0xf5, 0, 0},{0x8b88, 0x6c, 0, 0},{0x8b89, 0x90, 0, 0}, ++ {0x8b8a, 0x60, 0, 0},{0x8b8b, 0x26, 0, 0},{0x8b8c, 0xe0, 0, 0}, ++ {0x8b8d, 0xf5, 0, 0},{0x8b8e, 0x6d, 0, 0},{0x8b8f, 0xa3, 0, 0}, ++ {0x8b90, 0xe0, 0, 0},{0x8b91, 0xf5, 0, 0},{0x8b92, 0x6e, 0, 0}, ++ {0x8b93, 0x90, 0, 0},{0x8b94, 0x60, 0, 0},{0x8b95, 0x2e, 0, 0}, ++ {0x8b96, 0xe0, 0, 0},{0x8b97, 0xf5, 0, 0},{0x8b98, 0x6f, 0, 0}, ++ {0x8b99, 0xa3, 0, 0},{0x8b9a, 0xe0, 0, 0},{0x8b9b, 0xf5, 0, 0}, ++ {0x8b9c, 0x70, 0, 0},{0x8b9d, 0x90, 0, 0},{0x8b9e, 0x60, 0, 0}, ++ {0x8b9f, 0x36, 0, 0},{0x8ba0, 0x12, 0, 0},{0x8ba1, 0x00, 0, 0}, ++ {0x8ba2, 0x16, 0, 0},{0x8ba3, 0x12, 0, 0},{0x8ba4, 0x01, 0, 0}, ++ {0x8ba5, 0xc8, 0, 0},{0x8ba6, 0x40, 0, 0},{0x8ba7, 0x06, 0, 0}, ++ {0x8ba8, 0x75, 0, 0},{0x8ba9, 0x2a, 0, 0},{0x8baa, 0xff, 0, 0}, ++ {0x8bab, 0x75, 0, 0},{0x8bac, 0x2b, 0, 0},{0x8bad, 0xff, 0, 0}, ++ {0x8bae, 0x85, 0, 0},{0x8baf, 0x2a, 0, 0},{0x8bb0, 0x73, 0, 0}, ++ {0x8bb1, 0x85, 0, 0},{0x8bb2, 0x2b, 0, 0},{0x8bb3, 0x74, 0, 0}, ++ {0x8bb4, 0x90, 0, 0},{0x8bb5, 0x60, 0, 0},{0x8bb6, 0x1a, 0, 0}, ++ {0x8bb7, 0xe0, 0, 0},{0x8bb8, 0xf5, 0, 0},{0x8bb9, 0x69, 0, 0}, ++ {0x8bba, 0xa3, 0, 0},{0x8bbb, 0xe0, 0, 0},{0x8bbc, 0xf5, 0, 0}, ++ {0x8bbd, 0x6a, 0, 0},{0x8bbe, 0x90, 0, 0},{0x8bbf, 0x60, 0, 0}, ++ {0x8bc0, 0x22, 0, 0},{0x8bc1, 0xe0, 0, 0},{0x8bc2, 0xf5, 0, 0}, ++ {0x8bc3, 0x6b, 0, 0},{0x8bc4, 0xa3, 0, 0},{0x8bc5, 0xe0, 0, 0}, ++ {0x8bc6, 0xf5, 0, 0},{0x8bc7, 0x6c, 0, 0},{0x8bc8, 0x90, 0, 0}, ++ {0x8bc9, 0x60, 0, 0},{0x8bca, 0x2a, 0, 0},{0x8bcb, 0xe0, 0, 0}, ++ {0x8bcc, 0xf5, 0, 0},{0x8bcd, 0x6d, 0, 0},{0x8bce, 0xa3, 0, 0}, ++ {0x8bcf, 0xe0, 0, 0},{0x8bd0, 0xf5, 0, 0},{0x8bd1, 0x6e, 0, 0}, ++ {0x8bd2, 0x90, 0, 0},{0x8bd3, 0x60, 0, 0},{0x8bd4, 0x32, 0, 0}, ++ {0x8bd5, 0xe0, 0, 0},{0x8bd6, 0xf5, 0, 0},{0x8bd7, 0x6f, 0, 0}, ++ {0x8bd8, 0xa3, 0, 0},{0x8bd9, 0xe0, 0, 0},{0x8bda, 0xf5, 0, 0}, ++ {0x8bdb, 0x70, 0, 0},{0x8bdc, 0x90, 0, 0},{0x8bdd, 0x60, 0, 0}, ++ {0x8bde, 0x3a, 0, 0},{0x8bdf, 0x12, 0, 0},{0x8be0, 0x00, 0, 0}, ++ {0x8be1, 0x16, 0, 0},{0x8be2, 0x12, 0, 0},{0x8be3, 0x01, 0, 0}, ++ {0x8be4, 0xc8, 0, 0},{0x8be5, 0x40, 0, 0},{0x8be6, 0x06, 0, 0}, ++ {0x8be7, 0x75, 0, 0},{0x8be8, 0x2a, 0, 0},{0x8be9, 0xff, 0, 0}, ++ {0x8bea, 0x75, 0, 0},{0x8beb, 0x2b, 0, 0},{0x8bec, 0xff, 0, 0}, ++ {0x8bed, 0x85, 0, 0},{0x8bee, 0x2a, 0, 0},{0x8bef, 0x75, 0, 0}, ++ {0x8bf0, 0x85, 0, 0},{0x8bf1, 0x2b, 0, 0},{0x8bf2, 0x76, 0, 0}, ++ {0x8bf3, 0xd2, 0, 0},{0x8bf4, 0x3b, 0, 0},{0x8bf5, 0xe5, 0, 0}, ++ {0x8bf6, 0x08, 0, 0},{0x8bf7, 0x30, 0, 0},{0x8bf8, 0xe5, 0, 0}, ++ {0x8bf9, 0x41, 0, 0},{0x8bfa, 0x90, 0, 0},{0x8bfb, 0x56, 0, 0}, ++ {0x8bfc, 0x90, 0, 0},{0x8bfd, 0xe0, 0, 0},{0x8bfe, 0xf5, 0, 0}, ++ {0x8bff, 0x55, 0, 0},{0x8c00, 0xe5, 0, 0},{0x8c01, 0x7a, 0, 0}, ++ {0x8c02, 0x12, 0, 0},{0x8c03, 0x01, 0, 0},{0x8c04, 0xc1, 0, 0}, ++ {0x8c05, 0xad, 0, 0},{0x8c06, 0x55, 0, 0},{0x8c07, 0xc3, 0, 0}, ++ {0x8c08, 0xef, 0, 0},{0x8c09, 0x9d, 0, 0},{0x8c0a, 0x74, 0, 0}, ++ {0x8c0b, 0x80, 0, 0},{0x8c0c, 0xf8, 0, 0},{0x8c0d, 0x6e, 0, 0}, ++ {0x8c0e, 0x98, 0, 0},{0x8c0f, 0x50, 0, 0},{0x8c10, 0x02, 0, 0}, ++ {0x8c11, 0x80, 0, 0},{0x8c12, 0x01, 0, 0},{0x8c13, 0xc3, 0, 0}, ++ {0x8c14, 0x92, 0, 0},{0x8c15, 0x27, 0, 0},{0x8c16, 0xaf, 0, 0}, ++ {0x8c17, 0x55, 0, 0},{0x8c18, 0xef, 0, 0},{0x8c19, 0x24, 0, 0}, ++ {0x8c1a, 0x01, 0, 0},{0x8c1b, 0xff, 0, 0},{0x8c1c, 0xe4, 0, 0}, ++ {0x8c1d, 0x33, 0, 0},{0x8c1e, 0xfe, 0, 0},{0x8c1f, 0xc3, 0, 0}, ++ {0x8c20, 0xef, 0, 0},{0x8c21, 0x95, 0, 0},{0x8c22, 0x7a, 0, 0}, ++ {0x8c23, 0x74, 0, 0},{0x8c24, 0x80, 0, 0},{0x8c25, 0xf8, 0, 0}, ++ {0x8c26, 0x6e, 0, 0},{0x8c27, 0x98, 0, 0},{0x8c28, 0x50, 0, 0}, ++ {0x8c29, 0x02, 0, 0},{0x8c2a, 0x80, 0, 0},{0x8c2b, 0x02, 0, 0}, ++ {0x8c2c, 0xa2, 0, 0},{0x8c2d, 0x27, 0, 0},{0x8c2e, 0x92, 0, 0}, ++ {0x8c2f, 0x27, 0, 0},{0x8c30, 0x30, 0, 0},{0x8c31, 0x27, 0, 0}, ++ {0x8c32, 0x04, 0, 0},{0x8c33, 0xaf, 0, 0},{0x8c34, 0x55, 0, 0}, ++ {0x8c35, 0x80, 0, 0},{0x8c36, 0x02, 0, 0},{0x8c37, 0xaf, 0, 0}, ++ {0x8c38, 0x7a, 0, 0},{0x8c39, 0x8f, 0, 0},{0x8c3a, 0x7a, 0, 0}, ++ {0x8c3b, 0xe5, 0, 0},{0x8c3c, 0x08, 0, 0},{0x8c3d, 0x30, 0, 0}, ++ {0x8c3e, 0xe1, 0, 0},{0x8c3f, 0x08, 0, 0},{0x8c40, 0x90, 0, 0}, ++ {0x8c41, 0x30, 0, 0},{0x8c42, 0x24, 0, 0},{0x8c43, 0xe0, 0, 0}, ++ {0x8c44, 0xf5, 0, 0},{0x8c45, 0x33, 0, 0},{0x8c46, 0xe4, 0, 0}, ++ {0x8c47, 0xf0, 0, 0},{0x8c48, 0x90, 0, 0},{0x8c49, 0x3f, 0, 0}, ++ {0x8c4a, 0x0c, 0, 0},{0x8c4b, 0xe5, 0, 0},{0x8c4c, 0x08, 0, 0}, ++ {0x8c4d, 0xf0, 0, 0},{0x8c4e, 0xd0, 0, 0},{0x8c4f, 0x07, 0, 0}, ++ {0x8c50, 0xd0, 0, 0},{0x8c51, 0x06, 0, 0},{0x8c52, 0xd0, 0, 0}, ++ {0x8c53, 0x05, 0, 0},{0x8c54, 0xd0, 0, 0},{0x8c55, 0x04, 0, 0}, ++ {0x8c56, 0xd0, 0, 0},{0x8c57, 0x03, 0, 0},{0x8c58, 0xd0, 0, 0}, ++ {0x8c59, 0x02, 0, 0},{0x8c5a, 0xd0, 0, 0},{0x8c5b, 0x01, 0, 0}, ++ {0x8c5c, 0xd0, 0, 0},{0x8c5d, 0x00, 0, 0},{0x8c5e, 0xd0, 0, 0}, ++ {0x8c5f, 0xd0, 0, 0},{0x8c60, 0xd0, 0, 0},{0x8c61, 0x82, 0, 0}, ++ {0x8c62, 0xd0, 0, 0},{0x8c63, 0x83, 0, 0},{0x8c64, 0xd0, 0, 0}, ++ {0x8c65, 0xf0, 0, 0},{0x8c66, 0xd0, 0, 0},{0x8c67, 0xe0, 0, 0}, ++ {0x8c68, 0x32, 0, 0},{0x8c69, 0xe5, 0, 0},{0x8c6a, 0x33, 0, 0}, ++ {0x8c6b, 0x70, 0, 0},{0x8c6c, 0x03, 0, 0},{0x8c6d, 0x02, 0, 0}, ++ {0x8c6e, 0x0d, 0, 0},{0x8c6f, 0x76, 0, 0},{0x8c70, 0xc2, 0, 0}, ++ {0x8c71, 0xaf, 0, 0},{0x8c72, 0xaf, 0, 0},{0x8c73, 0x33, 0, 0}, ++ {0x8c74, 0xe4, 0, 0},{0x8c75, 0xf5, 0, 0},{0x8c76, 0x33, 0, 0}, ++ {0x8c77, 0xd2, 0, 0},{0x8c78, 0xaf, 0, 0},{0x8c79, 0x90, 0, 0}, ++ {0x8c7a, 0x30, 0, 0},{0x8c7b, 0x25, 0, 0},{0x8c7c, 0xe0, 0, 0}, ++ {0x8c7d, 0xf5, 0, 0},{0x8c7e, 0x7d, 0, 0},{0x8c7f, 0x90, 0, 0}, ++ {0x8c80, 0x50, 0, 0},{0x8c81, 0x82, 0, 0},{0x8c82, 0xe0, 0, 0}, ++ {0x8c83, 0xf5, 0, 0},{0x8c84, 0x65, 0, 0},{0x8c85, 0xa3, 0, 0}, ++ {0x8c86, 0xe0, 0, 0},{0x8c87, 0xf5, 0, 0},{0x8c88, 0x66, 0, 0}, ++ {0x8c89, 0xa3, 0, 0},{0x8c8a, 0xe0, 0, 0},{0x8c8b, 0xf5, 0, 0}, ++ {0x8c8c, 0x67, 0, 0},{0x8c8d, 0xa3, 0, 0},{0x8c8e, 0xe0, 0, 0}, ++ {0x8c8f, 0xf5, 0, 0},{0x8c90, 0x68, 0, 0},{0x8c91, 0xef, 0, 0}, ++ {0x8c92, 0x12, 0, 0},{0x8c93, 0x09, 0, 0},{0x8c94, 0xd2, 0, 0}, ++ {0x8c95, 0x0c, 0, 0},{0x8c96, 0xba, 0, 0},{0x8c97, 0x03, 0, 0}, ++ {0x8c98, 0x0c, 0, 0},{0x8c99, 0xcf, 0, 0},{0x8c9a, 0x05, 0, 0}, ++ {0x8c9b, 0x0c, 0, 0},{0x8c9c, 0xf9, 0, 0},{0x8c9d, 0x06, 0, 0}, ++ {0x8c9e, 0x0c, 0, 0},{0x8c9f, 0xe7, 0, 0},{0x8ca0, 0x08, 0, 0}, ++ {0x8ca1, 0x0d, 0, 0},{0x8ca2, 0x06, 0, 0},{0x8ca3, 0x10, 0, 0}, ++ {0x8ca4, 0x0d, 0, 0},{0x8ca5, 0x1a, 0, 0},{0x8ca6, 0x12, 0, 0}, ++ {0x8ca7, 0x0d, 0, 0},{0x8ca8, 0x1f, 0, 0},{0x8ca9, 0x20, 0, 0}, ++ {0x8caa, 0x0d, 0, 0},{0x8cab, 0x2d, 0, 0},{0x8cac, 0x21, 0, 0}, ++ {0x8cad, 0x0d, 0, 0},{0x8cae, 0x32, 0, 0},{0x8caf, 0x30, 0, 0}, ++ {0x8cb0, 0x0d, 0, 0},{0x8cb1, 0x5b, 0, 0},{0x8cb2, 0x50, 0, 0}, ++ {0x8cb3, 0x0d, 0, 0},{0x8cb4, 0x3d, 0, 0},{0x8cb5, 0xd8, 0, 0}, ++ {0x8cb6, 0x00, 0, 0},{0x8cb7, 0x00, 0, 0},{0x8cb8, 0x0d, 0, 0}, ++ {0x8cb9, 0x68, 0, 0},{0x8cba, 0x20, 0, 0},{0x8cbb, 0x05, 0, 0}, ++ {0x8cbc, 0x03, 0, 0},{0x8cbd, 0x02, 0, 0},{0x8cbe, 0x0d, 0, 0}, ++ {0x8cbf, 0x68, 0, 0},{0x8cc0, 0x30, 0, 0},{0x8cc1, 0x00, 0, 0}, ++ {0x8cc2, 0x03, 0, 0},{0x8cc3, 0x02, 0, 0},{0x8cc4, 0x0d, 0, 0}, ++ {0x8cc5, 0x68, 0, 0},{0x8cc6, 0xd2, 0, 0},{0x8cc7, 0x07, 0, 0}, ++ {0x8cc8, 0xc2, 0, 0},{0x8cc9, 0x06, 0, 0},{0x8cca, 0x12, 0, 0}, ++ {0x8ccb, 0x02, 0, 0},{0x8ccc, 0x90, 0, 0},{0x8ccd, 0x80, 0, 0}, ++ {0x8cce, 0x24, 0, 0},{0x8ccf, 0x20, 0, 0},{0x8cd0, 0x05, 0, 0}, ++ {0x8cd1, 0x03, 0, 0},{0x8cd2, 0x02, 0, 0},{0x8cd3, 0x0d, 0, 0}, ++ {0x8cd4, 0x68, 0, 0},{0x8cd5, 0x30, 0, 0},{0x8cd6, 0x00, 0, 0}, ++ {0x8cd7, 0x03, 0, 0},{0x8cd8, 0x02, 0, 0},{0x8cd9, 0x0d, 0, 0}, ++ {0x8cda, 0x68, 0, 0},{0x8cdb, 0xc2, 0, 0},{0x8cdc, 0x07, 0, 0}, ++ {0x8cdd, 0xd2, 0, 0},{0x8cde, 0x06, 0, 0},{0x8cdf, 0x12, 0, 0}, ++ {0x8ce0, 0x02, 0, 0},{0x8ce1, 0xa5, 0, 0},{0x8ce2, 0xc2, 0, 0}, ++ {0x8ce3, 0x04, 0, 0},{0x8ce4, 0x02, 0, 0},{0x8ce5, 0x0d, 0, 0}, ++ {0x8ce6, 0x68, 0, 0},{0x8ce7, 0x12, 0, 0},{0x8ce8, 0x02, 0, 0}, ++ {0x8ce9, 0x40, 0, 0},{0x8cea, 0x30, 0, 0},{0x8ceb, 0x05, 0, 0}, ++ {0x8cec, 0x06, 0, 0},{0x8ced, 0xe4, 0, 0},{0x8cee, 0xf5, 0, 0}, ++ {0x8cef, 0x0c, 0, 0},{0x8cf0, 0x12, 0, 0},{0x8cf1, 0x0f, 0, 0}, ++ {0x8cf2, 0x11, 0, 0},{0x8cf3, 0xc2, 0, 0},{0x8cf4, 0x31, 0, 0}, ++ {0x8cf5, 0xd2, 0, 0},{0x8cf6, 0x34, 0, 0},{0x8cf7, 0x80, 0, 0}, ++ {0x8cf8, 0x6f, 0, 0},{0x8cf9, 0x30, 0, 0},{0x8cfa, 0x07, 0, 0}, ++ {0x8cfb, 0x6c, 0, 0},{0x8cfc, 0x30, 0, 0},{0x8cfd, 0x06, 0, 0}, ++ {0x8cfe, 0x69, 0, 0},{0x8cff, 0x12, 0, 0},{0x8d00, 0x02, 0, 0}, ++ {0x8d01, 0x90, 0, 0},{0x8d02, 0xd2, 0, 0},{0x8d03, 0x31, 0, 0}, ++ {0x8d04, 0x80, 0, 0},{0x8d05, 0x62, 0, 0},{0x8d06, 0x20, 0, 0}, ++ {0x8d07, 0x07, 0, 0},{0x8d08, 0x03, 0, 0},{0x8d09, 0x30, 0, 0}, ++ {0x8d0a, 0x06, 0, 0},{0x8d0b, 0x09, 0, 0},{0x8d0c, 0xe5, 0, 0}, ++ {0x8d0d, 0x7d, 0, 0},{0x8d0e, 0x64, 0, 0},{0x8d0f, 0x0e, 0, 0}, ++ {0x8d10, 0x70, 0, 0},{0x8d11, 0x56, 0, 0},{0x8d12, 0x20, 0, 0}, ++ {0x8d13, 0x00, 0, 0},{0x8d14, 0x53, 0, 0},{0x8d15, 0x12, 0, 0}, ++ {0x8d16, 0x05, 0, 0},{0x8d17, 0x16, 0, 0},{0x8d18, 0x80, 0, 0}, ++ {0x8d19, 0x4e, 0, 0},{0x8d1a, 0x12, 0, 0},{0x8d1b, 0x06, 0, 0}, ++ {0x8d1c, 0xdf, 0, 0},{0x8d1d, 0x80, 0, 0},{0x8d1e, 0x49, 0, 0}, ++ {0x8d1f, 0x30, 0, 0},{0x8d20, 0x05, 0, 0},{0x8d21, 0x46, 0, 0}, ++ {0x8d22, 0x20, 0, 0},{0x8d23, 0x07, 0, 0},{0x8d24, 0x43, 0, 0}, ++ {0x8d25, 0x20, 0, 0},{0x8d26, 0x06, 0, 0},{0x8d27, 0x40, 0, 0}, ++ {0x8d28, 0x12, 0, 0},{0x8d29, 0x15, 0, 0},{0x8d2a, 0x4c, 0, 0}, ++ {0x8d2b, 0x80, 0, 0},{0x8d2c, 0x3b, 0, 0},{0x8d2d, 0x12, 0, 0}, ++ {0x8d2e, 0x11, 0, 0},{0x8d2f, 0x7d, 0, 0},{0x8d30, 0x80, 0, 0}, ++ {0x8d31, 0x36, 0, 0},{0x8d32, 0x20, 0, 0},{0x8d33, 0x07, 0, 0}, ++ {0x8d34, 0x33, 0, 0},{0x8d35, 0x20, 0, 0},{0x8d36, 0x06, 0, 0}, ++ {0x8d37, 0x30, 0, 0},{0x8d38, 0x12, 0, 0},{0x8d39, 0x15, 0, 0}, ++ {0x8d3a, 0x5b, 0, 0},{0x8d3b, 0x80, 0, 0},{0x8d3c, 0x2b, 0, 0}, ++ {0x8d3d, 0xe5, 0, 0},{0x8d3e, 0x7d, 0, 0},{0x8d3f, 0x64, 0, 0}, ++ {0x8d40, 0x01, 0, 0},{0x8d41, 0x70, 0, 0},{0x8d42, 0x25, 0, 0}, ++ {0x8d43, 0xd2, 0, 0},{0x8d44, 0x35, 0, 0},{0x8d45, 0x90, 0, 0}, ++ {0x8d46, 0x50, 0, 0},{0x8d47, 0x82, 0, 0},{0x8d48, 0xe5, 0, 0}, ++ {0x8d49, 0x73, 0, 0},{0x8d4a, 0xf0, 0, 0},{0x8d4b, 0xa3, 0, 0}, ++ {0x8d4c, 0xe5, 0, 0},{0x8d4d, 0x74, 0, 0},{0x8d4e, 0xf0, 0, 0}, ++ {0x8d4f, 0xa3, 0, 0},{0x8d50, 0xe5, 0, 0},{0x8d51, 0x75, 0, 0}, ++ {0x8d52, 0xf0, 0, 0},{0x8d53, 0xa3, 0, 0},{0x8d54, 0xe5, 0, 0}, ++ {0x8d55, 0x76, 0, 0},{0x8d56, 0xf0, 0, 0},{0x8d57, 0xc2, 0, 0}, ++ {0x8d58, 0x35, 0, 0},{0x8d59, 0x80, 0, 0},{0x8d5a, 0x0d, 0, 0}, ++ {0x8d5b, 0x90, 0, 0},{0x8d5c, 0x50, 0, 0},{0x8d5d, 0x82, 0, 0}, ++ {0x8d5e, 0x30, 0, 0},{0x8d5f, 0x33, 0, 0},{0x8d60, 0x05, 0, 0}, ++ {0x8d61, 0x74, 0, 0},{0x8d62, 0x55, 0, 0},{0x8d63, 0xf0, 0, 0}, ++ {0x8d64, 0x80, 0, 0},{0x8d65, 0x02, 0, 0},{0x8d66, 0xe4, 0, 0}, ++ {0x8d67, 0xf0, 0, 0},{0x8d68, 0x20, 0, 0},{0x8d69, 0x07, 0, 0}, ++ {0x8d6a, 0x06, 0, 0},{0x8d6b, 0x30, 0, 0},{0x8d6c, 0x06, 0, 0}, ++ {0x8d6d, 0x03, 0, 0},{0x8d6e, 0x30, 0, 0},{0x8d6f, 0x04, 0, 0}, ++ {0x8d70, 0x05, 0, 0},{0x8d71, 0x90, 0, 0},{0x8d72, 0x30, 0, 0}, ++ {0x8d73, 0x25, 0, 0},{0x8d74, 0xe4, 0, 0},{0x8d75, 0xf0, 0, 0}, ++ {0x8d76, 0x22, 0, 0},{0x8d77, 0x30, 0, 0},{0x8d78, 0x04, 0, 0}, ++ {0x8d79, 0x03, 0, 0},{0x8d7a, 0x02, 0, 0},{0x8d7b, 0x0e, 0, 0}, ++ {0x8d7c, 0x62, 0, 0},{0x8d7d, 0xd2, 0, 0},{0x8d7e, 0x04, 0, 0}, ++ {0x8d7f, 0xe5, 0, 0},{0x8d80, 0x7d, 0, 0},{0x8d81, 0xb4, 0, 0}, ++ {0x8d82, 0x01, 0, 0},{0x8d83, 0x06, 0, 0},{0x8d84, 0x12, 0, 0}, ++ {0x8d85, 0x15, 0, 0},{0x8d86, 0x2c, 0, 0},{0x8d87, 0x02, 0, 0}, ++ {0x8d88, 0x0e, 0, 0},{0x8d89, 0x5b, 0, 0},{0x8d8a, 0xe5, 0, 0}, ++ {0x8d8b, 0x7d, 0, 0},{0x8d8c, 0xb4, 0, 0},{0x8d8d, 0x02, 0, 0}, ++ {0x8d8e, 0x06, 0, 0},{0x8d8f, 0x12, 0, 0},{0x8d90, 0x15, 0, 0}, ++ {0x8d91, 0x3d, 0, 0},{0x8d92, 0x02, 0, 0},{0x8d93, 0x0e, 0, 0}, ++ {0x8d94, 0x5b, 0, 0},{0x8d95, 0xe5, 0, 0},{0x8d96, 0x7d, 0, 0}, ++ {0x8d97, 0xb4, 0, 0},{0x8d98, 0x03, 0, 0},{0x8d99, 0x05, 0, 0}, ++ {0x8d9a, 0xe4, 0, 0},{0x8d9b, 0xf5, 0, 0},{0x8d9c, 0x0c, 0, 0}, ++ {0x8d9d, 0x80, 0, 0},{0x8d9e, 0x08, 0, 0},{0x8d9f, 0xe5, 0, 0}, ++ {0x8da0, 0x7d, 0, 0},{0x8da1, 0xb4, 0, 0},{0x8da2, 0x04, 0, 0}, ++ {0x8da3, 0x09, 0, 0},{0x8da4, 0x85, 0, 0},{0x8da5, 0x7b, 0, 0}, ++ {0x8da6, 0x0c, 0, 0},{0x8da7, 0x12, 0, 0},{0x8da8, 0x0f, 0, 0}, ++ {0x8da9, 0x11, 0, 0},{0x8daa, 0x02, 0, 0},{0x8dab, 0x0e, 0, 0}, ++ {0x8dac, 0x5b, 0, 0},{0x8dad, 0xe5, 0, 0},{0x8dae, 0x7d, 0, 0}, ++ {0x8daf, 0x64, 0, 0},{0x8db0, 0x0f, 0, 0},{0x8db1, 0x70, 0, 0}, ++ {0x8db2, 0x1f, 0, 0},{0x8db3, 0x12, 0, 0},{0x8db4, 0x02, 0, 0}, ++ {0x8db5, 0xac, 0, 0},{0x8db6, 0x40, 0, 0},{0x8db7, 0x06, 0, 0}, ++ {0x8db8, 0x7e, 0, 0},{0x8db9, 0x00, 0, 0},{0x8dba, 0x7f, 0, 0}, ++ {0x8dbb, 0xff, 0, 0},{0x8dbc, 0x80, 0, 0},{0x8dbd, 0x04, 0, 0}, ++ {0x8dbe, 0xae, 0, 0},{0x8dbf, 0x67, 0, 0},{0x8dc0, 0xaf, 0, 0}, ++ {0x8dc1, 0x68, 0, 0},{0x8dc2, 0x12, 0, 0},{0x8dc3, 0x02, 0, 0}, ++ {0x8dc4, 0x58, 0, 0},{0x8dc5, 0xc3, 0, 0},{0x8dc6, 0x33, 0, 0}, ++ {0x8dc7, 0xce, 0, 0},{0x8dc8, 0x33, 0, 0},{0x8dc9, 0xce, 0, 0}, ++ {0x8dca, 0xd8, 0, 0},{0x8dcb, 0xf9, 0, 0},{0x8dcc, 0x12, 0, 0}, ++ {0x8dcd, 0x0e, 0, 0},{0x8dce, 0x63, 0, 0},{0x8dcf, 0x02, 0, 0}, ++ {0x8dd0, 0x0e, 0, 0},{0x8dd1, 0x5b, 0, 0},{0x8dd2, 0xe5, 0, 0}, ++ {0x8dd3, 0x7d, 0, 0},{0x8dd4, 0x64, 0, 0},{0x8dd5, 0x10, 0, 0}, ++ {0x8dd6, 0x60, 0, 0},{0x8dd7, 0x03, 0, 0},{0x8dd8, 0x02, 0, 0}, ++ {0x8dd9, 0x0e, 0, 0},{0x8dda, 0x5b, 0, 0},{0x8ddb, 0xf5, 0, 0}, ++ {0x8ddc, 0x65, 0, 0},{0x8ddd, 0xf5, 0, 0},{0x8dde, 0x66, 0, 0}, ++ {0x8ddf, 0xf5, 0, 0},{0x8de0, 0x67, 0, 0},{0x8de1, 0xab, 0, 0}, ++ {0x8de2, 0x68, 0, 0},{0x8de3, 0xaa, 0, 0},{0x8de4, 0x67, 0, 0}, ++ {0x8de5, 0xa9, 0, 0},{0x8de6, 0x66, 0, 0},{0x8de7, 0xa8, 0, 0}, ++ {0x8de8, 0x65, 0, 0},{0x8de9, 0x12, 0, 0},{0x8dea, 0x01, 0, 0}, ++ {0x8deb, 0xa0, 0, 0},{0x8dec, 0xfe, 0, 0},{0x8ded, 0xe4, 0, 0}, ++ {0x8dee, 0xfc, 0, 0},{0x8def, 0xfd, 0, 0},{0x8df0, 0x12, 0, 0}, ++ {0x8df1, 0x01, 0, 0},{0x8df2, 0xe7, 0, 0},{0x8df3, 0xe4, 0, 0}, ++ {0x8df4, 0x7b, 0, 0},{0x8df5, 0xff, 0, 0},{0x8df6, 0xfa, 0, 0}, ++ {0x8df7, 0xf9, 0, 0},{0x8df8, 0xf8, 0, 0},{0x8df9, 0x12, 0, 0}, ++ {0x8dfa, 0x02, 0, 0},{0x8dfb, 0x6d, 0, 0},{0x8dfc, 0x85, 0, 0}, ++ {0x8dfd, 0x49, 0, 0},{0x8dfe, 0x82, 0, 0},{0x8dff, 0x85, 0, 0}, ++ {0x8e00, 0x48, 0, 0},{0x8e01, 0x83, 0, 0},{0x8e02, 0xe4, 0, 0}, ++ {0x8e03, 0x93, 0, 0},{0x8e04, 0xff, 0, 0},{0x8e05, 0xe4, 0, 0}, ++ {0x8e06, 0xfc, 0, 0},{0x8e07, 0xfd, 0, 0},{0x8e08, 0xfe, 0, 0}, ++ {0x8e09, 0xe5, 0, 0},{0x8e0a, 0x68, 0, 0},{0x8e0b, 0x2f, 0, 0}, ++ {0x8e0c, 0xf5, 0, 0},{0x8e0d, 0x68, 0, 0},{0x8e0e, 0xee, 0, 0}, ++ {0x8e0f, 0x35, 0, 0},{0x8e10, 0x67, 0, 0},{0x8e11, 0xf5, 0, 0}, ++ {0x8e12, 0x67, 0, 0},{0x8e13, 0xed, 0, 0},{0x8e14, 0x35, 0, 0}, ++ {0x8e15, 0x66, 0, 0},{0x8e16, 0xf5, 0, 0},{0x8e17, 0x66, 0, 0}, ++ {0x8e18, 0xec, 0, 0},{0x8e19, 0x35, 0, 0},{0x8e1a, 0x65, 0, 0}, ++ {0x8e1b, 0xf5, 0, 0},{0x8e1c, 0x65, 0, 0},{0x8e1d, 0x12, 0, 0}, ++ {0x8e1e, 0x02, 0, 0},{0x8e1f, 0xac, 0, 0},{0x8e20, 0x40, 0, 0}, ++ {0x8e21, 0x04, 0, 0},{0x8e22, 0x7f, 0, 0},{0x8e23, 0xff, 0, 0}, ++ {0x8e24, 0x80, 0, 0},{0x8e25, 0x04, 0, 0},{0x8e26, 0xae, 0, 0}, ++ {0x8e27, 0x67, 0, 0},{0x8e28, 0xaf, 0, 0},{0x8e29, 0x68, 0, 0}, ++ {0x8e2a, 0x12, 0, 0},{0x8e2b, 0x02, 0, 0},{0x8e2c, 0x58, 0, 0}, ++ {0x8e2d, 0xc3, 0, 0},{0x8e2e, 0x33, 0, 0},{0x8e2f, 0xce, 0, 0}, ++ {0x8e30, 0x33, 0, 0},{0x8e31, 0xce, 0, 0},{0x8e32, 0xd8, 0, 0}, ++ {0x8e33, 0xf9, 0, 0},{0x8e34, 0x12, 0, 0},{0x8e35, 0x0e, 0, 0}, ++ {0x8e36, 0x63, 0, 0},{0x8e37, 0xe4, 0, 0},{0x8e38, 0xf5, 0, 0}, ++ {0x8e39, 0x66, 0, 0},{0x8e3a, 0xf5, 0, 0},{0x8e3b, 0x66, 0, 0}, ++ {0x8e3c, 0xe5, 0, 0},{0x8e3d, 0x66, 0, 0},{0x8e3e, 0xd3, 0, 0}, ++ {0x8e3f, 0x95, 0, 0},{0x8e40, 0x7b, 0, 0},{0x8e41, 0x50, 0, 0}, ++ {0x8e42, 0x15, 0, 0},{0x8e43, 0xaf, 0, 0},{0x8e44, 0x66, 0, 0}, ++ {0x8e45, 0xe5, 0, 0},{0x8e46, 0x49, 0, 0},{0x8e47, 0x2f, 0, 0}, ++ {0x8e48, 0x12, 0, 0},{0x8e49, 0x02, 0, 0},{0x8e4a, 0x4f, 0, 0}, ++ {0x8e4b, 0x93, 0, 0},{0x8e4c, 0xc3, 0, 0},{0x8e4d, 0x95, 0, 0}, ++ {0x8e4e, 0x68, 0, 0},{0x8e4f, 0xe4, 0, 0},{0x8e50, 0x95, 0, 0}, ++ {0x8e51, 0x67, 0, 0},{0x8e52, 0x50, 0, 0},{0x8e53, 0x04, 0, 0}, ++ {0x8e54, 0x05, 0, 0},{0x8e55, 0x66, 0, 0},{0x8e56, 0x80, 0, 0}, ++ {0x8e57, 0xe4, 0, 0},{0x8e58, 0x85, 0, 0},{0x8e59, 0x66, 0, 0}, ++ {0x8e5a, 0x7c, 0, 0},{0x8e5b, 0x90, 0, 0},{0x8e5c, 0x30, 0, 0}, ++ {0x8e5d, 0x25, 0, 0},{0x8e5e, 0xe4, 0, 0},{0x8e5f, 0xf0, 0, 0}, ++ {0x8e60, 0xd2, 0, 0},{0x8e61, 0x34, 0, 0},{0x8e62, 0x22, 0, 0}, ++ {0x8e63, 0xf5, 0, 0},{0x8e64, 0x68, 0, 0},{0x8e65, 0x8e, 0, 0}, ++ {0x8e66, 0x67, 0, 0},{0x8e67, 0x85, 0, 0},{0x8e68, 0x67, 0, 0}, ++ {0x8e69, 0x10, 0, 0},{0x8e6a, 0x85, 0, 0},{0x8e6b, 0x68, 0, 0}, ++ {0x8e6c, 0x11, 0, 0},{0x8e6d, 0x12, 0, 0},{0x8e6e, 0x09, 0, 0}, ++ {0x8e6f, 0xf8, 0, 0},{0x8e70, 0x22, 0, 0},{0x8e71, 0x12, 0, 0}, ++ {0x8e72, 0x02, 0, 0},{0x8e73, 0x85, 0, 0},{0x8e74, 0xb5, 0, 0}, ++ {0x8e75, 0x07, 0, 0},{0x8e76, 0x03, 0, 0},{0x8e77, 0xd3, 0, 0}, ++ {0x8e78, 0x80, 0, 0},{0x8e79, 0x01, 0, 0},{0x8e7a, 0xc3, 0, 0}, ++ {0x8e7b, 0x40, 0, 0},{0x8e7c, 0x03, 0, 0},{0x8e7d, 0x02, 0, 0}, ++ {0x8e7e, 0x0f, 0, 0},{0x8e7f, 0x10, 0, 0},{0x8e80, 0x90, 0, 0}, ++ {0x8e81, 0x30, 0, 0},{0x8e82, 0x04, 0, 0},{0x8e83, 0xe0, 0, 0}, ++ {0x8e84, 0x44, 0, 0},{0x8e85, 0x20, 0, 0},{0x8e86, 0xf0, 0, 0}, ++ {0x8e87, 0xa3, 0, 0},{0x8e88, 0xe0, 0, 0},{0x8e89, 0x44, 0, 0}, ++ {0x8e8a, 0x40, 0, 0},{0x8e8b, 0xf0, 0, 0},{0x8e8c, 0x90, 0, 0}, ++ {0x8e8d, 0x50, 0, 0},{0x8e8e, 0x25, 0, 0},{0x8e8f, 0xe0, 0, 0}, ++ {0x8e90, 0x44, 0, 0},{0x8e91, 0x04, 0, 0},{0x8e92, 0xf0, 0, 0}, ++ {0x8e93, 0x90, 0, 0},{0x8e94, 0x50, 0, 0},{0x8e95, 0x03, 0, 0}, ++ {0x8e96, 0xe0, 0, 0},{0x8e97, 0x54, 0, 0},{0x8e98, 0xfd, 0, 0}, ++ {0x8e99, 0xf0, 0, 0},{0x8e9a, 0x90, 0, 0},{0x8e9b, 0x50, 0, 0}, ++ {0x8e9c, 0x27, 0, 0},{0x8e9d, 0xe0, 0, 0},{0x8e9e, 0x44, 0, 0}, ++ {0x8e9f, 0x01, 0, 0},{0x8ea0, 0xf0, 0, 0},{0x8ea1, 0x90, 0, 0}, ++ {0x8ea2, 0x50, 0, 0},{0x8ea3, 0x31, 0, 0},{0x8ea4, 0xe4, 0, 0}, ++ {0x8ea5, 0xf0, 0, 0},{0x8ea6, 0x90, 0, 0},{0x8ea7, 0x50, 0, 0}, ++ {0x8ea8, 0x33, 0, 0},{0x8ea9, 0xf0, 0, 0},{0x8eaa, 0x90, 0, 0}, ++ {0x8eab, 0x30, 0, 0},{0x8eac, 0x1e, 0, 0},{0x8ead, 0x12, 0, 0}, ++ {0x8eae, 0x01, 0, 0},{0x8eaf, 0xfb, 0, 0},{0x8eb0, 0x90, 0, 0}, ++ {0x8eb1, 0x30, 0, 0},{0x8eb2, 0x18, 0, 0},{0x8eb3, 0x12, 0, 0}, ++ {0x8eb4, 0x01, 0, 0},{0x8eb5, 0xfb, 0, 0},{0x8eb6, 0x90, 0, 0}, ++ {0x8eb7, 0x30, 0, 0},{0x8eb8, 0x1b, 0, 0},{0x8eb9, 0x12, 0, 0}, ++ {0x8eba, 0x01, 0, 0},{0x8ebb, 0xfb, 0, 0},{0x8ebc, 0xe0, 0, 0}, ++ {0x8ebd, 0xf5, 0, 0},{0x8ebe, 0x25, 0, 0},{0x8ebf, 0x90, 0, 0}, ++ {0x8ec0, 0x30, 0, 0},{0x8ec1, 0x18, 0, 0},{0x8ec2, 0xe0, 0, 0}, ++ {0x8ec3, 0xf5, 0, 0},{0x8ec4, 0x21, 0, 0},{0x8ec5, 0x90, 0, 0}, ++ {0x8ec6, 0x60, 0, 0},{0x8ec7, 0x00, 0, 0},{0x8ec8, 0x74, 0, 0}, ++ {0x8ec9, 0xf5, 0, 0},{0x8eca, 0xf0, 0, 0},{0x8ecb, 0x90, 0, 0}, ++ {0x8ecc, 0x3f, 0, 0},{0x8ecd, 0x01, 0, 0},{0x8ece, 0xe4, 0, 0}, ++ {0x8ecf, 0xf0, 0, 0},{0x8ed0, 0xa3, 0, 0},{0x8ed1, 0xf0, 0, 0}, ++ {0x8ed2, 0x90, 0, 0},{0x8ed3, 0x3f, 0, 0},{0x8ed4, 0x01, 0, 0}, ++ {0x8ed5, 0xe0, 0, 0},{0x8ed6, 0x44, 0, 0},{0x8ed7, 0x08, 0, 0}, ++ {0x8ed8, 0xf0, 0, 0},{0x8ed9, 0xe0, 0, 0},{0x8eda, 0x44, 0, 0}, ++ {0x8edb, 0x20, 0, 0},{0x8edc, 0xf0, 0, 0},{0x8edd, 0x90, 0, 0}, ++ {0x8ede, 0x3f, 0, 0},{0x8edf, 0x05, 0, 0},{0x8ee0, 0x74, 0, 0}, ++ {0x8ee1, 0x30, 0, 0},{0x8ee2, 0xf0, 0, 0},{0x8ee3, 0xa3, 0, 0}, ++ {0x8ee4, 0x74, 0, 0},{0x8ee5, 0x24, 0, 0},{0x8ee6, 0xf0, 0, 0}, ++ {0x8ee7, 0x90, 0, 0},{0x8ee8, 0x3f, 0, 0},{0x8ee9, 0x0b, 0, 0}, ++ {0x8eea, 0xe0, 0, 0},{0x8eeb, 0x44, 0, 0},{0x8eec, 0x0f, 0, 0}, ++ {0x8eed, 0xf0, 0, 0},{0x8eee, 0x90, 0, 0},{0x8eef, 0x3f, 0, 0}, ++ {0x8ef0, 0x01, 0, 0},{0x8ef1, 0xe0, 0, 0},{0x8ef2, 0x44, 0, 0}, ++ {0x8ef3, 0x02, 0, 0},{0x8ef4, 0xf0, 0, 0},{0x8ef5, 0xc2, 0, 0}, ++ {0x8ef6, 0x8c, 0, 0},{0x8ef7, 0x75, 0, 0},{0x8ef8, 0x89, 0, 0}, ++ {0x8ef9, 0x03, 0, 0},{0x8efa, 0x75, 0, 0},{0x8efb, 0xa8, 0, 0}, ++ {0x8efc, 0x07, 0, 0},{0x8efd, 0x75, 0, 0},{0x8efe, 0xb8, 0, 0}, ++ {0x8eff, 0x04, 0, 0},{0x8f00, 0xe4, 0, 0},{0x8f01, 0xf5, 0, 0}, ++ {0x8f02, 0xd8, 0, 0},{0x8f03, 0xf5, 0, 0},{0x8f04, 0xe8, 0, 0}, ++ {0x8f05, 0x90, 0, 0},{0x8f06, 0x30, 0, 0},{0x8f07, 0x01, 0, 0}, ++ {0x8f08, 0xe0, 0, 0},{0x8f09, 0x44, 0, 0},{0x8f0a, 0x40, 0, 0}, ++ {0x8f0b, 0xf0, 0, 0},{0x8f0c, 0xe0, 0, 0},{0x8f0d, 0x54, 0, 0}, ++ {0x8f0e, 0xbf, 0, 0},{0x8f0f, 0xf0, 0, 0},{0x8f10, 0x22, 0, 0}, ++ {0x8f11, 0xe5, 0, 0},{0x8f12, 0x0c, 0, 0},{0x8f13, 0xd3, 0, 0}, ++ {0x8f14, 0x95, 0, 0},{0x8f15, 0x7b, 0, 0},{0x8f16, 0x40, 0, 0}, ++ {0x8f17, 0x01, 0, 0},{0x8f18, 0x22, 0, 0},{0x8f19, 0xe5, 0, 0}, ++ {0x8f1a, 0x49, 0, 0},{0x8f1b, 0x25, 0, 0},{0x8f1c, 0x0c, 0, 0}, ++ {0x8f1d, 0x12, 0, 0},{0x8f1e, 0x02, 0, 0},{0x8f1f, 0x4f, 0, 0}, ++ {0x8f20, 0x93, 0, 0},{0x8f21, 0x75, 0, 0},{0x8f22, 0x0d, 0, 0}, ++ {0x8f23, 0x00, 0, 0},{0x8f24, 0xf5, 0, 0},{0x8f25, 0x0e, 0, 0}, ++ {0x8f26, 0x45, 0, 0},{0x8f27, 0x0d, 0, 0},{0x8f28, 0x70, 0, 0}, ++ {0x8f29, 0x05, 0, 0},{0x8f2a, 0x85, 0, 0},{0x8f2b, 0x64, 0, 0}, ++ {0x8f2c, 0x0f, 0, 0},{0x8f2d, 0x80, 0, 0},{0x8f2e, 0x1b, 0, 0}, ++ {0x8f2f, 0x12, 0, 0},{0x8f30, 0x02, 0, 0},{0x8f31, 0x9b, 0, 0}, ++ {0x8f32, 0xc3, 0, 0},{0x8f33, 0x33, 0, 0},{0x8f34, 0xce, 0, 0}, ++ {0x8f35, 0x33, 0, 0},{0x8f36, 0xce, 0, 0},{0x8f37, 0xd8, 0, 0}, ++ {0x8f38, 0xf9, 0, 0},{0x8f39, 0xf5, 0, 0},{0x8f3a, 0x0e, 0, 0}, ++ {0x8f3b, 0x8e, 0, 0},{0x8f3c, 0x0d, 0, 0},{0x8f3d, 0x85, 0, 0}, ++ {0x8f3e, 0x0d, 0, 0},{0x8f3f, 0x10, 0, 0},{0x8f40, 0xf5, 0, 0}, ++ {0x8f41, 0x11, 0, 0},{0x8f42, 0x12, 0, 0},{0x8f43, 0x09, 0, 0}, ++ {0x8f44, 0xf8, 0, 0},{0x8f45, 0x30, 0, 0},{0x8f46, 0x33, 0, 0}, ++ {0x8f47, 0x63, 0, 0},{0x8f48, 0xc3, 0, 0},{0x8f49, 0x22, 0, 0}, ++ {0x8f4a, 0xe5, 0, 0},{0x8f4b, 0x0f, 0, 0},{0x8f4c, 0xd3, 0, 0}, ++ {0x8f4d, 0x94, 0, 0},{0x8f4e, 0x10, 0, 0},{0x8f4f, 0x40, 0, 0}, ++ {0x8f50, 0x33, 0, 0},{0x8f51, 0xe5, 0, 0},{0x8f52, 0x0f, 0, 0}, ++ {0x8f53, 0xd3, 0, 0},{0x8f54, 0x94, 0, 0},{0x8f55, 0x60, 0, 0}, ++ {0x8f56, 0x40, 0, 0},{0x8f57, 0x05, 0, 0},{0x8f58, 0x75, 0, 0}, ++ {0x8f59, 0x0f, 0, 0},{0x8f5a, 0x58, 0, 0},{0x8f5b, 0x80, 0, 0}, ++ {0x8f5c, 0x11, 0, 0},{0x8f5d, 0xe5, 0, 0},{0x8f5e, 0x0f, 0, 0}, ++ {0x8f5f, 0xd3, 0, 0},{0x8f60, 0x94, 0, 0},{0x8f61, 0x40, 0, 0}, ++ {0x8f62, 0x40, 0, 0},{0x8f63, 0x04, 0, 0},{0x8f64, 0x74, 0, 0}, ++ {0x8f65, 0xf0, 0, 0},{0x8f66, 0x80, 0, 0},{0x8f67, 0x02, 0, 0}, ++ {0x8f68, 0x74, 0, 0},{0x8f69, 0xf8, 0, 0},{0x8f6a, 0x25, 0, 0}, ++ {0x8f6b, 0x0f, 0, 0},{0x8f6c, 0xf5, 0, 0},{0x8f6d, 0x0f, 0, 0}, ++ {0x8f6e, 0x75, 0, 0},{0x8f6f, 0x0d, 0, 0},{0x8f70, 0x00, 0, 0}, ++ {0x8f71, 0x85, 0, 0},{0x8f72, 0x0f, 0, 0},{0x8f73, 0x0e, 0, 0}, ++ {0x8f74, 0x12, 0, 0},{0x8f75, 0x02, 0, 0},{0x8f76, 0x9b, 0, 0}, ++ {0x8f77, 0xc3, 0, 0},{0x8f78, 0x33, 0, 0},{0x8f79, 0xce, 0, 0}, ++ {0x8f7a, 0x33, 0, 0},{0x8f7b, 0xce, 0, 0},{0x8f7c, 0xd8, 0, 0}, ++ {0x8f7d, 0xf9, 0, 0},{0x8f7e, 0xf5, 0, 0},{0x8f7f, 0x0e, 0, 0}, ++ {0x8f80, 0x8e, 0, 0},{0x8f81, 0x0d, 0, 0},{0x8f82, 0x80, 0, 0}, ++ {0x8f83, 0x0a, 0, 0},{0x8f84, 0xe4, 0, 0},{0x8f85, 0xf5, 0, 0}, ++ {0x8f86, 0x0f, 0, 0},{0x8f87, 0x75, 0, 0},{0x8f88, 0x0d, 0, 0}, ++ {0x8f89, 0x80, 0, 0},{0x8f8a, 0xf5, 0, 0},{0x8f8b, 0x0e, 0, 0}, ++ {0x8f8c, 0xf5, 0, 0},{0x8f8d, 0x64, 0, 0},{0x8f8e, 0x85, 0, 0}, ++ {0x8f8f, 0x0d, 0, 0},{0x8f90, 0x10, 0, 0},{0x8f91, 0x85, 0, 0}, ++ {0x8f92, 0x0e, 0, 0},{0x8f93, 0x11, 0, 0},{0x8f94, 0x12, 0, 0}, ++ {0x8f95, 0x09, 0, 0},{0x8f96, 0xf8, 0, 0},{0x8f97, 0x30, 0, 0}, ++ {0x8f98, 0x33, 0, 0},{0x8f99, 0x02, 0, 0},{0x8f9a, 0xc3, 0, 0}, ++ {0x8f9b, 0x22, 0, 0},{0x8f9c, 0xe5, 0, 0},{0x8f9d, 0x0f, 0, 0}, ++ {0x8f9e, 0x60, 0, 0},{0x8f9f, 0x0b, 0, 0},{0x8fa0, 0x75, 0, 0}, ++ {0x8fa1, 0x10, 0, 0},{0x8fa2, 0x00, 0, 0},{0x8fa3, 0x75, 0, 0}, ++ {0x8fa4, 0x11, 0, 0},{0x8fa5, 0x32, 0, 0},{0x8fa6, 0x12, 0, 0}, ++ {0x8fa7, 0x14, 0, 0},{0x8fa8, 0xcd, 0, 0},{0x8fa9, 0x80, 0, 0}, ++ {0x8faa, 0x9f, 0, 0},{0x8fab, 0x85, 0, 0},{0x8fac, 0x0c, 0, 0}, ++ {0x8fad, 0x7c, 0, 0},{0x8fae, 0xd3, 0, 0},{0x8faf, 0x22, 0, 0}, ++ {0x8fb0, 0x30, 0, 0},{0x8fb1, 0x3c, 0, 0},{0x8fb2, 0x09, 0, 0}, ++ {0x8fb3, 0x30, 0, 0},{0x8fb4, 0x20, 0, 0},{0x8fb5, 0x06, 0, 0}, ++ {0x8fb6, 0xae, 0, 0},{0x8fb7, 0x56, 0, 0},{0x8fb8, 0xaf, 0, 0}, ++ {0x8fb9, 0x57, 0, 0},{0x8fba, 0x80, 0, 0},{0x8fbb, 0x04, 0, 0}, ++ {0x8fbc, 0xae, 0, 0},{0x8fbd, 0x69, 0, 0},{0x8fbe, 0xaf, 0, 0}, ++ {0x8fbf, 0x6a, 0, 0},{0x8fc0, 0x8e, 0, 0},{0x8fc1, 0x56, 0, 0}, ++ {0x8fc2, 0x8f, 0, 0},{0x8fc3, 0x57, 0, 0},{0x8fc4, 0x30, 0, 0}, ++ {0x8fc5, 0x3c, 0, 0},{0x8fc6, 0x09, 0, 0},{0x8fc7, 0x30, 0, 0}, ++ {0x8fc8, 0x21, 0, 0},{0x8fc9, 0x06, 0, 0},{0x8fca, 0xae, 0, 0}, ++ {0x8fcb, 0x58, 0, 0},{0x8fcc, 0xaf, 0, 0},{0x8fcd, 0x59, 0, 0}, ++ {0x8fce, 0x80, 0, 0},{0x8fcf, 0x04, 0, 0},{0x8fd0, 0xae, 0, 0}, ++ {0x8fd1, 0x6b, 0, 0},{0x8fd2, 0xaf, 0, 0},{0x8fd3, 0x6c, 0, 0}, ++ {0x8fd4, 0x8e, 0, 0},{0x8fd5, 0x58, 0, 0},{0x8fd6, 0x8f, 0, 0}, ++ {0x8fd7, 0x59, 0, 0},{0x8fd8, 0x30, 0, 0},{0x8fd9, 0x3c, 0, 0}, ++ {0x8fda, 0x09, 0, 0},{0x8fdb, 0x30, 0, 0},{0x8fdc, 0x22, 0, 0}, ++ {0x8fdd, 0x06, 0, 0},{0x8fde, 0xae, 0, 0},{0x8fdf, 0x5a, 0, 0}, ++ {0x8fe0, 0xaf, 0, 0},{0x8fe1, 0x5b, 0, 0},{0x8fe2, 0x80, 0, 0}, ++ {0x8fe3, 0x04, 0, 0},{0x8fe4, 0xae, 0, 0},{0x8fe5, 0x6d, 0, 0}, ++ {0x8fe6, 0xaf, 0, 0},{0x8fe7, 0x6e, 0, 0},{0x8fe8, 0x8e, 0, 0}, ++ {0x8fe9, 0x5a, 0, 0},{0x8fea, 0x8f, 0, 0},{0x8feb, 0x5b, 0, 0}, ++ {0x8fec, 0x30, 0, 0},{0x8fed, 0x3c, 0, 0},{0x8fee, 0x09, 0, 0}, ++ {0x8fef, 0x30, 0, 0},{0x8ff0, 0x23, 0, 0},{0x8ff1, 0x06, 0, 0}, ++ {0x8ff2, 0xae, 0, 0},{0x8ff3, 0x5c, 0, 0},{0x8ff4, 0xaf, 0, 0}, ++ {0x8ff5, 0x5d, 0, 0},{0x8ff6, 0x80, 0, 0},{0x8ff7, 0x04, 0, 0}, ++ {0x8ff8, 0xae, 0, 0},{0x8ff9, 0x6f, 0, 0},{0x8ffa, 0xaf, 0, 0}, ++ {0x8ffb, 0x70, 0, 0},{0x8ffc, 0x8e, 0, 0},{0x8ffd, 0x5c, 0, 0}, ++ {0x8ffe, 0x8f, 0, 0},{0x8fff, 0x5d, 0, 0},{0x9000, 0x30, 0, 0}, ++ {0x9001, 0x3c, 0, 0},{0x9002, 0x09, 0, 0},{0x9003, 0x30, 0, 0}, ++ {0x9004, 0x24, 0, 0},{0x9005, 0x06, 0, 0},{0x9006, 0xae, 0, 0}, ++ {0x9007, 0x5e, 0, 0},{0x9008, 0xaf, 0, 0},{0x9009, 0x5f, 0, 0}, ++ {0x900a, 0x80, 0, 0},{0x900b, 0x04, 0, 0},{0x900c, 0xae, 0, 0}, ++ {0x900d, 0x71, 0, 0},{0x900e, 0xaf, 0, 0},{0x900f, 0x72, 0, 0}, ++ {0x9010, 0x8e, 0, 0},{0x9011, 0x5e, 0, 0},{0x9012, 0x8f, 0, 0}, ++ {0x9013, 0x5f, 0, 0},{0x9014, 0x30, 0, 0},{0x9015, 0x3c, 0, 0}, ++ {0x9016, 0x09, 0, 0},{0x9017, 0x30, 0, 0},{0x9018, 0x25, 0, 0}, ++ {0x9019, 0x06, 0, 0},{0x901a, 0xae, 0, 0},{0x901b, 0x60, 0, 0}, ++ {0x901c, 0xaf, 0, 0},{0x901d, 0x61, 0, 0},{0x901e, 0x80, 0, 0}, ++ {0x901f, 0x04, 0, 0},{0x9020, 0xae, 0, 0},{0x9021, 0x73, 0, 0}, ++ {0x9022, 0xaf, 0, 0},{0x9023, 0x74, 0, 0},{0x9024, 0x8e, 0, 0}, ++ {0x9025, 0x60, 0, 0},{0x9026, 0x8f, 0, 0},{0x9027, 0x61, 0, 0}, ++ {0x9028, 0x30, 0, 0},{0x9029, 0x3c, 0, 0},{0x902a, 0x09, 0, 0}, ++ {0x902b, 0x30, 0, 0},{0x902c, 0x26, 0, 0},{0x902d, 0x06, 0, 0}, ++ {0x902e, 0xae, 0, 0},{0x902f, 0x62, 0, 0},{0x9030, 0xaf, 0, 0}, ++ {0x9031, 0x63, 0, 0},{0x9032, 0x80, 0, 0},{0x9033, 0x04, 0, 0}, ++ {0x9034, 0xae, 0, 0},{0x9035, 0x75, 0, 0},{0x9036, 0xaf, 0, 0}, ++ {0x9037, 0x76, 0, 0},{0x9038, 0x8e, 0, 0},{0x9039, 0x62, 0, 0}, ++ {0x903a, 0x8f, 0, 0},{0x903b, 0x63, 0, 0},{0x903c, 0x22, 0, 0}, ++ {0x903d, 0xd3, 0, 0},{0x903e, 0xe5, 0, 0},{0x903f, 0x57, 0, 0}, ++ {0x9040, 0x95, 0, 0},{0x9041, 0x6a, 0, 0},{0x9042, 0xe5, 0, 0}, ++ {0x9043, 0x56, 0, 0},{0x9044, 0x95, 0, 0},{0x9045, 0x69, 0, 0}, ++ {0x9046, 0x40, 0, 0},{0x9047, 0x03, 0, 0},{0x9048, 0xd3, 0, 0}, ++ {0x9049, 0x80, 0, 0},{0x904a, 0x01, 0, 0},{0x904b, 0xc3, 0, 0}, ++ {0x904c, 0x92, 0, 0},{0x904d, 0x20, 0, 0},{0x904e, 0xd3, 0, 0}, ++ {0x904f, 0xe5, 0, 0},{0x9050, 0x59, 0, 0},{0x9051, 0x95, 0, 0}, ++ {0x9052, 0x6c, 0, 0},{0x9053, 0xe5, 0, 0},{0x9054, 0x58, 0, 0}, ++ {0x9055, 0x95, 0, 0},{0x9056, 0x6b, 0, 0},{0x9057, 0x40, 0, 0}, ++ {0x9058, 0x03, 0, 0},{0x9059, 0xd3, 0, 0},{0x905a, 0x80, 0, 0}, ++ {0x905b, 0x01, 0, 0},{0x905c, 0xc3, 0, 0},{0x905d, 0x92, 0, 0}, ++ {0x905e, 0x21, 0, 0},{0x905f, 0xd3, 0, 0},{0x9060, 0xe5, 0, 0}, ++ {0x9061, 0x5b, 0, 0},{0x9062, 0x95, 0, 0},{0x9063, 0x6e, 0, 0}, ++ {0x9064, 0xe5, 0, 0},{0x9065, 0x5a, 0, 0},{0x9066, 0x95, 0, 0}, ++ {0x9067, 0x6d, 0, 0},{0x9068, 0x40, 0, 0},{0x9069, 0x03, 0, 0}, ++ {0x906a, 0xd3, 0, 0},{0x906b, 0x80, 0, 0},{0x906c, 0x01, 0, 0}, ++ {0x906d, 0xc3, 0, 0},{0x906e, 0x92, 0, 0},{0x906f, 0x22, 0, 0}, ++ {0x9070, 0xd3, 0, 0},{0x9071, 0xe5, 0, 0},{0x9072, 0x5d, 0, 0}, ++ {0x9073, 0x95, 0, 0},{0x9074, 0x70, 0, 0},{0x9075, 0xe5, 0, 0}, ++ {0x9076, 0x5c, 0, 0},{0x9077, 0x95, 0, 0},{0x9078, 0x6f, 0, 0}, ++ {0x9079, 0x40, 0, 0},{0x907a, 0x03, 0, 0},{0x907b, 0xd3, 0, 0}, ++ {0x907c, 0x80, 0, 0},{0x907d, 0x01, 0, 0},{0x907e, 0xc3, 0, 0}, ++ {0x907f, 0x92, 0, 0},{0x9080, 0x23, 0, 0},{0x9081, 0xd3, 0, 0}, ++ {0x9082, 0xe5, 0, 0},{0x9083, 0x5f, 0, 0},{0x9084, 0x95, 0, 0}, ++ {0x9085, 0x72, 0, 0},{0x9086, 0xe5, 0, 0},{0x9087, 0x5e, 0, 0}, ++ {0x9088, 0x95, 0, 0},{0x9089, 0x71, 0, 0},{0x908a, 0x40, 0, 0}, ++ {0x908b, 0x03, 0, 0},{0x908c, 0xd3, 0, 0},{0x908d, 0x80, 0, 0}, ++ {0x908e, 0x01, 0, 0},{0x908f, 0xc3, 0, 0},{0x9090, 0x92, 0, 0}, ++ {0x9091, 0x24, 0, 0},{0x9092, 0xd3, 0, 0},{0x9093, 0xe5, 0, 0}, ++ {0x9094, 0x61, 0, 0},{0x9095, 0x95, 0, 0},{0x9096, 0x74, 0, 0}, ++ {0x9097, 0xe5, 0, 0},{0x9098, 0x60, 0, 0},{0x9099, 0x95, 0, 0}, ++ {0x909a, 0x73, 0, 0},{0x909b, 0x40, 0, 0},{0x909c, 0x03, 0, 0}, ++ {0x909d, 0xd3, 0, 0},{0x909e, 0x80, 0, 0},{0x909f, 0x01, 0, 0}, ++ {0x90a0, 0xc3, 0, 0},{0x90a1, 0x92, 0, 0},{0x90a2, 0x25, 0, 0}, ++ {0x90a3, 0xd3, 0, 0},{0x90a4, 0xe5, 0, 0},{0x90a5, 0x63, 0, 0}, ++ {0x90a6, 0x95, 0, 0},{0x90a7, 0x76, 0, 0},{0x90a8, 0xe5, 0, 0}, ++ {0x90a9, 0x62, 0, 0},{0x90aa, 0x95, 0, 0},{0x90ab, 0x75, 0, 0}, ++ {0x90ac, 0x40, 0, 0},{0x90ad, 0x03, 0, 0},{0x90ae, 0xd3, 0, 0}, ++ {0x90af, 0x80, 0, 0},{0x90b0, 0x01, 0, 0},{0x90b1, 0xc3, 0, 0}, ++ {0x90b2, 0x92, 0, 0},{0x90b3, 0x26, 0, 0},{0x90b4, 0x22, 0, 0}, ++ {0x90b5, 0xe5, 0, 0},{0x90b6, 0x0a, 0, 0},{0x90b7, 0x70, 0, 0}, ++ {0x90b8, 0x04, 0, 0},{0x90b9, 0x7a, 0, 0},{0x90ba, 0x11, 0, 0}, ++ {0x90bb, 0x7b, 0, 0},{0x90bc, 0xee, 0, 0},{0x90bd, 0xe5, 0, 0}, ++ {0x90be, 0x0a, 0, 0},{0x90bf, 0xb4, 0, 0},{0x90c0, 0x01, 0, 0}, ++ {0x90c1, 0x04, 0, 0},{0x90c2, 0x7a, 0, 0},{0x90c3, 0x12, 0, 0}, ++ {0x90c4, 0x7b, 0, 0},{0x90c5, 0x02, 0, 0},{0x90c6, 0xe5, 0, 0}, ++ {0x90c7, 0x0a, 0, 0},{0x90c8, 0xb4, 0, 0},{0x90c9, 0x02, 0, 0}, ++ {0x90ca, 0x04, 0, 0},{0x90cb, 0x7a, 0, 0},{0x90cc, 0x12, 0, 0}, ++ {0x90cd, 0x7b, 0, 0},{0x90ce, 0x16, 0, 0},{0x90cf, 0x8b, 0, 0}, ++ {0x90d0, 0x82, 0, 0},{0x90d1, 0x8a, 0, 0},{0x90d2, 0x83, 0, 0}, ++ {0x90d3, 0x12, 0, 0},{0x90d4, 0x09, 0, 0},{0x90d5, 0xc2, 0, 0}, ++ {0x90d6, 0x8f, 0, 0},{0x90d7, 0x37, 0, 0},{0x90d8, 0x8e, 0, 0}, ++ {0x90d9, 0x36, 0, 0},{0x90da, 0x8d, 0, 0},{0x90db, 0x35, 0, 0}, ++ {0x90dc, 0x8c, 0, 0},{0x90dd, 0x34, 0, 0},{0x90de, 0xe5, 0, 0}, ++ {0x90df, 0x82, 0, 0},{0x90e0, 0x24, 0, 0},{0x90e1, 0x04, 0, 0}, ++ {0x90e2, 0xf5, 0, 0},{0x90e3, 0x82, 0, 0},{0x90e4, 0xe4, 0, 0}, ++ {0x90e5, 0x35, 0, 0},{0x90e6, 0x83, 0, 0},{0x90e7, 0xf5, 0, 0}, ++ {0x90e8, 0x83, 0, 0},{0x90e9, 0x12, 0, 0},{0x90ea, 0x09, 0, 0}, ++ {0x90eb, 0xc2, 0, 0},{0x90ec, 0x8f, 0, 0},{0x90ed, 0x3b, 0, 0}, ++ {0x90ee, 0x8e, 0, 0},{0x90ef, 0x3a, 0, 0},{0x90f0, 0x8d, 0, 0}, ++ {0x90f1, 0x39, 0, 0},{0x90f2, 0x8c, 0, 0},{0x90f3, 0x38, 0, 0}, ++ {0x90f4, 0xeb, 0, 0},{0x90f5, 0x24, 0, 0},{0x90f6, 0x08, 0, 0}, ++ {0x90f7, 0x12, 0, 0},{0x90f8, 0x02, 0, 0},{0x90f9, 0x2f, 0, 0}, ++ {0x90fa, 0x12, 0, 0},{0x90fb, 0x01, 0, 0},{0x90fc, 0x97, 0, 0}, ++ {0x90fd, 0xeb, 0, 0},{0x90fe, 0x24, 0, 0},{0x90ff, 0x0c, 0, 0}, ++ {0x9100, 0x12, 0, 0},{0x9101, 0x02, 0, 0},{0x9102, 0x2f, 0, 0}, ++ {0x9103, 0x8f, 0, 0},{0x9104, 0x43, 0, 0},{0x9105, 0x8e, 0, 0}, ++ {0x9106, 0x42, 0, 0},{0x9107, 0x8d, 0, 0},{0x9108, 0x41, 0, 0}, ++ {0x9109, 0x8c, 0, 0},{0x910a, 0x40, 0, 0},{0x910b, 0xeb, 0, 0}, ++ {0x910c, 0x24, 0, 0},{0x910d, 0x10, 0, 0},{0x910e, 0x12, 0, 0}, ++ {0x910f, 0x02, 0, 0},{0x9110, 0x2f, 0, 0},{0x9111, 0x8f, 0, 0}, ++ {0x9112, 0x47, 0, 0},{0x9113, 0x8e, 0, 0},{0x9114, 0x46, 0, 0}, ++ {0x9115, 0x8d, 0, 0},{0x9116, 0x45, 0, 0},{0x9117, 0x8c, 0, 0}, ++ {0x9118, 0x44, 0, 0},{0x9119, 0x22, 0, 0},{0x911a, 0x30, 0, 0}, ++ {0x911b, 0x3c, 0, 0},{0x911c, 0x07, 0, 0},{0x911d, 0x30, 0, 0}, ++ {0x911e, 0x20, 0, 0},{0x911f, 0x04, 0, 0},{0x9120, 0xaf, 0, 0}, ++ {0x9121, 0x4a, 0, 0},{0x9122, 0x80, 0, 0},{0x9123, 0x02, 0, 0}, ++ {0x9124, 0xaf, 0, 0},{0x9125, 0x7c, 0, 0},{0x9126, 0x8f, 0, 0}, ++ {0x9127, 0x4a, 0, 0},{0x9128, 0x30, 0, 0},{0x9129, 0x3c, 0, 0}, ++ {0x912a, 0x07, 0, 0},{0x912b, 0x30, 0, 0},{0x912c, 0x21, 0, 0}, ++ {0x912d, 0x04, 0, 0},{0x912e, 0xaf, 0, 0},{0x912f, 0x4b, 0, 0}, ++ {0x9130, 0x80, 0, 0},{0x9131, 0x02, 0, 0},{0x9132, 0xaf, 0, 0}, ++ {0x9133, 0x7c, 0, 0},{0x9134, 0x8f, 0, 0},{0x9135, 0x4b, 0, 0}, ++ {0x9136, 0x30, 0, 0},{0x9137, 0x3c, 0, 0},{0x9138, 0x07, 0, 0}, ++ {0x9139, 0x30, 0, 0},{0x913a, 0x22, 0, 0},{0x913b, 0x04, 0, 0}, ++ {0x913c, 0xaf, 0, 0},{0x913d, 0x4c, 0, 0},{0x913e, 0x80, 0, 0}, ++ {0x913f, 0x02, 0, 0},{0x9140, 0xaf, 0, 0},{0x9141, 0x7c, 0, 0}, ++ {0x9142, 0x8f, 0, 0},{0x9143, 0x4c, 0, 0},{0x9144, 0x30, 0, 0}, ++ {0x9145, 0x3c, 0, 0},{0x9146, 0x07, 0, 0},{0x9147, 0x30, 0, 0}, ++ {0x9148, 0x23, 0, 0},{0x9149, 0x04, 0, 0},{0x914a, 0xaf, 0, 0}, ++ {0x914b, 0x4d, 0, 0},{0x914c, 0x80, 0, 0},{0x914d, 0x02, 0, 0}, ++ {0x914e, 0xaf, 0, 0},{0x914f, 0x7c, 0, 0},{0x9150, 0x8f, 0, 0}, ++ {0x9151, 0x4d, 0, 0},{0x9152, 0x30, 0, 0},{0x9153, 0x3c, 0, 0}, ++ {0x9154, 0x07, 0, 0},{0x9155, 0x30, 0, 0},{0x9156, 0x24, 0, 0}, ++ {0x9157, 0x04, 0, 0},{0x9158, 0xaf, 0, 0},{0x9159, 0x4e, 0, 0}, ++ {0x915a, 0x80, 0, 0},{0x915b, 0x02, 0, 0},{0x915c, 0xaf, 0, 0}, ++ {0x915d, 0x7c, 0, 0},{0x915e, 0x8f, 0, 0},{0x915f, 0x4e, 0, 0}, ++ {0x9160, 0x30, 0, 0},{0x9161, 0x3c, 0, 0},{0x9162, 0x07, 0, 0}, ++ {0x9163, 0x30, 0, 0},{0x9164, 0x25, 0, 0},{0x9165, 0x04, 0, 0}, ++ {0x9166, 0xaf, 0, 0},{0x9167, 0x4f, 0, 0},{0x9168, 0x80, 0, 0}, ++ {0x9169, 0x02, 0, 0},{0x916a, 0xaf, 0, 0},{0x916b, 0x7c, 0, 0}, ++ {0x916c, 0x8f, 0, 0},{0x916d, 0x4f, 0, 0},{0x916e, 0x30, 0, 0}, ++ {0x916f, 0x3c, 0, 0},{0x9170, 0x07, 0, 0},{0x9171, 0x30, 0, 0}, ++ {0x9172, 0x26, 0, 0},{0x9173, 0x04, 0, 0},{0x9174, 0xaf, 0, 0}, ++ {0x9175, 0x50, 0, 0},{0x9176, 0x80, 0, 0},{0x9177, 0x02, 0, 0}, ++ {0x9178, 0xaf, 0, 0},{0x9179, 0x7c, 0, 0},{0x917a, 0x8f, 0, 0}, ++ {0x917b, 0x50, 0, 0},{0x917c, 0x22, 0, 0},{0x917d, 0xe5, 0, 0}, ++ {0x917e, 0x7d, 0, 0},{0x917f, 0x64, 0, 0},{0x9180, 0x01, 0, 0}, ++ {0x9181, 0x70, 0, 0},{0x9182, 0x47, 0, 0},{0x9183, 0xe5, 0, 0}, ++ {0x9184, 0x49, 0, 0},{0x9185, 0x25, 0, 0},{0x9186, 0x7c, 0, 0}, ++ {0x9187, 0x12, 0, 0},{0x9188, 0x01, 0, 0},{0x9189, 0xa4, 0, 0}, ++ {0x918a, 0xfe, 0, 0},{0x918b, 0xe4, 0, 0},{0x918c, 0x8f, 0, 0}, ++ {0x918d, 0x68, 0, 0},{0x918e, 0x8e, 0, 0},{0x918f, 0x67, 0, 0}, ++ {0x9190, 0xf5, 0, 0},{0x9191, 0x66, 0, 0},{0x9192, 0xf5, 0, 0}, ++ {0x9193, 0x65, 0, 0},{0x9194, 0x12, 0, 0},{0x9195, 0x01, 0, 0}, ++ {0x9196, 0xf2, 0, 0},{0x9197, 0x7b, 0, 0},{0x9198, 0xff, 0, 0}, ++ {0x9199, 0xfa, 0, 0},{0x919a, 0xf9, 0, 0},{0x919b, 0xf8, 0, 0}, ++ {0x919c, 0x12, 0, 0},{0x919d, 0x01, 0, 0},{0x919e, 0xe7, 0, 0}, ++ {0x919f, 0xc0, 0, 0},{0x91a0, 0x05, 0, 0},{0x91a1, 0xc0, 0, 0}, ++ {0x91a2, 0x06, 0, 0},{0x91a3, 0xc0, 0, 0},{0x91a4, 0x07, 0, 0}, ++ {0x91a5, 0x12, 0, 0},{0x91a6, 0x01, 0, 0},{0x91a7, 0xa0, 0, 0}, ++ {0x91a8, 0xab, 0, 0},{0x91a9, 0x07, 0, 0},{0x91aa, 0xfa, 0, 0}, ++ {0x91ab, 0xe4, 0, 0},{0x91ac, 0xf9, 0, 0},{0x91ad, 0xf8, 0, 0}, ++ {0x91ae, 0xd0, 0, 0},{0x91af, 0x07, 0, 0},{0x91b0, 0xd0, 0, 0}, ++ {0x91b1, 0x06, 0, 0},{0x91b2, 0xd0, 0, 0},{0x91b3, 0x05, 0, 0}, ++ {0x91b4, 0x12, 0, 0},{0x91b5, 0x02, 0, 0},{0x91b6, 0x6d, 0, 0}, ++ {0x91b7, 0x85, 0, 0},{0x91b8, 0x68, 0, 0},{0x91b9, 0x65, 0, 0}, ++ {0x91ba, 0x85, 0, 0},{0x91bb, 0x7c, 0, 0},{0x91bc, 0x66, 0, 0}, ++ {0x91bd, 0xe5, 0, 0},{0x91be, 0x49, 0, 0},{0x91bf, 0x25, 0, 0}, ++ {0x91c0, 0x7c, 0, 0},{0x91c1, 0x12, 0, 0},{0x91c2, 0x02, 0, 0}, ++ {0x91c3, 0x4f, 0, 0},{0x91c4, 0x93, 0, 0},{0x91c5, 0x75, 0, 0}, ++ {0x91c6, 0x67, 0, 0},{0x91c7, 0x00, 0, 0},{0x91c8, 0xf5, 0, 0}, ++ {0x91c9, 0x68, 0, 0},{0x91ca, 0x90, 0, 0},{0x91cb, 0x50, 0, 0}, ++ {0x91cc, 0x82, 0, 0},{0x91cd, 0xe5, 0, 0},{0x91ce, 0x65, 0, 0}, ++ {0x91cf, 0xf0, 0, 0},{0x91d0, 0xa3, 0, 0},{0x91d1, 0xe5, 0, 0}, ++ {0x91d2, 0x66, 0, 0},{0x91d3, 0xf0, 0, 0},{0x91d4, 0xa3, 0, 0}, ++ {0x91d5, 0xe5, 0, 0},{0x91d6, 0x67, 0, 0},{0x91d7, 0xf0, 0, 0}, ++ {0x91d8, 0xa3, 0, 0},{0x91d9, 0xe5, 0, 0},{0x91da, 0x68, 0, 0}, ++ {0x91db, 0xf0, 0, 0},{0x91dc, 0x22, 0, 0},{0x91dd, 0x56, 0, 0}, ++ {0x91de, 0x0c, 0, 0},{0x91df, 0x04, 0, 0},{0x91e0, 0x00, 0, 0}, ++ {0x91e1, 0x2a, 0, 0},{0x91e2, 0x35, 0, 0},{0x91e3, 0x40, 0, 0}, ++ {0x91e4, 0x49, 0, 0},{0x91e5, 0x52, 0, 0},{0x91e6, 0x5b, 0, 0}, ++ {0x91e7, 0x64, 0, 0},{0x91e8, 0x6d, 0, 0},{0x91e9, 0x76, 0, 0}, ++ {0x91ea, 0x7f, 0, 0},{0x91eb, 0x88, 0, 0},{0x91ec, 0x91, 0, 0}, ++ {0x91ed, 0x07, 0, 0},{0x91ee, 0x20, 0, 0},{0x91ef, 0x12, 0, 0}, ++ {0x91f0, 0x28, 0, 0},{0x91f1, 0x1e, 0, 0},{0x91f2, 0x18, 0, 0}, ++ {0x91f3, 0x18, 0, 0},{0x91f4, 0x28, 0, 0},{0x91f5, 0x1e, 0, 0}, ++ {0x91f6, 0x18, 0, 0},{0x91f7, 0x12, 0, 0},{0x91f8, 0x28, 0, 0}, ++ {0x91f9, 0x1e, 0, 0},{0x91fa, 0x18, 0, 0},{0x91fb, 0x12, 0, 0}, ++ {0x91fc, 0x28, 0, 0},{0x91fd, 0x18, 0, 0},{0x91fe, 0x18, 0, 0}, ++ {0x91ff, 0x12, 0, 0},{0x9200, 0x20, 0, 0},{0x9201, 0x18, 0, 0}, ++ {0x9202, 0x28, 0, 0},{0x9203, 0x1c, 0, 0},{0x9204, 0x30, 0, 0}, ++ {0x9205, 0x24, 0, 0},{0x9206, 0x10, 0, 0},{0x9207, 0x1c, 0, 0}, ++ {0x9208, 0x18, 0, 0},{0x9209, 0x24, 0, 0},{0x920a, 0x1c, 0, 0}, ++ {0x920b, 0x14, 0, 0},{0x920c, 0x24, 0, 0},{0x920d, 0x1c, 0, 0}, ++ {0x920e, 0x28, 0, 0},{0x920f, 0x0c, 0, 0},{0x9210, 0x30, 0, 0}, ++ {0x9211, 0x14, 0, 0},{0x9212, 0x10, 0, 0},{0x9213, 0x0c, 0, 0}, ++ {0x9214, 0x18, 0, 0},{0x9215, 0x14, 0, 0},{0x9216, 0x1c, 0, 0}, ++ {0x9217, 0x20, 0, 0},{0x9218, 0x24, 0, 0},{0x9219, 0x28, 0, 0}, ++ {0x921a, 0x0c, 0, 0},{0x921b, 0x14, 0, 0},{0x921c, 0x14, 0, 0}, ++ {0x921d, 0x1c, 0, 0},{0x921e, 0x1c, 0, 0},{0x921f, 0x14, 0, 0}, ++ {0x9220, 0x24, 0, 0},{0x9221, 0x1c, 0, 0},{0x9222, 0x2c, 0, 0}, ++ {0x9223, 0x14, 0, 0},{0x9224, 0x34, 0, 0},{0x9225, 0x1c, 0, 0}, ++ {0x9226, 0x1c, 0, 0},{0x9227, 0x08, 0, 0},{0x9228, 0x24, 0, 0}, ++ {0x9229, 0x10, 0, 0},{0x922a, 0x19, 0, 0},{0x922b, 0x19, 0, 0}, ++ {0x922c, 0x1c, 0, 0},{0x922d, 0x19, 0, 0},{0x922e, 0x19, 0, 0}, ++ {0x922f, 0x10, 0, 0},{0x9230, 0x10, 0, 0},{0x9231, 0x10, 0, 0}, ++ {0x9232, 0x10, 0, 0},{0x9233, 0x10, 0, 0},{0x9234, 0x00, 0, 0}, ++ {0x9235, 0x00, 0, 0},{0x9236, 0x00, 0, 0},{0x9237, 0x00, 0, 0}, ++ {0x9238, 0x00, 0, 0},{0x9239, 0xc2, 0, 0},{0x923a, 0x34, 0, 0}, ++ {0x923b, 0x20, 0, 0},{0x923c, 0x05, 0, 0},{0x923d, 0x05, 0, 0}, ++ {0x923e, 0x75, 0, 0},{0x923f, 0x0a, 0, 0},{0x9240, 0xee, 0, 0}, ++ {0x9241, 0x80, 0, 0},{0x9242, 0x36, 0, 0},{0x9243, 0x20, 0, 0}, ++ {0x9244, 0x07, 0, 0},{0x9245, 0x08, 0, 0},{0x9246, 0x20, 0, 0}, ++ {0x9247, 0x06, 0, 0},{0x9248, 0x05, 0, 0},{0x9249, 0xe4, 0, 0}, ++ {0x924a, 0xf5, 0, 0},{0x924b, 0x0a, 0, 0},{0x924c, 0x80, 0, 0}, ++ {0x924d, 0x2b, 0, 0},{0x924e, 0x20, 0, 0},{0x924f, 0x07, 0, 0}, ++ {0x9250, 0x08, 0, 0},{0x9251, 0x30, 0, 0},{0x9252, 0x06, 0, 0}, ++ {0x9253, 0x05, 0, 0},{0x9254, 0x75, 0, 0},{0x9255, 0x0a, 0, 0}, ++ {0x9256, 0x20, 0, 0},{0x9257, 0x80, 0, 0},{0x9258, 0x20, 0, 0}, ++ {0x9259, 0x30, 0, 0},{0x925a, 0x00, 0, 0},{0x925b, 0x05, 0, 0}, ++ {0x925c, 0x75, 0, 0},{0x925d, 0x0a, 0, 0},{0x925e, 0x01, 0, 0}, ++ {0x925f, 0x80, 0, 0},{0x9260, 0x18, 0, 0},{0x9261, 0xe5, 0, 0}, ++ {0x9262, 0x20, 0, 0},{0x9263, 0x54, 0, 0},{0x9264, 0x07, 0, 0}, ++ {0x9265, 0xff, 0, 0},{0x9266, 0xbf, 0, 0},{0x9267, 0x06, 0, 0}, ++ {0x9268, 0x0d, 0, 0},{0x9269, 0x30, 0, 0},{0x926a, 0x31, 0, 0}, ++ {0x926b, 0x04, 0, 0},{0x926c, 0x7f, 0, 0},{0x926d, 0x12, 0, 0}, ++ {0x926e, 0x80, 0, 0},{0x926f, 0x02, 0, 0},{0x9270, 0x7f, 0, 0}, ++ {0x9271, 0x02, 0, 0},{0x9272, 0x8f, 0, 0},{0x9273, 0x0a, 0, 0}, ++ {0x9274, 0x80, 0, 0},{0x9275, 0x03, 0, 0},{0x9276, 0x75, 0, 0}, ++ {0x9277, 0x0a, 0, 0},{0x9278, 0xfe, 0, 0},{0x9279, 0x90, 0, 0}, ++ {0x927a, 0x30, 0, 0},{0x927b, 0x27, 0, 0},{0x927c, 0xe5, 0, 0}, ++ {0x927d, 0x0a, 0, 0},{0x927e, 0xf0, 0, 0},{0x927f, 0xe5, 0, 0}, ++ {0x9280, 0x23, 0, 0},{0x9281, 0x54, 0, 0},{0x9282, 0xf8, 0, 0}, ++ {0x9283, 0xf5, 0, 0},{0x9284, 0x0a, 0, 0},{0x9285, 0xe5, 0, 0}, ++ {0x9286, 0x78, 0, 0},{0x9287, 0x25, 0, 0},{0x9288, 0x0a, 0, 0}, ++ {0x9289, 0xf5, 0, 0},{0x928a, 0x0a, 0, 0},{0x928b, 0x90, 0, 0}, ++ {0x928c, 0x30, 0, 0},{0x928d, 0x26, 0, 0},{0x928e, 0xe5, 0, 0}, ++ {0x928f, 0x0a, 0, 0},{0x9290, 0xf0, 0, 0},{0x9291, 0x22, 0, 0}, ++ {0x9292, 0xe5, 0, 0},{0x9293, 0x0a, 0, 0},{0x9294, 0x70, 0, 0}, ++ {0x9295, 0x04, 0, 0},{0x9296, 0x7e, 0, 0},{0x9297, 0x12, 0, 0}, ++ {0x9298, 0x7f, 0, 0},{0x9299, 0x2a, 0, 0},{0x929a, 0xe5, 0, 0}, ++ {0x929b, 0x0a, 0, 0},{0x929c, 0xb4, 0, 0},{0x929d, 0x01, 0, 0}, ++ {0x929e, 0x04, 0, 0},{0x929f, 0x7e, 0, 0},{0x92a0, 0x12, 0, 0}, ++ {0x92a1, 0x7f, 0, 0},{0x92a2, 0x2f, 0, 0},{0x92a3, 0xe5, 0, 0}, ++ {0x92a4, 0x0a, 0, 0},{0x92a5, 0xb4, 0, 0},{0x92a6, 0x02, 0, 0}, ++ {0x92a7, 0x04, 0, 0},{0x92a8, 0x7e, 0, 0},{0x92a9, 0x12, 0, 0}, ++ {0x92aa, 0x7f, 0, 0},{0x92ab, 0x34, 0, 0},{0x92ac, 0x8f, 0, 0}, ++ {0x92ad, 0x82, 0, 0},{0x92ae, 0x8e, 0, 0},{0x92af, 0x83, 0, 0}, ++ {0x92b0, 0xe4, 0, 0},{0x92b1, 0x93, 0, 0},{0x92b2, 0xf5, 0, 0}, ++ {0x92b3, 0x2c, 0, 0},{0x92b4, 0x74, 0, 0},{0x92b5, 0x01, 0, 0}, ++ {0x92b6, 0x93, 0, 0},{0x92b7, 0xf5, 0, 0},{0x92b8, 0x2d, 0, 0}, ++ {0x92b9, 0x74, 0, 0},{0x92ba, 0x02, 0, 0},{0x92bb, 0x93, 0, 0}, ++ {0x92bc, 0xf5, 0, 0},{0x92bd, 0x2e, 0, 0},{0x92be, 0x74, 0, 0}, ++ {0x92bf, 0x03, 0, 0},{0x92c0, 0x93, 0, 0},{0x92c1, 0xf5, 0, 0}, ++ {0x92c2, 0x2f, 0, 0},{0x92c3, 0x74, 0, 0},{0x92c4, 0x04, 0, 0}, ++ {0x92c5, 0x93, 0, 0},{0x92c6, 0xf5, 0, 0},{0x92c7, 0x30, 0, 0}, ++ {0x92c8, 0xe5, 0, 0},{0x92c9, 0x0a, 0, 0},{0x92ca, 0xb4, 0, 0}, ++ {0x92cb, 0x01, 0, 0},{0x92cc, 0x07, 0, 0},{0x92cd, 0x74, 0, 0}, ++ {0x92ce, 0x2c, 0, 0},{0x92cf, 0x25, 0, 0},{0x92d0, 0x78, 0, 0}, ++ {0x92d1, 0xf8, 0, 0},{0x92d2, 0x76, 0, 0},{0x92d3, 0x40, 0, 0}, ++ {0x92d4, 0xe5, 0, 0},{0x92d5, 0x0a, 0, 0},{0x92d6, 0xb4, 0, 0}, ++ {0x92d7, 0x02, 0, 0},{0x92d8, 0x07, 0, 0},{0x92d9, 0x74, 0, 0}, ++ {0x92da, 0x2c, 0, 0},{0x92db, 0x25, 0, 0},{0x92dc, 0x78, 0, 0}, ++ {0x92dd, 0xf8, 0, 0},{0x92de, 0x76, 0, 0},{0x92df, 0x80, 0, 0}, ++ {0x92e0, 0x22, 0, 0},{0x92e1, 0xc0, 0, 0},{0x92e2, 0xe0, 0, 0}, ++ {0x92e3, 0xc0, 0, 0},{0x92e4, 0x83, 0, 0},{0x92e5, 0xc0, 0, 0}, ++ {0x92e6, 0x82, 0, 0},{0x92e7, 0xc0, 0, 0},{0x92e8, 0xd0, 0, 0}, ++ {0x92e9, 0x90, 0, 0},{0x92ea, 0x3f, 0, 0},{0x92eb, 0x0d, 0, 0}, ++ {0x92ec, 0xe0, 0, 0},{0x92ed, 0xf5, 0, 0},{0x92ee, 0x09, 0, 0}, ++ {0x92ef, 0xe5, 0, 0},{0x92f0, 0x09, 0, 0},{0x92f1, 0x30, 0, 0}, ++ {0x92f2, 0xe0, 0, 0},{0x92f3, 0x2e, 0, 0},{0x92f4, 0xe5, 0, 0}, ++ {0x92f5, 0x79, 0, 0},{0x92f6, 0xb4, 0, 0},{0x92f7, 0x01, 0, 0}, ++ {0x92f8, 0x09, 0, 0},{0x92f9, 0x90, 0, 0},{0x92fa, 0x3a, 0, 0}, ++ {0x92fb, 0x00, 0, 0},{0x92fc, 0xe0, 0, 0},{0x92fd, 0xf5, 0, 0}, ++ {0x92fe, 0x77, 0, 0},{0x92ff, 0x44, 0, 0},{0x9300, 0x01, 0, 0}, ++ {0x9301, 0xf0, 0, 0},{0x9302, 0xe5, 0, 0},{0x9303, 0x79, 0, 0}, ++ {0x9304, 0xb4, 0, 0},{0x9305, 0x03, 0, 0},{0x9306, 0x09, 0, 0}, ++ {0x9307, 0x90, 0, 0},{0x9308, 0x3a, 0, 0},{0x9309, 0x00, 0, 0}, ++ {0x930a, 0xe0, 0, 0},{0x930b, 0xf5, 0, 0},{0x930c, 0x77, 0, 0}, ++ {0x930d, 0x54, 0, 0},{0x930e, 0xfe, 0, 0},{0x930f, 0xf0, 0, 0}, ++ {0x9310, 0xe5, 0, 0},{0x9311, 0x79, 0, 0},{0x9312, 0xb4, 0, 0}, ++ {0x9313, 0x03, 0, 0},{0x9314, 0x05, 0, 0},{0x9315, 0x75, 0, 0}, ++ {0x9316, 0x79, 0, 0},{0x9317, 0x00, 0, 0},{0x9318, 0x80, 0, 0}, ++ {0x9319, 0x02, 0, 0},{0x931a, 0x05, 0, 0},{0x931b, 0x79, 0, 0}, ++ {0x931c, 0x90, 0, 0},{0x931d, 0x3f, 0, 0},{0x931e, 0x0d, 0, 0}, ++ {0x931f, 0x74, 0, 0},{0x9320, 0x01, 0, 0},{0x9321, 0xf0, 0, 0}, ++ {0x9322, 0xd0, 0, 0},{0x9323, 0xd0, 0, 0},{0x9324, 0xd0, 0, 0}, ++ {0x9325, 0x82, 0, 0},{0x9326, 0xd0, 0, 0},{0x9327, 0x83, 0, 0}, ++ {0x9328, 0xd0, 0, 0},{0x9329, 0xe0, 0, 0},{0x932a, 0x32, 0, 0}, ++ {0x932b, 0x90, 0, 0},{0x932c, 0x50, 0, 0},{0x932d, 0x27, 0, 0}, ++ {0x932e, 0xe0, 0, 0},{0x932f, 0x44, 0, 0},{0x9330, 0x01, 0, 0}, ++ {0x9331, 0xf0, 0, 0},{0x9332, 0x90, 0, 0},{0x9333, 0x50, 0, 0}, ++ {0x9334, 0x34, 0, 0},{0x9335, 0x74, 0, 0},{0x9336, 0x80, 0, 0}, ++ {0x9337, 0xf0, 0, 0},{0x9338, 0xa3, 0, 0},{0x9339, 0x74, 0, 0}, ++ {0x933a, 0x2a, 0, 0},{0x933b, 0xf0, 0, 0},{0x933c, 0xa3, 0, 0}, ++ {0x933d, 0x74, 0, 0},{0x933e, 0x14, 0, 0},{0x933f, 0xf0, 0, 0}, ++ {0x9340, 0x90, 0, 0},{0x9341, 0x50, 0, 0},{0x9342, 0x30, 0, 0}, ++ {0x9343, 0xe4, 0, 0},{0x9344, 0xf0, 0, 0},{0x9345, 0xa3, 0, 0}, ++ {0x9346, 0x74, 0, 0},{0x9347, 0x02, 0, 0},{0x9348, 0xf0, 0, 0}, ++ {0x9349, 0xa3, 0, 0},{0x934a, 0xe4, 0, 0},{0x934b, 0xf0, 0, 0}, ++ {0x934c, 0xa3, 0, 0},{0x934d, 0x74, 0, 0},{0x934e, 0x80, 0, 0}, ++ {0x934f, 0xf0, 0, 0},{0x9350, 0xe4, 0, 0},{0x9351, 0xf5, 0, 0}, ++ {0x9352, 0x0a, 0, 0},{0x9353, 0x12, 0, 0},{0x9354, 0x10, 0, 0}, ++ {0x9355, 0xb5, 0, 0},{0x9356, 0x75, 0, 0},{0x9357, 0x78, 0, 0}, ++ {0x9358, 0x02, 0, 0},{0x9359, 0x75, 0, 0},{0x935a, 0x0a, 0, 0}, ++ {0x935b, 0x01, 0, 0},{0x935c, 0x12, 0, 0},{0x935d, 0x12, 0, 0}, ++ {0x935e, 0x92, 0, 0},{0x935f, 0xd2, 0, 0},{0x9360, 0x18, 0, 0}, ++ {0x9361, 0xd2, 0, 0},{0x9362, 0x19, 0, 0},{0x9363, 0xc2, 0, 0}, ++ {0x9364, 0x3a, 0, 0},{0x9365, 0xc2, 0, 0},{0x9366, 0x39, 0, 0}, ++ {0x9367, 0xd2, 0, 0},{0x9368, 0x1a, 0, 0},{0x9369, 0xd2, 0, 0}, ++ {0x936a, 0x36, 0, 0},{0x936b, 0xd2, 0, 0},{0x936c, 0x30, 0, 0}, ++ {0x936d, 0xc2, 0, 0},{0x936e, 0x35, 0, 0},{0x936f, 0xc2, 0, 0}, ++ {0x9370, 0x3b, 0, 0},{0x9371, 0x22, 0, 0},{0x9372, 0x85, 0, 0}, ++ {0x9373, 0x13, 0, 0},{0x9374, 0x14, 0, 0},{0x9375, 0x7f, 0, 0}, ++ {0x9376, 0x08, 0, 0},{0x9377, 0xe5, 0, 0},{0x9378, 0x14, 0, 0}, ++ {0x9379, 0x30, 0, 0},{0x937a, 0xe7, 0, 0},{0x937b, 0x04, 0, 0}, ++ {0x937c, 0xd2, 0, 0},{0x937d, 0x29, 0, 0},{0x937e, 0x80, 0, 0}, ++ {0x937f, 0x02, 0, 0},{0x9380, 0xc2, 0, 0},{0x9381, 0x29, 0, 0}, ++ {0x9382, 0x12, 0, 0},{0x9383, 0x01, 0, 0},{0x9384, 0x6c, 0, 0}, ++ {0x9385, 0x75, 0, 0},{0x9386, 0x51, 0, 0},{0x9387, 0x0a, 0, 0}, ++ {0x9388, 0xae, 0, 0},{0x9389, 0x51, 0, 0},{0x938a, 0x15, 0, 0}, ++ {0x938b, 0x51, 0, 0},{0x938c, 0xee, 0, 0},{0x938d, 0x70, 0, 0}, ++ {0x938e, 0xf9, 0, 0},{0x938f, 0xe5, 0, 0},{0x9390, 0x14, 0, 0}, ++ {0x9391, 0x25, 0, 0},{0x9392, 0xe0, 0, 0},{0x9393, 0xf5, 0, 0}, ++ {0x9394, 0x14, 0, 0},{0x9395, 0xd2, 0, 0},{0x9396, 0x28, 0, 0}, ++ {0x9397, 0x12, 0, 0},{0x9398, 0x01, 0, 0},{0x9399, 0x6c, 0, 0}, ++ {0x939a, 0x75, 0, 0},{0x939b, 0x51, 0, 0},{0x939c, 0x0a, 0, 0}, ++ {0x939d, 0xae, 0, 0},{0x939e, 0x51, 0, 0},{0x939f, 0x15, 0, 0}, ++ {0x93a0, 0x51, 0, 0},{0x93a1, 0xee, 0, 0},{0x93a2, 0x70, 0, 0}, ++ {0x93a3, 0xf9, 0, 0},{0x93a4, 0xc2, 0, 0},{0x93a5, 0x28, 0, 0}, ++ {0x93a6, 0x12, 0, 0},{0x93a7, 0x01, 0, 0},{0x93a8, 0x6c, 0, 0}, ++ {0x93a9, 0x75, 0, 0},{0x93aa, 0x51, 0, 0},{0x93ab, 0x05, 0, 0}, ++ {0x93ac, 0xae, 0, 0},{0x93ad, 0x51, 0, 0},{0x93ae, 0x15, 0, 0}, ++ {0x93af, 0x51, 0, 0},{0x93b0, 0xee, 0, 0},{0x93b1, 0x70, 0, 0}, ++ {0x93b2, 0xf9, 0, 0},{0x93b3, 0xdf, 0, 0},{0x93b4, 0xc2, 0, 0}, ++ {0x93b5, 0x22, 0, 0},{0x93b6, 0xc2, 0, 0},{0x93b7, 0xaf, 0, 0}, ++ {0x93b8, 0x90, 0, 0},{0x93b9, 0x30, 0, 0},{0x93ba, 0x27, 0, 0}, ++ {0x93bb, 0x74, 0, 0},{0x93bc, 0xfa, 0, 0},{0x93bd, 0xf0, 0, 0}, ++ {0x93be, 0x12, 0, 0},{0x93bf, 0x0e, 0, 0},{0x93c0, 0x71, 0, 0}, ++ {0x93c1, 0x12, 0, 0},{0x93c2, 0x14, 0, 0},{0x93c3, 0x84, 0, 0}, ++ {0x93c4, 0xe4, 0, 0},{0x93c5, 0xf5, 0, 0},{0x93c6, 0x33, 0, 0}, ++ {0x93c7, 0xd2, 0, 0},{0x93c8, 0xaf, 0, 0},{0x93c9, 0x12, 0, 0}, ++ {0x93ca, 0x0c, 0, 0},{0x93cb, 0x69, 0, 0},{0x93cc, 0x30, 0, 0}, ++ {0x93cd, 0x30, 0, 0},{0x93ce, 0x03, 0, 0},{0x93cf, 0x12, 0, 0}, ++ {0x93d0, 0x06, 0, 0},{0x93d1, 0xdf, 0, 0},{0x93d2, 0x30, 0, 0}, ++ {0x93d3, 0x34, 0, 0},{0x93d4, 0x03, 0, 0},{0x93d5, 0x12, 0, 0}, ++ {0x93d6, 0x12, 0, 0},{0x93d7, 0x39, 0, 0},{0x93d8, 0x30, 0, 0}, ++ {0x93d9, 0x3b, 0, 0},{0x93da, 0xee, 0, 0},{0x93db, 0xc2, 0, 0}, ++ {0x93dc, 0x3b, 0, 0},{0x93dd, 0xd2, 0, 0},{0x93de, 0x35, 0, 0}, ++ {0x93df, 0x30, 0, 0},{0x93e0, 0x00, 0, 0},{0x93e1, 0x05, 0, 0}, ++ {0x93e2, 0x12, 0, 0},{0x93e3, 0x14, 0, 0},{0x93e4, 0x57, 0, 0}, ++ {0x93e5, 0x80, 0, 0},{0x93e6, 0x09, 0, 0},{0x93e7, 0x20, 0, 0}, ++ {0x93e8, 0x07, 0, 0},{0x93e9, 0x06, 0, 0},{0x93ea, 0x30, 0, 0}, ++ {0x93eb, 0x06, 0, 0},{0x93ec, 0x03, 0, 0},{0x93ed, 0x12, 0, 0}, ++ {0x93ee, 0x0d, 0, 0},{0x93ef, 0x77, 0, 0},{0x93f0, 0xc2, 0, 0}, ++ {0x93f1, 0x35, 0, 0},{0x93f2, 0x80, 0, 0},{0x93f3, 0xd5, 0, 0}, ++ {0x93f4, 0x12, 0, 0},{0x93f5, 0x10, 0, 0},{0x93f6, 0x3d, 0, 0}, ++ {0x93f7, 0xd2, 0, 0},{0x93f8, 0x3c, 0, 0},{0x93f9, 0x12, 0, 0}, ++ {0x93fa, 0x0f, 0, 0},{0x93fb, 0xb0, 0, 0},{0x93fc, 0xd2, 0, 0}, ++ {0x93fd, 0x3c, 0, 0},{0x93fe, 0x12, 0, 0},{0x93ff, 0x11, 0, 0}, ++ {0x9400, 0x1a, 0, 0},{0x9401, 0xe5, 0, 0},{0x9402, 0x7b, 0, 0}, ++ {0x9403, 0xd3, 0, 0},{0x9404, 0x95, 0, 0},{0x9405, 0x7c, 0, 0}, ++ {0x9406, 0x40, 0, 0},{0x9407, 0x03, 0, 0},{0x9408, 0xd3, 0, 0}, ++ {0x9409, 0x80, 0, 0},{0x940a, 0x01, 0, 0},{0x940b, 0xc3, 0, 0}, ++ {0x940c, 0x50, 0, 0},{0x940d, 0x14, 0, 0},{0x940e, 0x20, 0, 0}, ++ {0x940f, 0x37, 0, 0},{0x9410, 0x0e, 0, 0},{0x9411, 0xe5, 0, 0}, ++ {0x9412, 0x24, 0, 0},{0x9413, 0x54, 0, 0},{0x9414, 0x1f, 0, 0}, ++ {0x9415, 0xff, 0, 0},{0x9416, 0xbf, 0, 0},{0x9417, 0x1f, 0, 0}, ++ {0x9418, 0x06, 0, 0},{0x9419, 0x30, 0, 0},{0x941a, 0x25, 0, 0}, ++ {0x941b, 0x03, 0, 0},{0x941c, 0x20, 0, 0},{0x941d, 0x26, 0, 0}, ++ {0x941e, 0x03, 0, 0},{0x941f, 0x02, 0, 0},{0x9420, 0x15, 0, 0}, ++ {0x9421, 0x2c, 0, 0},{0x9422, 0x12, 0, 0},{0x9423, 0x02, 0, 0}, ++ {0x9424, 0xb6, 0, 0},{0x9425, 0x22, 0, 0},{0x9426, 0xe5, 0, 0}, ++ {0x9427, 0x7c, 0, 0},{0x9428, 0x70, 0, 0},{0x9429, 0x19, 0, 0}, ++ {0x942a, 0x12, 0, 0},{0x942b, 0x15, 0, 0},{0x942c, 0x04, 0, 0}, ++ {0x942d, 0xc2, 0, 0},{0x942e, 0x3c, 0, 0},{0x942f, 0x12, 0, 0}, ++ {0x9430, 0x0f, 0, 0},{0x9431, 0xb0, 0, 0},{0x9432, 0xc2, 0, 0}, ++ {0x9433, 0x3c, 0, 0},{0x9434, 0x12, 0, 0},{0x9435, 0x11, 0, 0}, ++ {0x9436, 0x1a, 0, 0},{0x9437, 0xc2, 0, 0},{0x9438, 0x03, 0, 0}, ++ {0x9439, 0x12, 0, 0},{0x943a, 0x15, 0, 0},{0x943b, 0x2c, 0, 0}, ++ {0x943c, 0xd2, 0, 0},{0x943d, 0x02, 0, 0},{0x943e, 0xd2, 0, 0}, ++ {0x943f, 0x01, 0, 0},{0x9440, 0xd2, 0, 0},{0x9441, 0x00, 0, 0}, ++ {0x9442, 0x22, 0, 0},{0x9443, 0x30, 0, 0},{0x9444, 0x03, 0, 0}, ++ {0x9445, 0x08, 0, 0},{0x9446, 0xc2, 0, 0},{0x9447, 0x03, 0, 0}, ++ {0x9448, 0xc2, 0, 0},{0x9449, 0x04, 0, 0},{0x944a, 0x12, 0, 0}, ++ {0x944b, 0x02, 0, 0},{0x944c, 0xa5, 0, 0},{0x944d, 0x22, 0, 0}, ++ {0x944e, 0xe4, 0, 0},{0x944f, 0xf5, 0, 0},{0x9450, 0x0c, 0, 0}, ++ {0x9451, 0x12, 0, 0},{0x9452, 0x0f, 0, 0},{0x9453, 0x11, 0, 0}, ++ {0x9454, 0xd2, 0, 0},{0x9455, 0x03, 0, 0},{0x9456, 0x22, 0, 0}, ++ {0x9457, 0xe5, 0, 0},{0x9458, 0x20, 0, 0},{0x9459, 0x54, 0, 0}, ++ {0x945a, 0x07, 0, 0},{0x945b, 0xff, 0, 0},{0x945c, 0xbf, 0, 0}, ++ {0x945d, 0x01, 0, 0},{0x945e, 0x03, 0, 0},{0x945f, 0x02, 0, 0}, ++ {0x9460, 0x14, 0, 0},{0x9461, 0x26, 0, 0},{0x9462, 0xe5, 0, 0}, ++ {0x9463, 0x20, 0, 0},{0x9464, 0x54, 0, 0},{0x9465, 0x07, 0, 0}, ++ {0x9466, 0xff, 0, 0},{0x9467, 0xbf, 0, 0},{0x9468, 0x07, 0, 0}, ++ {0x9469, 0x03, 0, 0},{0x946a, 0x02, 0, 0},{0x946b, 0x14, 0, 0}, ++ {0x946c, 0xaa, 0, 0},{0x946d, 0xe5, 0, 0},{0x946e, 0x20, 0, 0}, ++ {0x946f, 0x54, 0, 0},{0x9470, 0x07, 0, 0},{0x9471, 0xff, 0, 0}, ++ {0x9472, 0xbf, 0, 0},{0x9473, 0x03, 0, 0},{0x9474, 0x03, 0, 0}, ++ {0x9475, 0x02, 0, 0},{0x9476, 0x13, 0, 0},{0x9477, 0xf4, 0, 0}, ++ {0x9478, 0xe5, 0, 0},{0x9479, 0x20, 0, 0},{0x947a, 0x54, 0, 0}, ++ {0x947b, 0x07, 0, 0},{0x947c, 0xff, 0, 0},{0x947d, 0xbf, 0, 0}, ++ {0x947e, 0x05, 0, 0},{0x947f, 0x03, 0, 0},{0x9480, 0x12, 0, 0}, ++ {0x9481, 0x15, 0, 0},{0x9482, 0x6a, 0, 0},{0x9483, 0x22, 0, 0}, ++ {0x9484, 0x12, 0, 0},{0x9485, 0x13, 0, 0},{0x9486, 0x2b, 0, 0}, ++ {0x9487, 0x12, 0, 0},{0x9488, 0x15, 0, 0},{0x9489, 0x78, 0, 0}, ++ {0x948a, 0x50, 0, 0},{0x948b, 0x04, 0, 0},{0x948c, 0xd2, 0, 0}, ++ {0x948d, 0x05, 0, 0},{0x948e, 0x80, 0, 0},{0x948f, 0x02, 0, 0}, ++ {0x9490, 0xc2, 0, 0},{0x9491, 0x05, 0, 0},{0x9492, 0x12, 0, 0}, ++ {0x9493, 0x02, 0, 0},{0x9494, 0x40, 0, 0},{0x9495, 0xc2, 0, 0}, ++ {0x9496, 0x37, 0, 0},{0x9497, 0xc2, 0, 0},{0x9498, 0x31, 0, 0}, ++ {0x9499, 0xd2, 0, 0},{0x949a, 0x34, 0, 0},{0x949b, 0x12, 0, 0}, ++ {0x949c, 0x02, 0, 0},{0x949d, 0x85, 0, 0},{0x949e, 0xb5, 0, 0}, ++ {0x949f, 0x07, 0, 0},{0x94a0, 0x03, 0, 0},{0x94a1, 0xd3, 0, 0}, ++ {0x94a2, 0x80, 0, 0},{0x94a3, 0x01, 0, 0},{0x94a4, 0xc3, 0, 0}, ++ {0x94a5, 0x40, 0, 0},{0x94a6, 0x02, 0, 0},{0x94a7, 0xc2, 0, 0}, ++ {0x94a8, 0x05, 0, 0},{0x94a9, 0x22, 0, 0},{0x94aa, 0x12, 0, 0}, ++ {0x94ab, 0x10, 0, 0},{0x94ac, 0x3d, 0, 0},{0x94ad, 0xd2, 0, 0}, ++ {0x94ae, 0x3c, 0, 0},{0x94af, 0x12, 0, 0},{0x94b0, 0x0f, 0, 0}, ++ {0x94b1, 0xb0, 0, 0},{0x94b2, 0xd2, 0, 0},{0x94b3, 0x3c, 0, 0}, ++ {0x94b4, 0x12, 0, 0},{0x94b5, 0x11, 0, 0},{0x94b6, 0x1a, 0, 0}, ++ {0x94b7, 0x12, 0, 0},{0x94b8, 0x15, 0, 0},{0x94b9, 0x2c, 0, 0}, ++ {0x94ba, 0xe5, 0, 0},{0x94bb, 0x32, 0, 0},{0x94bc, 0xd3, 0, 0}, ++ {0x94bd, 0x95, 0, 0},{0x94be, 0x7c, 0, 0},{0x94bf, 0x40, 0, 0}, ++ {0x94c0, 0x05, 0, 0},{0x94c1, 0xe4, 0, 0},{0x94c2, 0x95, 0, 0}, ++ {0x94c3, 0x7c, 0, 0},{0x94c4, 0x40, 0, 0},{0x94c5, 0x06, 0, 0}, ++ {0x94c6, 0xc2, 0, 0},{0x94c7, 0x02, 0, 0},{0x94c8, 0xd2, 0, 0}, ++ {0x94c9, 0x01, 0, 0},{0x94ca, 0xd2, 0, 0},{0x94cb, 0x00, 0, 0}, ++ {0x94cc, 0x22, 0, 0},{0x94cd, 0xe4, 0, 0},{0x94ce, 0xff, 0, 0}, ++ {0x94cf, 0xfe, 0, 0},{0x94d0, 0xc3, 0, 0},{0x94d1, 0xef, 0, 0}, ++ {0x94d2, 0x95, 0, 0},{0x94d3, 0x11, 0, 0},{0x94d4, 0xee, 0, 0}, ++ {0x94d5, 0x95, 0, 0},{0x94d6, 0x10, 0, 0},{0x94d7, 0x50, 0, 0}, ++ {0x94d8, 0x15, 0, 0},{0x94d9, 0x7d, 0, 0},{0x94da, 0x8a, 0, 0}, ++ {0x94db, 0x7c, 0, 0},{0x94dc, 0x02, 0, 0},{0x94dd, 0xed, 0, 0}, ++ {0x94de, 0x1d, 0, 0},{0x94df, 0xaa, 0, 0},{0x94e0, 0x04, 0, 0}, ++ {0x94e1, 0x70, 0, 0},{0x94e2, 0x01, 0, 0},{0x94e3, 0x1c, 0, 0}, ++ {0x94e4, 0x4a, 0, 0},{0x94e5, 0x70, 0, 0},{0x94e6, 0xf6, 0, 0}, ++ {0x94e7, 0x0f, 0, 0},{0x94e8, 0xbf, 0, 0},{0x94e9, 0x00, 0, 0}, ++ {0x94ea, 0x01, 0, 0},{0x94eb, 0x0e, 0, 0},{0x94ec, 0x80, 0, 0}, ++ {0x94ed, 0xe2, 0, 0},{0x94ee, 0x22, 0, 0},{0x94ef, 0x75, 0, 0}, ++ {0x94f0, 0x48, 0, 0},{0x94f1, 0x11, 0, 0},{0x94f2, 0x75, 0, 0}, ++ {0x94f3, 0x49, 0, 0},{0x94f4, 0xe0, 0, 0},{0x94f5, 0x90, 0, 0}, ++ {0x94f6, 0x11, 0, 0},{0x94f7, 0xde, 0, 0},{0x94f8, 0xe4, 0, 0}, ++ {0x94f9, 0x93, 0, 0},{0x94fa, 0xf5, 0, 0},{0x94fb, 0x7b, 0, 0}, ++ {0x94fc, 0xa3, 0, 0},{0x94fd, 0xe4, 0, 0},{0x94fe, 0x93, 0, 0}, ++ {0x94ff, 0xf5, 0, 0},{0x9500, 0x32, 0, 0},{0x9501, 0xc2, 0, 0}, ++ {0x9502, 0x38, 0, 0},{0x9503, 0x22, 0, 0},{0x9504, 0xe4, 0, 0}, ++ {0x9505, 0xff, 0, 0},{0x9506, 0xef, 0, 0},{0x9507, 0x25, 0, 0}, ++ {0x9508, 0xe0, 0, 0},{0x9509, 0x24, 0, 0},{0x950a, 0x56, 0, 0}, ++ {0x950b, 0xf8, 0, 0},{0x950c, 0xe4, 0, 0},{0x950d, 0xf6, 0, 0}, ++ {0x950e, 0x08, 0, 0},{0x950f, 0xf6, 0, 0},{0x9510, 0x0f, 0, 0}, ++ {0x9511, 0xbf, 0, 0},{0x9512, 0x07, 0, 0},{0x9513, 0xf2, 0, 0}, ++ {0x9514, 0x53, 0, 0},{0x9515, 0x24, 0, 0},{0x9516, 0x80, 0, 0}, ++ {0x9517, 0x22, 0, 0},{0x9518, 0xc2, 0, 0},{0x9519, 0x03, 0, 0}, ++ {0x951a, 0xd2, 0, 0},{0x951b, 0x04, 0, 0},{0x951c, 0x12, 0, 0}, ++ {0x951d, 0x02, 0, 0},{0x951e, 0xa5, 0, 0},{0x951f, 0xc2, 0, 0}, ++ {0x9520, 0x3c, 0, 0},{0x9521, 0x12, 0, 0},{0x9522, 0x0f, 0, 0}, ++ {0x9523, 0xb0, 0, 0},{0x9524, 0xc2, 0, 0},{0x9525, 0x3c, 0, 0}, ++ {0x9526, 0x12, 0, 0},{0x9527, 0x11, 0, 0},{0x9528, 0x1a, 0, 0}, ++ {0x9529, 0xd2, 0, 0},{0x952a, 0x34, 0, 0},{0x952b, 0x22, 0, 0}, ++ {0x952c, 0xe5, 0, 0},{0x952d, 0x7c, 0, 0},{0x952e, 0xc3, 0, 0}, ++ {0x952f, 0x95, 0, 0},{0x9530, 0x7b, 0, 0},{0x9531, 0x40, 0, 0}, ++ {0x9532, 0x01, 0, 0},{0x9533, 0x22, 0, 0},{0x9534, 0xe5, 0, 0}, ++ {0x9535, 0x7c, 0, 0},{0x9536, 0x04, 0, 0},{0x9537, 0xf5, 0, 0}, ++ {0x9538, 0x0c, 0, 0},{0x9539, 0x12, 0, 0},{0x953a, 0x0f, 0, 0}, ++ {0x953b, 0x11, 0, 0},{0x953c, 0x22, 0, 0},{0x953d, 0xe5, 0, 0}, ++ {0x953e, 0x7c, 0, 0},{0x953f, 0x70, 0, 0},{0x9540, 0x02, 0, 0}, ++ {0x9541, 0xc3, 0, 0},{0x9542, 0x22, 0, 0},{0x9543, 0xe5, 0, 0}, ++ {0x9544, 0x7c, 0, 0},{0x9545, 0x14, 0, 0},{0x9546, 0xf5, 0, 0}, ++ {0x9547, 0x0c, 0, 0},{0x9548, 0x12, 0, 0},{0x9549, 0x0f, 0, 0}, ++ {0x954a, 0x11, 0, 0},{0x954b, 0x22, 0, 0},{0x954c, 0xe5, 0, 0}, ++ {0x954d, 0x7d, 0, 0},{0x954e, 0xb4, 0, 0},{0x954f, 0x01, 0, 0}, ++ {0x9550, 0x09, 0, 0},{0x9551, 0x12, 0, 0},{0x9552, 0x14, 0, 0}, ++ {0x9553, 0xef, 0, 0},{0x9554, 0xe4, 0, 0},{0x9555, 0xf5, 0, 0}, ++ {0x9556, 0x0c, 0, 0},{0x9557, 0x12, 0, 0},{0x9558, 0x0f, 0, 0}, ++ {0x9559, 0x11, 0, 0},{0x955a, 0x22, 0, 0},{0x955b, 0xe5, 0, 0}, ++ {0x955c, 0x7d, 0, 0},{0x955d, 0x24, 0, 0},{0x955e, 0xfe, 0, 0}, ++ {0x955f, 0x60, 0, 0},{0x9560, 0x06, 0, 0},{0x9561, 0x04, 0, 0}, ++ {0x9562, 0x70, 0, 0},{0x9563, 0x05, 0, 0},{0x9564, 0xd2, 0, 0}, ++ {0x9565, 0x37, 0, 0},{0x9566, 0x22, 0, 0},{0x9567, 0xc2, 0, 0}, ++ {0x9568, 0x37, 0, 0},{0x9569, 0x22, 0, 0},{0x956a, 0xe5, 0, 0}, ++ {0x956b, 0x31, 0, 0},{0x956c, 0xd3, 0, 0},{0x956d, 0x94, 0, 0}, ++ {0x956e, 0x00, 0, 0},{0x956f, 0x40, 0, 0},{0x9570, 0x03, 0, 0}, ++ {0x9571, 0x15, 0, 0},{0x9572, 0x31, 0, 0},{0x9573, 0x22, 0, 0}, ++ {0x9574, 0x12, 0, 0},{0x9575, 0x15, 0, 0},{0x9576, 0x18, 0, 0}, ++ {0x9577, 0x22, 0, 0},{0x9578, 0x12, 0, 0},{0x9579, 0x14, 0, 0}, ++ {0x957a, 0xef, 0, 0},{0x957b, 0xe4, 0, 0},{0x957c, 0xf5, 0, 0}, ++ {0x957d, 0x0c, 0, 0},{0x957e, 0x12, 0, 0},{0x957f, 0x0f, 0, 0}, ++ {0x9580, 0x11, 0, 0},{0x9581, 0x22, 0, 0},{0x3024, 0x00, 0, 0}, ++ {0x3025, 0x00, 0, 0},{0x5082, 0x00, 0, 0},{0x5083, 0x00, 0, 0}, ++ {0x5084, 0x00, 0, 0},{0x5085, 0x00, 0, 0},{0x3026, 0x00, 0, 0}, ++ {0x3027, 0xFF, 0, 0},{0x3000, 0x00, 0, 0}, ++}; ++ ++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_idle_mode(void) { ++ register u16 RegAddr = 0; ++ u8 ReadVal = 0; ++ u8 WriteVal = 0; ++ int retval = 0; ++ int lc = 0; ++ ++ ReadVal = -1; ++ RegAddr = REG_STA_FOCUS; ++ retval = ov5642_read_reg(RegAddr, &ReadVal); ++ if (retval < 0) { ++ pr_err("%s, read reg 0x%x failed\n", __FUNCTION__, RegAddr); ++ } ++ ++ for (lc = 0; (lc < 100) && (ReadVal != S_IDLE); ++lc) { ++ WriteVal = CMD_IDLE_MODE; ++ RegAddr = REG_CMD_MAIN; ++ retval = ov5642_write_reg(RegAddr, WriteVal); ++ if (retval < 0) { ++ pr_err("%s, write reg 0x%x failed\n", __FUNCTION__, RegAddr); ++ } ++ ++ mdelay(1); ++ ++ ReadVal = -1; ++ RegAddr = REG_STA_FOCUS; ++ retval = ov5642_read_reg(RegAddr, &ReadVal); ++ if (retval < 0) { ++ pr_err("%s, read reg 0x%x failed\n", __FUNCTION__, RegAddr); ++ } ++ } ++ ++ if (ReadVal != S_IDLE) ++ retval = -1; ++ else ++ retval = 0; ++ return retval; ++} ++ ++static int ov5642_config_auto_focus(void){ ++ ov5642_write_reg(REG_CMD_TAG, 0x01); ++ ov5642_write_reg(REG_CMD_MAIN, 0x10); ++ return 0; ++} ++ ++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_auto_focus_start(void) { ++ register u16 RegAddr = 0; ++ u8 RegVal = 0; ++ int retval = 0; ++ ++ retval = ov5642_set_idle_mode(); ++ ov5642_config_auto_focus(); ++ ++ if (retval > -1) { ++ RegVal = CMD_SINGLE_FOCUS_MODE; ++ RegAddr = REG_CMD_MAIN; ++ retval = ov5642_write_reg(RegAddr, RegVal); ++ if (retval < 0) { ++ pr_err("%s, write reg 0x%x failed\n", __FUNCTION__, RegAddr); ++ } ++ } else { ++ pr_err("Could not get camera into idle mode. Abandoning focus attempt"); ++ } ++ ++ 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_AUTO_FOCUS_START: ++ retval = ov5642_auto_focus_start(); ++ break; ++ case V4L2_CID_AUTO_FOCUS_STOP: ++ retval = ov5642_set_idle_mode(); ++ 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; ++} ++ ++static int ioctl_send_command(struct v4l2_int_device *s, struct v4l2_send_command_control *vc) { ++ int ret = -1; ++ int retval1,retval2; ++ u8 loca_val=0; ++ ++ ret = ov5642_set_idle_mode(); ++ if (0 != ret) ++ pr_err("error %d setting idle mode\n", ret); ++ ov5642_config_auto_focus(); ++ switch (vc->id) { ++ case 101: //step to near ++ pr_debug("Stepping to near object\n"); ++ retval1=ov5642_write_reg(REG_CMD_TAG, 0x01); ++ retval2=ov5642_write_reg(REG_CMD_MAIN, 0x05); ++ if(retval1 == 0 && retval2 == 0) ++ ret = 0; ++ break; ++ case 102: //step to far ++ pr_debug("Stepping to far object\n"); ++ retval1=ov5642_write_reg(REG_CMD_TAG, 0x02); ++ retval2=ov5642_write_reg(REG_CMD_MAIN, 0x05); ++ if(retval1 == 0 && retval2 == 0) ++ ret = 0; ++ break; ++ ++ case 103: //step to furthest ++ pr_debug("Stepping to furthest object\n"); ++ retval1=ov5642_write_reg(REG_CMD_TAG, 0x03); ++ retval2=ov5642_write_reg(REG_CMD_MAIN, 0x05); ++ if(retval1 == 0 && retval2 == 0) ++ ret = 0; ++ break; ++ ++ case 104: //step to nearest ++ pr_debug("Stepping to nearest object\n"); ++ retval1=ov5642_write_reg(REG_CMD_TAG, 0x04); ++ retval2=ov5642_write_reg(REG_CMD_MAIN, 0x05); ++ if(retval1 == 0 && retval2 == 0) ++ ret = 0; ++ break; ++ ++ ++ case 105: //step to specified position ++ pr_debug("Stepping to position: %d\n", vc->value0); ++ if(vc->value0 < 0 || vc->value0 > 255) ++ return ret; ++ loca_val = vc->value0; ++ retval1=ov5642_write_reg(REG_CMD_TAG, 0x10); ++ retval2=ov5642_write_reg(REG_CMD_PARA0, loca_val); ++ ret=ov5642_write_reg(REG_CMD_MAIN, 0x05); ++ if(retval1 != 0 && retval2 != 0 && ret != 0) ++ ret = -1; ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * 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 }, ++ {vidioc_int_send_command_num, ++ (v4l2_int_ioctl_func *) ioctl_send_command}, ++}; ++ ++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; ++ struct reg_value *firmware_regs; ++ int i; ++ struct sensor_data *sensor = &ov5642_data; ++ ++ /* 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, "ipu_id", ++ &sensor->ipu_id); ++ if (retval) { ++ dev_err(dev, "ipu_id 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; ++ ++ pr_info("Upload Auto-focus firmware"); ++ firmware_regs = ov5642_af_firmware; ++ for (i = 0; i < ARRAY_SIZE(ov5642_af_firmware); ++i, ++firmware_regs) { ++ retval = ov5642_write_reg(firmware_regs->u16RegAddr, ++ firmware_regs->u8Val); ++ if (retval < 0) ++ break; ++ } ++ ++ 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.72.orig/drivers/media/platform/mxc/capture/ov5647_mipi.c linux-3.14.72/drivers/media/platform/mxc/capture/ov5647_mipi.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/ov5647_mipi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/ov5647_mipi.c 2016-06-19 22:11:55.181148143 +0200 +@@ -0,0 +1,3781 @@ ++/* ++ * 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 "v4l2-int-device.h" ++#include "mxc_v4l2_capture.h" ++ ++#define OV5647_VOLTAGE_ANALOG 2800000 ++#define OV5647_VOLTAGE_DIGITAL_CORE 1500000 ++#define OV5647_VOLTAGE_DIGITAL_IO 1800000 ++ ++#define MIN_FPS 15 ++#define MAX_FPS 30 ++#define DEFAULT_FPS 30 ++ ++#define OV5647_XCLK_MIN 6000000 ++#define OV5647_XCLK_MAX 27000000 ++ ++#define OV5647_CHIP_ID_HIGH_BYTE 0x300A ++#define OV5647_CHIP_ID_LOW_BYTE 0x300B ++ ++enum ov5647_mode { ++ ov5647_mode_MIN = 0, ++ ov5647_mode_960P_1280_960 = 0, ++ ov5647_mode_720P_1280_720 = 1, ++ ov5647_mode_1080P_1920_1080 = 2, ++ ov5647_mode_VGA_640_480 = 3, ++ ov5647_mode_XGA_1024_768 = 4, ++ ov5647_mode_960_720 = 5, ++ ov5647_mode_VGA_640_480_narrow = 6, ++ ov5647_mode_MAX = 6, ++ ov5647_mode_INIT = 0xff, /*only for sensor init*/ ++}; ++ ++enum ov5647_frame_rate { ++ ov5647_15_fps, ++ ov5647_30_fps ++}; ++ ++/* image size under 1280 * 960 are SUBSAMPLING ++ * image size upper 1280 * 960 are SCALING ++ */ ++enum ov5647_downsize_mode { ++ SUBSAMPLING, ++ SCALING, ++}; ++ ++struct reg_value { ++ u16 u16RegAddr; ++ u8 u8Val; ++ u8 u8Mask; ++ u32 u32Delay_ms; ++}; ++ ++struct ov5647_mode_info { ++ enum ov5647_mode mode; ++ enum ov5647_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 ov5647_data; ++static struct additional_data ov5647_data_add; ++static int pwn_gpio = -EINVAL; ++static int powon_active; ++static int rst_gpio = -EINVAL; ++static int rst_active; ++static int led_gpio = -EINVAL; ++static int led_active; ++ ++static struct reg_value ov5647_setting_30fps_960P_1280_960[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x21 , 0 , 0 } , ++ { 0x3036 , 0x52 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x07 , 0 , 0 } , ++ { 0x380d , 0x68 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x05 , 0 , 0 } , ++ { 0x3809 , 0x00 , 0 , 0 } , ++ { 0x380a , 0x03 , 0 , 0 } , ++ { 0x380b , 0xc0 , 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 , 0xa1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_15fps_960P_1280_960[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0x52 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x07 , 0 , 0 } , ++ { 0x380d , 0x68 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x05 , 0 , 0 } , ++ { 0x3809 , 0x00 , 0 , 0 } , ++ { 0x380a , 0x03 , 0 , 0 } , ++ { 0x380b , 0xc0 , 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 , 0xa1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_30fps_720P_1280_720[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0xa0 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x06 , 0 , 0 } , ++ { 0x380d , 0xd6 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x05 , 0 , 0 } , ++ { 0x3809 , 0x00 , 0 , 0 } , ++ { 0x380a , 0x02 , 0 , 0 } , ++ { 0x380b , 0xd0 , 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 , 0x06 , 0 , 0 } , ++ { 0x3807 , 0xb2 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_15fps_720P_1280_720[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0x49 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x06 , 0 , 0 } , ++ { 0x380d , 0xd6 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x05 , 0 , 0 } , ++ { 0x3809 , 0x00 , 0 , 0 } , ++ { 0x380a , 0x02 , 0 , 0 } , ++ { 0x380b , 0xd0 , 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 , 0x06 , 0 , 0 } , ++ { 0x3807 , 0xb2 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_30fps_1080P_1920_1080[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x21 , 0 , 0 } , ++ { 0x3036 , 0x7b , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x06 , 0 , 0 } , ++ { 0x3820 , 0x00 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x04 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x36 , 0 , 0 } , ++ { 0x380d , 0x4e , 0 , 0 } , ++ { 0x380e , 0x04 , 0 , 0 } , ++ { 0x380f , 0x60 , 0 , 0 } , ++ { 0x3814 , 0x11 , 0 , 0 } , ++ { 0x3815 , 0x11 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x07 , 0 , 0 } , ++ { 0x3809 , 0x80 , 0 , 0 } , ++ { 0x380a , 0x04 , 0 , 0 } , ++ { 0x380b , 0x39 , 0 , 0 } , ++ { 0x3800 , 0x01 , 0 , 0 } , ++ { 0x3801 , 0x5c , 0 , 0 } , ++ { 0x3802 , 0x01 , 0 , 0 } , ++ { 0x3803 , 0xb2 , 0 , 0 } , ++ { 0x3804 , 0x08 , 0 , 0 } , ++ { 0x3805 , 0xe7 , 0 , 0 } , ++ { 0x3806 , 0x05 , 0 , 0 } , ++ { 0x3807 , 0xf1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_15fps_1080P_1920_1080[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0x7b , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x06 , 0 , 0 } , ++ { 0x3820 , 0x00 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x04 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x36 , 0 , 0 } , ++ { 0x380d , 0x4e , 0 , 0 } , ++ { 0x380e , 0x04 , 0 , 0 } , ++ { 0x380f , 0x60 , 0 , 0 } , ++ { 0x3814 , 0x11 , 0 , 0 } , ++ { 0x3815 , 0x11 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x07 , 0 , 0 } , ++ { 0x3809 , 0x80 , 0 , 0 } , ++ { 0x380a , 0x04 , 0 , 0 } , ++ { 0x380b , 0x39 , 0 , 0 } , ++ { 0x3800 , 0x01 , 0 , 0 } , ++ { 0x3801 , 0x5c , 0 , 0 } , ++ { 0x3802 , 0x01 , 0 , 0 } , ++ { 0x3803 , 0xb2 , 0 , 0 } , ++ { 0x3804 , 0x08 , 0 , 0 } , ++ { 0x3805 , 0xe7 , 0 , 0 } , ++ { 0x3806 , 0x05 , 0 , 0 } , ++ { 0x3807 , 0xf1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_30fps_VGA_640_480[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x21 , 0 , 0 } , ++ { 0x3036 , 0x52 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x07 , 0 , 0 } , ++ { 0x380d , 0x68 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x71 , 0 , 0 } , ++ { 0x3815 , 0x71 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x02 , 0 , 0 } , ++ { 0x3809 , 0x80 , 0 , 0 } , ++ { 0x380a , 0x01 , 0 , 0 } , ++ { 0x380b , 0xe0 , 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 , 0xa1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++ { 0x3814 , 0x31 , 0 , 0 } , /* overwrite */ ++ { 0x3815 , 0x31 , 0 , 0 } , /* overwrite */ ++}; ++ ++static struct reg_value ov5647_setting_15fps_VGA_640_480[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0x52 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x07 , 0 , 0 } , ++ { 0x380d , 0x68 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x71 , 0 , 0 } , ++ { 0x3815 , 0x71 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x02 , 0 , 0 } , ++ { 0x3809 , 0x80 , 0 , 0 } , ++ { 0x380a , 0x01 , 0 , 0 } , ++ { 0x380b , 0xe0 , 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 , 0xa1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++ { 0x3814 , 0x31 , 0 , 0 } , /* overwrite */ ++ { 0x3815 , 0x31 , 0 , 0 } , /* overwrite */ ++}; ++ ++static struct reg_value ov5647_setting_30fps_XGA_1024_768[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x21 , 0 , 0 } , ++ { 0x3036 , 0x52 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x07 , 0 , 0 } , ++ { 0x380d , 0x68 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x04 , 0 , 0 } , ++ { 0x3809 , 0x00 , 0 , 0 } , ++ { 0x380a , 0x03 , 0 , 0 } , ++ { 0x380b , 0x00 , 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 , 0xa1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_15fps_XGA_1024_768[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0x52 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x07 , 0 , 0 } , ++ { 0x380d , 0x68 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x04 , 0 , 0 } , ++ { 0x3809 , 0x00 , 0 , 0 } , ++ { 0x380a , 0x03 , 0 , 0 } , ++ { 0x380b , 0x00 , 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 , 0xa1 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_30fps_960_720[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0xa0 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x06 , 0 , 0 } , ++ { 0x380d , 0xd6 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x03 , 0 , 0 } , ++ { 0x3809 , 0xc0 , 0 , 0 } , ++ { 0x380a , 0x02 , 0 , 0 } , ++ { 0x380b , 0xd0 , 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 , 0x06 , 0 , 0 } , ++ { 0x3807 , 0xb2 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct reg_value ov5647_setting_15fps_960_720[] = { ++ { 0x0100 , 0x00 , 0 , 0 } , ++ { 0x0103 , 0x01 , 0 , 0 } , ++ { 0x3034 , 0x18 , 0 , 0 } , /* was 0x1A */ ++ { 0x3035 , 0x41 , 0 , 0 } , ++ { 0x3036 , 0x49 , 0 , 0 } , ++ { 0x303c , 0x11 , 0 , 0 } , ++ { 0x3106 , 0xf5 , 0 , 0 } , ++ { 0x3821 , 0x07 , 0 , 0 } , ++ { 0x3820 , 0x41 , 0 , 0 } , ++ { 0x3827 , 0xec , 0 , 0 } , ++ { 0x370c , 0x03 , 0 , 0 } , ++ { 0x3612 , 0x4b , 0 , 0 } , ++ { 0x3618 , 0x00 , 0 , 0 } , ++ { 0x5001 , 0x01 , 0 , 0 } , ++ { 0x5002 , 0x40 , 0 , 0 } , ++ { 0x5003 , 0x08 , 0 , 0 } , ++ { 0x5a00 , 0x08 , 0 , 0 } , ++ { 0x3000 , 0x00 , 0 , 0 } , ++ { 0x3001 , 0x00 , 0 , 0 } , ++ { 0x3002 , 0x00 , 0 , 0 } , ++ { 0x3016 , 0x08 , 0 , 0 } , ++ { 0x3017 , 0xe0 , 0 , 0 } , ++ { 0x3018 , 0x44 , 0 , 0 } , ++ { 0x301c , 0xf8 , 0 , 0 } , ++ { 0x301d , 0xf0 , 0 , 0 } , ++ { 0x3a18 , 0x00 , 0 , 0 } , ++ { 0x3a19 , 0xf8 , 0 , 0 } , ++ { 0x3c01 , 0x80 , 0 , 0 } , ++ { 0x3b07 , 0x0c , 0 , 0 } , ++ { 0x380c , 0x06 , 0 , 0 } , ++ { 0x380d , 0xd6 , 0 , 0 } , ++ { 0x380e , 0x03 , 0 , 0 } , ++ { 0x380f , 0xd8 , 0 , 0 } , ++ { 0x3814 , 0x31 , 0 , 0 } , ++ { 0x3815 , 0x31 , 0 , 0 } , ++ { 0x3708 , 0x64 , 0 , 0 } , ++ { 0x3709 , 0x52 , 0 , 0 } , ++ { 0x3808 , 0x03 , 0 , 0 } , ++ { 0x3809 , 0xc0 , 0 , 0 } , ++ { 0x380a , 0x02 , 0 , 0 } , ++ { 0x380b , 0xd0 , 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 , 0x06 , 0 , 0 } , ++ { 0x3807 , 0xb2 , 0 , 0 } , ++ { 0x3811 , 0x08 , 0 , 0 } , ++ { 0x3813 , 0x02 , 0 , 0 } , ++ { 0x3630 , 0x2e , 0 , 0 } , ++ { 0x3632 , 0xe2 , 0 , 0 } , ++ { 0x3633 , 0x23 , 0 , 0 } , ++ { 0x3634 , 0x44 , 0 , 0 } , ++ { 0x3636 , 0x06 , 0 , 0 } , ++ { 0x3620 , 0x64 , 0 , 0 } , ++ { 0x3621 , 0xe0 , 0 , 0 } , ++ { 0x3600 , 0x37 , 0 , 0 } , ++ { 0x3704 , 0xa0 , 0 , 0 } , ++ { 0x3703 , 0x5a , 0 , 0 } , ++ { 0x3715 , 0x78 , 0 , 0 } , ++ { 0x3717 , 0x01 , 0 , 0 } , ++ { 0x3731 , 0x02 , 0 , 0 } , ++ { 0x370b , 0x60 , 0 , 0 } , ++ { 0x3705 , 0x1a , 0 , 0 } , ++ { 0x3f05 , 0x02 , 0 , 0 } , ++ { 0x3f06 , 0x10 , 0 , 0 } , ++ { 0x3f01 , 0x0a , 0 , 0 } , ++ { 0x3a08 , 0x01 , 0 , 0 } , ++ { 0x3a09 , 0x27 , 0 , 0 } , ++ { 0x3a0a , 0x00 , 0 , 0 } , ++ { 0x3a0b , 0xf6 , 0 , 0 } , ++ { 0x3a0d , 0x04 , 0 , 0 } , ++ { 0x3a0e , 0x03 , 0 , 0 } , ++ { 0x3a0f , 0x58 , 0 , 0 } , ++ { 0x3a10 , 0x50 , 0 , 0 } , ++ { 0x3a1b , 0x58 , 0 , 0 } , ++ { 0x3a1e , 0x50 , 0 , 0 } , ++ { 0x3a11 , 0x60 , 0 , 0 } , ++ { 0x3a1f , 0x28 , 0 , 300 } , ++ { 0x4001 , 0x02 , 0 , 0 } , ++ { 0x4004 , 0x02 , 0 , 0 } , ++ { 0x4000 , 0x09 , 0 , 0 } , ++ { 0x4837 , 0x24 , 0 , 0 } , ++ { 0x4050 , 0x6e , 0 , 0 } , ++ { 0x4051 , 0x8f , 0 , 0 } , ++ { 0x0100 , 0x01 , 0 , 0 } , ++#if 0 ++ { 0x503d , 0xc0 , 0 , 0 } , /* test pattern */ ++ { 0x503e , 0x11 , 0 , 0 } , /* test pattern */ ++#endif ++ { 0x5000 , 0x86 , 0 , 0 } , /* enable LENC registers */ ++ { 0x5800 , 0x00 , 0 , 0 } , ++ { 0x5801 , 0x00 , 0 , 0 } , ++ { 0x5802 , 0x00 , 0 , 0 } , ++ { 0x5803 , 0x00 , 0 , 0 } , ++ { 0x5804 , 0x00 , 0 , 0 } , ++ { 0x5805 , 0x00 , 0 , 0 } , ++ { 0x5806 , 0x00 , 0 , 0 } , ++ { 0x5807 , 0x00 , 0 , 0 } , ++ { 0x5808 , 0x00 , 0 , 0 } , ++ { 0x5809 , 0x00 , 0 , 0 } , ++ { 0x580a , 0x00 , 0 , 0 } , ++ { 0x580b , 0x00 , 0 , 0 } , ++ { 0x580c , 0x00 , 0 , 0 } , ++ { 0x580d , 0x00 , 0 , 0 } , ++ { 0x580e , 0x00 , 0 , 0 } , ++ { 0x580f , 0x00 , 0 , 0 } , ++ { 0x5810 , 0x00 , 0 , 0 } , ++ { 0x5811 , 0x00 , 0 , 0 } , ++ { 0x5812 , 0x00 , 0 , 0 } , ++ { 0x5813 , 0x00 , 0 , 0 } , ++ { 0x5814 , 0x00 , 0 , 0 } , ++ { 0x5815 , 0x00 , 0 , 0 } , ++ { 0x5816 , 0x00 , 0 , 0 } , ++ { 0x5817 , 0x00 , 0 , 0 } , ++ { 0x5818 , 0x00 , 0 , 0 } , ++ { 0x5819 , 0x00 , 0 , 0 } , ++ { 0x581a , 0x00 , 0 , 0 } , ++ { 0x581b , 0x00 , 0 , 0 } , ++ { 0x581c , 0x00 , 0 , 0 } , ++ { 0x581d , 0x00 , 0 , 0 } , ++ { 0x581e , 0x00 , 0 , 0 } , ++ { 0x581f , 0x00 , 0 , 0 } , ++ { 0x5820 , 0x00 , 0 , 0 } , ++ { 0x5821 , 0x00 , 0 , 0 } , ++ { 0x5822 , 0x00 , 0 , 0 } , ++ { 0x5823 , 0x00 , 0 , 0 } , ++ { 0x5824 , 0xfe , 0 , 0 } , ++ { 0x5825 , 0xfe , 0 , 0 } , ++ { 0x5826 , 0xfe , 0 , 0 } , ++ { 0x5827 , 0xfe , 0 , 0 } , ++ { 0x5828 , 0xfe , 0 , 0 } , ++ { 0x5829 , 0xfe , 0 , 0 } , ++ { 0x582a , 0xed , 0 , 0 } , ++ { 0x582b , 0xed , 0 , 0 } , ++ { 0x582c , 0xed , 0 , 0 } , ++ { 0x582d , 0xfe , 0 , 0 } , ++ { 0x582e , 0xfe , 0 , 0 } , ++ { 0x582f , 0xed , 0 , 0 } , ++ { 0x5830 , 0xdc , 0 , 0 } , ++ { 0x5831 , 0xed , 0 , 0 } , ++ { 0x5832 , 0xfe , 0 , 0 } , ++ { 0x5833 , 0xfe , 0 , 0 } , ++ { 0x5834 , 0xed , 0 , 0 } , ++ { 0x5835 , 0xed , 0 , 0 } , ++ { 0x5836 , 0xed , 0 , 0 } , ++ { 0x5837 , 0xfe , 0 , 0 } , ++ { 0x5838 , 0xfe , 0 , 0 } , ++ { 0x5839 , 0xfe , 0 , 0 } , ++ { 0x583a , 0xfe , 0 , 0 } , ++ { 0x583b , 0xfe , 0 , 0 } , ++ { 0x583c , 0xfe , 0 , 0 } , ++ { 0x583d , 0xce , 0 , 0 } , ++ { 0x3501 , 0x10 , 0 , 0 } , ++ { 0x3502 , 0x80 , 0 , 0 } , ++ { 0x350a , 0x00 , 0 , 0 } , ++ { 0x350b , 0x7f , 0 , 0 } , ++ { 0x3c00 , 0x04 , 0 , 300 } , ++ { 0x3002 , 0xe4 , 0x01, 0 } , /* enable all outputs */ ++}; ++ ++static struct ov5647_mode_info ov5647_mode_info_data[2][ov5647_mode_MAX + 1] = { ++ { ++ {ov5647_mode_960P_1280_960, SUBSAMPLING, 1280, 960, ++ ov5647_setting_15fps_960P_1280_960, ++ ARRAY_SIZE(ov5647_setting_15fps_960P_1280_960)}, ++ {ov5647_mode_720P_1280_720, SUBSAMPLING, 1280, 720, ++ ov5647_setting_15fps_720P_1280_720, ++ ARRAY_SIZE(ov5647_setting_15fps_720P_1280_720)}, ++ {ov5647_mode_1080P_1920_1080, SCALING, 1920, 1080, ++ ov5647_setting_15fps_1080P_1920_1080, ++ ARRAY_SIZE(ov5647_setting_15fps_1080P_1920_1080)}, ++ {ov5647_mode_VGA_640_480, SUBSAMPLING, 640, 480, ++ ov5647_setting_15fps_VGA_640_480, ++ ARRAY_SIZE(ov5647_setting_15fps_VGA_640_480) - 2}, ++ {ov5647_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, ++ ov5647_setting_15fps_XGA_1024_768, ++ ARRAY_SIZE(ov5647_setting_15fps_XGA_1024_768)}, ++ {ov5647_mode_960_720, SUBSAMPLING, 960, 720, ++ ov5647_setting_15fps_960_720, ++ ARRAY_SIZE(ov5647_setting_15fps_960_720)}, ++ {ov5647_mode_VGA_640_480_narrow, SUBSAMPLING, 640, 480, ++ ov5647_setting_15fps_VGA_640_480, ++ ARRAY_SIZE(ov5647_setting_15fps_VGA_640_480)}, ++ }, ++ { ++ {ov5647_mode_960P_1280_960, SUBSAMPLING, 1280, 960, ++ ov5647_setting_30fps_960P_1280_960, ++ ARRAY_SIZE(ov5647_setting_30fps_960P_1280_960)}, ++ {ov5647_mode_720P_1280_720, SUBSAMPLING, 1280, 720, ++ ov5647_setting_30fps_720P_1280_720, ++ ARRAY_SIZE(ov5647_setting_30fps_720P_1280_720)}, ++ {ov5647_mode_1080P_1920_1080, SCALING, 1920, 1080, ++ ov5647_setting_30fps_1080P_1920_1080, ++ ARRAY_SIZE(ov5647_setting_30fps_1080P_1920_1080)}, ++ {ov5647_mode_VGA_640_480, SUBSAMPLING, 640, 480, ++ ov5647_setting_30fps_VGA_640_480, ++ ARRAY_SIZE(ov5647_setting_30fps_VGA_640_480) - 2}, ++ {ov5647_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, ++ ov5647_setting_30fps_XGA_1024_768, ++ ARRAY_SIZE(ov5647_setting_30fps_XGA_1024_768)}, ++ {ov5647_mode_960_720, SUBSAMPLING, 960, 720, ++ ov5647_setting_30fps_960_720, ++ ARRAY_SIZE(ov5647_setting_15fps_960_720)}, ++ {ov5647_mode_VGA_640_480_narrow, SUBSAMPLING, 640, 480, ++ ov5647_setting_30fps_VGA_640_480, ++ ARRAY_SIZE(ov5647_setting_30fps_VGA_640_480)}, ++ }, ++}; ++ ++static struct regulator *io_regulator; ++static struct regulator *core_regulator; ++static struct regulator *analog_regulator; ++static struct regulator *gpo_regulator; ++ ++static int ov5647_probe(struct i2c_client *adapter, ++ const struct i2c_device_id *device_id); ++static int ov5647_remove(struct i2c_client *client); ++ ++static s32 ov5647_read_reg(u16 reg, u8 *val); ++static s32 ov5647_write_reg(u16 reg, u8 val); ++ ++static const struct i2c_device_id ov5647_id[] = { ++ {"ov5647_mipi", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, ov5647_id); ++ ++static struct i2c_driver ov5647_i2c_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ov5647_mipi", ++ }, ++ .probe = ov5647_probe, ++ .remove = ov5647_remove, ++ .id_table = ov5647_id, ++}; ++ ++static void ov5647_standby(s32 enable) ++{ ++ if (!gpio_is_valid(pwn_gpio)) ++ return; ++ ++ if (enable) { ++ gpio_set_value(pwn_gpio, !powon_active); ++ if (gpio_is_valid(led_gpio)) ++ gpio_set_value(led_gpio, !led_active); ++ } ++ else { ++ gpio_set_value(pwn_gpio, powon_active); ++ if (gpio_is_valid(led_gpio)) ++ gpio_set_value(led_gpio, led_active); ++ } ++ ++ pr_debug("ov5647_mipi_camera_powerdown: powerdown=%x, power_gp=0x%x\n", enable, pwn_gpio); ++ msleep(2); ++} ++ ++static void ov5647_reset(void) ++{ ++ if (!gpio_is_valid(rst_gpio)) ++ return; ++ ++ /* camera reset */ ++ gpio_set_value(rst_gpio, !rst_active); ++ ++ /* camera power dowmn */ ++ if (gpio_is_valid(pwn_gpio)) { ++ gpio_set_value(pwn_gpio, !powon_active); ++ msleep(5); ++ ++ gpio_set_value(pwn_gpio, powon_active); ++ msleep(5); ++ } ++ ++ gpio_set_value(rst_gpio, rst_active); ++ msleep(1); ++ ++ gpio_set_value(rst_gpio, !rst_active); ++ msleep(5); ++ ++ if (gpio_is_valid(pwn_gpio)) ++ gpio_set_value(pwn_gpio, !powon_active); ++} ++ ++static int ov5647_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, ++ OV5647_VOLTAGE_DIGITAL_IO, ++ OV5647_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, ++ OV5647_VOLTAGE_DIGITAL_CORE, ++ OV5647_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, ++ OV5647_VOLTAGE_ANALOG, ++ OV5647_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 ov5647_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(ov5647_data.i2c_client, au8Buf, 3) < 0) { ++ pr_err("%s:write reg error:reg=%x,val=%x\n", ++ __func__, reg, val); ++ return -1; ++ } ++ pr_debug("reg=%x,val=%x\n", reg, val); ++ return 0; ++} ++ ++static s32 ov5647_read_reg(u16 reg, u8 *val) ++{ ++ struct sensor_data *sensor = &ov5647_data; ++ struct i2c_client *client = sensor->i2c_client; ++ struct i2c_msg msgs[2]; ++ u8 buf[2]; ++ int ret; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].addr = client->addr; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = 1; ++ msgs[1].buf = buf; ++ ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if (ret < 0) { ++ pr_err("%s(mipi):reg=%x ret=%d\n", __func__, reg, ret); ++ return ret; ++ } ++ *val = buf[0]; ++ pr_debug("%s(mipi):reg=%x,val=%x\n", __func__, reg, buf[0]); ++ return buf[0]; ++} ++ ++static int prev_sysclk, prev_HTS; ++static int AE_low, AE_high, AE_Target = 44; ++ ++void OV5647_stream_on(void) ++{ ++ ov5647_write_reg(0x4202, 0x00); ++ ov5647_write_reg(0x300D, 0x00); ++} ++ ++void OV5647_stream_off(void) ++{ ++ ov5647_write_reg(0x4202, 0x0f); ++ ov5647_write_reg(0x300D, 0x01); ++} ++ ++static const int sclk_rdiv_map[] = {1, 2, 4, 8}; ++ ++int OV5647_get_sysclk(void) ++{ ++ /* calculate sysclk */ ++ int tmp; ++ unsigned Multiplier, PreDiv, SysDiv, Pll_rdiv, Bit_div2x = 1; ++ unsigned div, sclk_rdiv, sysclk; ++ u8 temp; ++ ++ tmp = ov5647_read_reg(0x3034, &temp); ++ if (tmp < 0) ++ return tmp; ++ tmp &= 0x0f; ++ if (tmp == 8 || tmp == 10) ++ Bit_div2x = tmp / 2; ++ ++ tmp = ov5647_read_reg(0x3035, &temp); ++ if (tmp < 0) ++ return tmp; ++ SysDiv = tmp >> 4; ++ if (SysDiv == 0) ++ SysDiv = 16; ++ ++ tmp = ov5647_read_reg(0x3036, &temp); ++ if (tmp < 0) ++ return tmp; ++ Multiplier = tmp; ++ ++ tmp = ov5647_read_reg(0x3037, &temp); ++ if (tmp < 0) ++ return tmp; ++ PreDiv = tmp & 0x0f; ++ Pll_rdiv = ((tmp >> 4) & 0x01) + 1; ++ ++ tmp = ov5647_read_reg(0x3108, &temp); ++ if (tmp < 0) ++ return tmp; ++ sclk_rdiv = sclk_rdiv_map[tmp & 0x03]; ++ ++ sysclk = ov5647_data.mclk / 10000 * Multiplier; ++ div = PreDiv * SysDiv * Pll_rdiv * Bit_div2x * sclk_rdiv; ++ if (!div) { ++ pr_err("%s:Error divide by 0, (%d * %d * %d * %d * %d)\n", ++ __func__, PreDiv, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv); ++ return -EINVAL; ++ } ++ if (!sysclk) { ++ pr_err("%s:Error 0 clk, ov5647_data.mclk=%d, Multiplier=%d\n", ++ __func__, ov5647_data.mclk, Multiplier); ++ return -EINVAL; ++ } ++ sysclk /= div; ++ pr_debug("%s: sysclk(%d) = %d / 10000 * %d / (%d * %d * %d * %d * %d)\n", ++ __func__, sysclk, ov5647_data.mclk, Multiplier, ++ PreDiv, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv); ++ return sysclk; ++} ++ ++void OV5647_set_night_mode(void) ++{ ++ /* read HTS from register settings */ ++ u8 mode; ++ ++ ov5647_read_reg(0x3a00, &mode); ++ mode &= 0xfb; ++ ov5647_write_reg(0x3a00, mode); ++} ++ ++int OV5647_get_HTS(void) ++{ ++ /* read HTS from register settings */ ++ int HTS; ++ u8 temp; ++ ++ HTS = ov5647_read_reg(0x380c, &temp); ++ HTS = (HTS<<8) + ov5647_read_reg(0x380d, &temp); ++ ++ return HTS; ++} ++ ++int OV5647_get_VTS(void) ++{ ++ /* read VTS from register settings */ ++ int VTS; ++ u8 temp; ++ ++ /* total vertical size[15:8] high byte */ ++ VTS = ov5647_read_reg(0x380e, &temp); ++ ++ VTS = (VTS<<8) + ov5647_read_reg(0x380f, &temp); ++ ++ return VTS; ++} ++ ++int OV5647_set_VTS(int VTS) ++{ ++ /* write VTS to registers */ ++ int temp; ++ ++ temp = VTS & 0xff; ++ ov5647_write_reg(0x380f, temp); ++ ++ temp = VTS>>8; ++ ov5647_write_reg(0x380e, temp); ++ ++ return 0; ++} ++ ++int OV5647_get_shutter(void) ++{ ++ /* read shutter, in number of line period */ ++ int shutter; ++ u8 temp; ++ ++ shutter = (ov5647_read_reg(0x03500, &temp) & 0x0f); ++ shutter = (shutter<<8) + ov5647_read_reg(0x3501, &temp); ++ shutter = (shutter<<4) + (ov5647_read_reg(0x3502, &temp)>>4); ++ ++ return shutter; ++} ++ ++int OV5647_set_shutter(int shutter) ++{ ++ /* write shutter, in number of line period */ ++ int temp; ++ ++ shutter = shutter & 0xffff; ++ ++ temp = shutter & 0x0f; ++ temp = temp<<4; ++ ov5647_write_reg(0x3502, temp); ++ ++ temp = shutter & 0xfff; ++ temp = temp>>4; ++ ov5647_write_reg(0x3501, temp); ++ ++ temp = shutter>>12; ++ ov5647_write_reg(0x3500, temp); ++ ++ return 0; ++} ++ ++int OV5647_get_gain16(void) ++{ ++ /* read gain, 16 = 1x */ ++ int gain16; ++ u8 temp; ++ ++ gain16 = ov5647_read_reg(0x350a, &temp) & 0x03; ++ gain16 = (gain16<<8) + ov5647_read_reg(0x350b, &temp); ++ ++ return gain16; ++} ++ ++int OV5647_set_gain16(int gain16) ++{ ++ /* write gain, 16 = 1x */ ++ u8 temp; ++ gain16 = gain16 & 0x3ff; ++ ++ temp = gain16 & 0xff; ++ ov5647_write_reg(0x350b, temp); ++ ++ temp = gain16>>8; ++ ov5647_write_reg(0x350a, temp); ++ ++ return 0; ++} ++ ++int OV5647_get_light_freq(void) ++{ ++ /* get banding filter value */ ++ int temp, temp1, light_freq = 0; ++ u8 tmp; ++ ++ temp = ov5647_read_reg(0x3c01, &tmp); ++ ++ if (temp & 0x80) { ++ /* manual */ ++ temp1 = ov5647_read_reg(0x3c00, &tmp); ++ if (temp1 & 0x04) { ++ /* 50Hz */ ++ light_freq = 50; ++ } else { ++ /* 60Hz */ ++ light_freq = 60; ++ } ++ } else { ++ /* auto */ ++ temp1 = ov5647_read_reg(0x3c0c, &tmp); ++ if (temp1 & 0x01) { ++ /* 50Hz */ ++ light_freq = 50; ++ } else { ++ /* 60Hz */ ++ light_freq = 60; ++ } ++ } ++ return light_freq; ++} ++ ++void OV5647_set_bandingfilter(void) ++{ ++ int prev_VTS; ++ int band_step60, max_band60, band_step50, max_band50; ++ ++ /* read preview PCLK */ ++ prev_sysclk = OV5647_get_sysclk(); ++ /* read preview HTS */ ++ prev_HTS = OV5647_get_HTS(); ++ ++ /* read preview VTS */ ++ prev_VTS = OV5647_get_VTS(); ++ ++ /* calculate banding filter */ ++ /* 60Hz */ ++ band_step60 = prev_sysclk * 100/prev_HTS * 100/120; ++ ov5647_write_reg(0x3a0a, (band_step60 >> 8)); ++ ov5647_write_reg(0x3a0b, (band_step60 & 0xff)); ++ ++ max_band60 = (int)((prev_VTS-4)/band_step60); ++ ov5647_write_reg(0x3a0d, max_band60); ++ ++ /* 50Hz */ ++ band_step50 = prev_sysclk * 100/prev_HTS; ++ ov5647_write_reg(0x3a08, (band_step50 >> 8)); ++ ov5647_write_reg(0x3a09, (band_step50 & 0xff)); ++ ++ max_band50 = (int)((prev_VTS-4)/band_step50); ++ ov5647_write_reg(0x3a0e, max_band50); ++} ++ ++int OV5647_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; ++ ++ ov5647_write_reg(0x3a0f, AE_high); ++ ov5647_write_reg(0x3a10, AE_low); ++ ov5647_write_reg(0x3a1b, AE_high); ++ ov5647_write_reg(0x3a1e, AE_low); ++ ov5647_write_reg(0x3a11, fast_high); ++ ov5647_write_reg(0x3a1f, fast_low); ++ ++ return 0; ++} ++ ++void OV5647_turn_on_AE_AG(int enable) ++{ ++ u8 ae_ag_ctrl; ++ ++ ov5647_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; ++ } ++ ov5647_write_reg(0x3503, ae_ag_ctrl); ++} ++ ++bool ov5647_binning_on(void) ++{ ++ u8 temp; ++ ov5647_read_reg(0x3821, &temp); ++ temp &= 0xfe; ++ if (temp) ++ return true; ++ else ++ return false; ++} ++ ++static void ov5647_set_virtual_channel(int channel) ++{ ++ u8 channel_id; ++ ++ ov5647_read_reg(0x4814, &channel_id); ++ channel_id &= ~(3 << 6); ++ ov5647_write_reg(0x4814, channel_id | (channel << 6)); ++} ++ ++/* download ov5647 settings to sensor through i2c */ ++static int ov5647_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 = ov5647_read_reg(RegAddr, &RegVal); ++ if (retval < 0) ++ goto err; ++ ++ RegVal &= ~(u8)Mask; ++ Val &= Mask; ++ Val |= RegVal; ++ } ++ ++ retval = ov5647_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 ov5647_change_mode_exposure_calc(enum ov5647_frame_rate frame_rate, ++ enum ov5647_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 = ++ ov5647_mode_info_data[frame_rate][mode].init_data_ptr; ++ ArySize = ++ ov5647_mode_info_data[frame_rate][mode].init_data_size; ++ ++ ov5647_data.pix.width = ++ ov5647_mode_info_data[frame_rate][mode].width; ++ ov5647_data.pix.height = ++ ov5647_mode_info_data[frame_rate][mode].height; ++ ov5647_data_add.map_sizeimage = ++ ov5647_data.pix.width * ov5647_data.pix.height * 3 / 2; ++ ++ if (ov5647_data.pix.width == 0 || ov5647_data.pix.height == 0 || ++ pModeSetting == NULL || ArySize == 0) ++ return -EINVAL; ++ ++ /* turn off AE/AG */ ++ OV5647_turn_on_AE_AG(0); ++ ++ /* read preview shutter */ ++ prev_shutter = OV5647_get_shutter(); ++ if ((ov5647_binning_on()) && (mode != ov5647_mode_960P_1280_960) && ++ (mode != ov5647_mode_720P_1280_720) && (mode != ov5647_mode_1080P_1920_1080)) ++ prev_shutter *= 2; ++ ++ /* read preview gain */ ++ prev_gain16 = OV5647_get_gain16(); ++ ++ /* get average */ ++ ov5647_read_reg(0x5693, &average); ++ ++ /* turn off night mode for capture */ ++ OV5647_set_night_mode(); ++ ++ /* turn off overlay */ ++ /* ov5647_write_reg(0x3022, 0x06);//if no af function, just skip it */ ++ ++ OV5647_stream_off(); ++ ++ /* Write capture setting */ ++ retval = ov5647_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ /* read capture VTS */ ++ cap_VTS = OV5647_get_VTS(); ++ cap_HTS = OV5647_get_HTS(); ++ cap_sysclk = OV5647_get_sysclk(); ++ ++ /* calculate capture banding filter */ ++ light_freq = OV5647_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 */ ++ OV5647_set_gain16(cap_gain16); ++ ++ /* write capture shutter */ ++ if (cap_shutter > (cap_VTS - 4)) { ++ cap_VTS = cap_shutter + 4; ++ OV5647_set_VTS(cap_VTS); ++ } ++ OV5647_set_shutter(cap_shutter); ++ ++ OV5647_stream_on(); ++ ++err: ++ return retval; ++} ++ ++/* if sensor changes inside scaling or subsampling ++ * change mode directly ++ * */ ++static int ov5647_change_mode_direct(enum ov5647_frame_rate frame_rate, ++ enum ov5647_mode mode) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 ArySize = 0; ++ int retval = 0; ++ ++ /* check if the input mode and frame rate is valid */ ++ pModeSetting = ++ ov5647_mode_info_data[frame_rate][mode].init_data_ptr; ++ ArySize = ++ ov5647_mode_info_data[frame_rate][mode].init_data_size; ++ ++ ov5647_data.pix.width = ++ ov5647_mode_info_data[frame_rate][mode].width; ++ ov5647_data.pix.height = ++ ov5647_mode_info_data[frame_rate][mode].height; ++ ov5647_data_add.map_sizeimage = ++ ov5647_data.pix.width * ov5647_data.pix.height * 3 / 2; ++ ++ if (ov5647_data.pix.width == 0 || ov5647_data.pix.height == 0 || ++ pModeSetting == NULL || ArySize == 0) ++ return -EINVAL; ++ ++ /* turn off AE/AG */ ++ OV5647_turn_on_AE_AG(0); ++ ++ OV5647_stream_off(); ++ ++ /* Write capture setting */ ++ retval = ov5647_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ OV5647_stream_on(); ++ ++ OV5647_turn_on_AE_AG(1); ++ ++err: ++ return retval; ++} ++ ++static int ov5647_init_mode(enum ov5647_frame_rate frame_rate, ++ enum ov5647_mode mode, enum ov5647_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 ov5647_downsize_mode dn_mode, orig_dn_mode; ++ ++ if ((mode > ov5647_mode_MAX || mode < ov5647_mode_MIN) ++ && (mode != ov5647_mode_INIT)) { ++ pr_err("Wrong ov5647 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; ++ } ++ ++ ov5647_write_reg(0x4800, 0x25); ++ OV5647_stream_off(); ++ ++ 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, 2); ++ ++ /*Only reset MIPI CSI2 HW at sensor initialize*/ ++ if (mode == ov5647_mode_INIT) ++ mipi_csi2_reset(mipi_csi2_info); ++ ++ /* reg 0x3034[3:0] == 0x8 is 8bit mode */ ++ mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_RAW8); ++ ++ if (orig_mode != ov5647_mode_INIT) { ++ dn_mode = ov5647_mode_info_data[frame_rate][mode].dn_mode; ++ orig_dn_mode = ov5647_mode_info_data[frame_rate][orig_mode].dn_mode; ++ } ++ else { ++ orig_dn_mode = dn_mode = 0; ++ } ++ ++ if (mode == ov5647_mode_INIT) { ++ int index = (int)ov5647_data.streamcap.capturemode; ++ ++ pModeSetting = ov5647_mode_info_data[frame_rate][index].init_data_ptr; ++ ArySize = ov5647_mode_info_data[frame_rate][index].init_data_size; ++ retval = ov5647_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ } 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 = ov5647_change_mode_exposure_calc(frame_rate, mode); ++ } else { ++ /* change inside subsampling or scaling ++ * download firmware directly */ ++ retval = ov5647_change_mode_direct(frame_rate, mode); ++ } ++ ++ if (retval < 0) ++ goto err; ++ ++ OV5647_set_AE_target(AE_Target); ++ OV5647_get_light_freq(); ++ OV5647_set_bandingfilter(); ++ ov5647_set_virtual_channel(ov5647_data.virtual_channel); ++ ++ /* add delay to wait for sensor stable */ ++ if (frame_rate == ov5647_15_fps) { ++ /* dump the first nine frames: 1/15*9 */ ++ msec_wait4stable = 600; ++ } else if (frame_rate == ov5647_30_fps) { ++ /* dump the first nine frames: 1/30*9 */ ++ msec_wait4stable = 300; ++ } ++ msleep(msec_wait4stable); ++ ++ if (mipi_csi2_info) { ++ unsigned int i = 0; ++ u8 resetval; ++ ++ /* wait for mipi sensor ready */ ++ while (1) { ++ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); ++ if (mipi_reg != 0x200) ++ break; ++ if (i++ >= 20) { ++ pr_err("mipi csi2 can not receive sensor clk! %x\n", mipi_reg); ++ return -1; ++ } ++ msleep(10); ++ } ++ ++ i = 0; ++ /* wait for mipi stable */ ++ while (1) { ++ mipi_reg = mipi_csi2_get_error1(mipi_csi2_info); ++ if (!mipi_reg) ++ break; ++ if (i++ >= 20) { ++ pr_err("mipi csi2 can not receive data correctly!\n"); ++ return -1; ++ } ++ msleep(10); ++ } ++ ++ pr_debug("receiving data"); ++ mipi_reg = mipi_csi2_get_error2(mipi_csi2_info); ++ pr_debug("mipi_csi2 error2 = 0x%X\n", mipi_reg); ++ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); ++ pr_debug("mipi_csi2_dphy_status = 0x%X\n", mipi_reg); ++ ++ ov5647_read_reg(0x0100, &resetval); ++ if (!resetval&0x01) { ++ pr_info("DEVICE WAS IN SOFTWARE STANDBY"); ++ ov5647_write_reg(0x0100, 0x01); ++ } ++ ++ ov5647_write_reg(0x4800, 0x04); ++ msleep(266); ++ OV5647_stream_on(); ++ msleep(30); ++ OV5647_turn_on_AE_AG(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 = ov5647_data.mclk; ++ pr_debug(" clock_curr=mclk=%d\n", ov5647_data.mclk); ++ p->if_type = V4L2_IF_TYPE_BT656; ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT; ++ p->u.bt656.clock_min = OV5647_XCLK_MIN; ++ p->u.bt656.clock_max = OV5647_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 */ ++ ov5647_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); ++ ++ ov5647_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 ov5647_frame_rate frame_rate; ++ enum ov5647_mode orig_mode; ++ int ret = 0; ++ ++ /* Make sure power on */ ++ ov5647_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 = ov5647_15_fps; ++ else if (tgt_fps == 30) ++ frame_rate = ov5647_30_fps; ++ else { ++ pr_err(" The camera frame rate is not supported!\n"); ++ return -EINVAL; ++ } ++ ++ orig_mode = sensor->streamcap.capturemode; ++ ret = ov5647_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; ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ f->fmt.pix = sensor->pix; ++ pr_debug("%s: %dx%d\n", __func__, sensor->pix.width, sensor->pix.height); ++ break; ++ ++ case V4L2_BUF_TYPE_SENSOR: ++ pr_debug("%s: left=%d, top=%d, %dx%d\n", __func__, ++ sensor->spix.left, sensor->spix.top, ++ sensor->spix.swidth, sensor->spix.sheight); ++ f->fmt.spix = sensor->spix; ++ break; ++ ++ case V4L2_BUF_TYPE_PRIVATE: ++ break; ++ ++ default: ++ f->fmt.pix = sensor->pix; ++ break; ++ } ++ ++ 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 = ov5647_data.brightness; ++ break; ++ case V4L2_CID_HUE: ++ vc->value = ov5647_data.hue; ++ break; ++ case V4L2_CID_CONTRAST: ++ vc->value = ov5647_data.contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ vc->value = ov5647_data.saturation; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ vc->value = ov5647_data.red; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ vc->value = ov5647_data.blue; ++ break; ++ case V4L2_CID_EXPOSURE: ++ vc->value = ov5647_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 ov5647: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 > ov5647_mode_MAX) ++ return -EINVAL; ++ ++ fsize->pixel_format = ov5647_data.pix.pixelformat; ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ fsize->discrete.width = ++ max(ov5647_mode_info_data[0][fsize->index].width, ++ ov5647_mode_info_data[1][fsize->index].width); ++ fsize->discrete.height = ++ max(ov5647_mode_info_data[0][fsize->index].height, ++ ov5647_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, ++ "ov5647_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 > ov5647_mode_MAX) ++ return -EINVAL; ++ ++ fmt->pixelformat = ov5647_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 ov5647_frame_rate frame_rate; ++ void *mipi_csi2_info; ++ ++ ov5647_data.on = true; ++ ++ /* mclk */ ++ tgt_xclk = ov5647_data.mclk; ++ tgt_xclk = min(tgt_xclk, (u32)OV5647_XCLK_MAX); ++ tgt_xclk = max(tgt_xclk, (u32)OV5647_XCLK_MIN); ++ ov5647_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 = ov5647_15_fps; ++ else if (tgt_fps == 30) ++ frame_rate = ov5647_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 = ov5647_init_mode(frame_rate, ov5647_mode_INIT, ov5647_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 ov5647_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 ov5647_slave = { ++ .ioctls = ov5647_ioctl_desc, ++ .num_ioctls = ARRAY_SIZE(ov5647_ioctl_desc), ++}; ++ ++static struct v4l2_int_device ov5647_int_device = { ++ .module = THIS_MODULE, ++ .name = "ov5647_mipi", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &ov5647_slave, ++ }, ++}; ++ ++static ssize_t show_reg(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 val; ++ s32 rval = ov5647_read_reg(ov5647_data.last_reg, &val); ++ ++ return sprintf(buf, "ov5647[0x%04x]=0x%02x\n",ov5647_data.last_reg, rval); ++} ++static ssize_t set_reg(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int regnum, value; ++ int num_parsed = sscanf(buf, "%04x=%02x", ®num, &value); ++ if (1 <= num_parsed) { ++ if (0xffff < (unsigned)regnum){ ++ pr_err("%s:invalid regnum %x\n", __func__, regnum); ++ return 0; ++ } ++ ov5647_data.last_reg = regnum; ++ } ++ if (2 == num_parsed) { ++ if (0xff < (unsigned)value) { ++ pr_err("%s:invalid value %x\n", __func__, value); ++ return 0; ++ } ++ ov5647_write_reg(ov5647_data.last_reg, value); ++ } ++ return count; ++} ++ ++/* XXX: workaround for v4l2 client except for gstreamer-imx */ ++static ssize_t show_mode(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "ov5647 mode = 0x%02x\n", (int)ov5647_data.streamcap.capturemode); ++} ++ ++static ssize_t set_mode(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long mode; ++ ++ mode = simple_strtoul(buf, NULL, 10); ++ if ((enum ov5647_mode)mode >= ov5647_mode_MIN && ++ (enum ov5647_mode)mode <= ov5647_mode_MAX) { ++ ++ ov5647_data.streamcap.capturemode = mode; ++ ov5647_data.pix.width = ++ max(ov5647_mode_info_data[0][mode].width, ++ ov5647_mode_info_data[1][mode].width); ++ ov5647_data.pix.height = ++ max(ov5647_mode_info_data[0][mode].height, ++ ov5647_mode_info_data[1][mode].height); ++ ov5647_data_add.map_sizeimage = ++ ov5647_data.pix.width * ov5647_data.pix.height * 3 / 2; ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(ov5647_reg, S_IRUGO|S_IWUGO, show_reg, set_reg); ++static DEVICE_ATTR(ov5647_mode, S_IRUGO|S_IWUGO, show_mode, set_mode); ++ ++/*! ++ * ov5647 I2C probe function ++ * ++ * @param adapter struct i2c_adapter * ++ * @return Error code indicating success or failure ++ */ ++static int ov5647_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ int retval, init, gpio; ++ u8 chip_id_high, chip_id_low; ++ struct sensor_data *sensor = &ov5647_data; ++ enum of_gpio_flags flags; ++ bool extbuf; ++ ++ /* request power down pin */ ++ pwn_gpio = of_get_named_gpio_flags(dev->of_node, "pwn-gpios", 0, &flags); ++ if (gpio_is_valid(pwn_gpio)) { ++ /* powon_active - camera power on */ ++ /* !powon_active - camera power down */ ++ powon_active = !(flags & OF_GPIO_ACTIVE_LOW); ++ init = (flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ ++ retval = devm_gpio_request_one(dev, pwn_gpio, init, "ov5647_mipi_pwdn"); ++ if (retval < 0) { ++ dev_warn(dev, "request of pwn_gpio failed"); ++ pwn_gpio = -EINVAL; ++ } ++ } ++ ++ /* request reset pin */ ++ rst_gpio = of_get_named_gpio_flags(dev->of_node, "rst-gpios", 0, &flags); ++ if (gpio_is_valid(rst_gpio)) { ++ /* rst_active - camera reset */ ++ /* !rst_active - clear camera reset */ ++ rst_active = !(flags & OF_GPIO_ACTIVE_LOW); ++ init = (flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ ++ retval = devm_gpio_request_one(dev, rst_gpio, init, "ov5647_mipi_reset"); ++ if (retval < 0) { ++ dev_warn(dev, "request of ov5647_mipi_reset failed"); ++ rst_gpio = -EINVAL; ++ } ++ } ++ ++ /* request LED(for sanity) pin */ ++ gpio = of_get_named_gpio_flags(dev->of_node, "led-gpios", 0, &flags); ++ if (gpio_is_valid(gpio)) { ++ /* led_active - LED turn on */ ++ /* !led_active - LED trun off */ ++ led_active = !(flags & OF_GPIO_ACTIVE_LOW); ++ init = (flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ ++ retval = devm_gpio_request_one(dev, gpio, init, "ov5647_mipi_led"); ++ if (retval < 0) { ++ dev_warn(dev, "request of led_gpio failed"); ++ gpio = -EINVAL; ++ } ++ } ++ ++ /* allocate extended video frame buffer */ ++ extbuf = of_find_property(dev->of_node, "extended-buffer", NULL); ++ ++ /* Set initial values for the sensor struct. */ ++ memset(&ov5647_data, 0, sizeof(ov5647_data)); ++ memset(&ov5647_data_add, 0, sizeof(ov5647_data_add)); ++ ++ sensor->mipi_camera = 1; ++ ov5647_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); ++ if (IS_ERR(ov5647_data.sensor_clk)) { ++ /* assuming clock enabled by default */ ++ ov5647_data.sensor_clk = NULL; ++ dev_err(dev, "clock-frequency missing or invalid\n"); ++ return PTR_ERR(ov5647_data.sensor_clk); ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk", ++ &(ov5647_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 *) &(ov5647_data.mclk_source)); ++ if (retval) { ++ dev_err(dev, "mclk_source missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "ipu_id", ++ &sensor->ipu_id); ++ if (retval) { ++ dev_err(dev, "ipu_id missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "csi_id", ++ &(ov5647_data.csi)); ++ if (retval) { ++ dev_err(dev, "csi id missing or invalid\n"); ++ return retval; ++ } ++ ++ clk_prepare_enable(ov5647_data.sensor_clk); ++ ++ ov5647_data.io_init = ov5647_reset; ++ ov5647_data.i2c_client = client; ++ /* real OV5647 pixelformat is V4L2_PIX_FMT_SBGGR10. */ ++ /* i.MX6 CSI CPD convert 10 bits color data to 8 bits. */ ++ /* (see drivers/mxc/ipu3/ipu_capture.c - _ipu_csi_init) */ ++ ov5647_data.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; ++ ov5647_data.pix.width = 1024; ++ ov5647_data.pix.height = 768; ++ ov5647_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | ++ V4L2_CAP_TIMEPERFRAME; ++ ov5647_data.streamcap.capturemode = ov5647_mode_XGA_1024_768; ++ ov5647_data.streamcap.timeperframe.denominator = DEFAULT_FPS; ++ ov5647_data.streamcap.timeperframe.numerator = 1; ++ ++ /* lager memory allocate for Vivante direct texture mapping API */ ++ /* (VIDIOC_REQBUFS ioctl) */ ++ ov5647_data_add.map_sizeimage = ++ ov5647_data.pix.width * ov5647_data.pix.height * 3 / 2; /* I420 */ ++ ++ if (extbuf) { ++ ov5647_data.adata = &ov5647_data_add; ++ } ++ ++ ov5647_power_on(dev); ++ ++ ov5647_reset(); ++ ++ ov5647_standby(0); ++ ++ retval = ov5647_read_reg(OV5647_CHIP_ID_HIGH_BYTE, &chip_id_high); ++ if (retval < 0 || chip_id_high != 0x56) { ++ pr_warning("camera ov5647_mipi is not found\n"); ++ clk_disable_unprepare(ov5647_data.sensor_clk); ++ return -ENODEV; ++ } ++ retval = ov5647_read_reg(OV5647_CHIP_ID_LOW_BYTE, &chip_id_low); ++ if (retval < 0 || chip_id_low != 0x47) { ++ pr_warning("camera ov5647_mipi is not found\n"); ++ clk_disable_unprepare(ov5647_data.sensor_clk); ++ return -ENODEV; ++ } ++ ++ sensor->virtual_channel = sensor->csi | (sensor->ipu_id << 1); ++ ov5647_standby(1); ++ ++ led_gpio = gpio; ++ ov5647_int_device.priv = &ov5647_data; ++ retval = v4l2_int_device_register(&ov5647_int_device); ++ ++// clk_disable_unprepare(ov5647_data.sensor_clk); ++ ++ if (device_create_file(dev, &dev_attr_ov5647_reg)) ++ dev_err(dev, "%s: error creating ov5647_reg entry\n", __func__); ++ if (device_create_file(dev, &dev_attr_ov5647_mode)) ++ dev_err(dev, "%s: error creating ov5647_mode entry\n", __func__); ++ ++ pr_info("camera ov5647_mipi is found\n"); ++ return retval; ++} ++ ++/*! ++ * ov5647 I2C detach function ++ * ++ * @param client struct i2c_client * ++ * @return Error code indicating success or failure ++ */ ++static int ov5647_remove(struct i2c_client *client) ++{ ++ v4l2_int_device_unregister(&ov5647_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; ++} ++ ++/*! ++ * ov5647 init function ++ * Called by insmod ov5647_camera.ko. ++ * ++ * @return Error code indicating success or failure ++ */ ++static __init int ov5647_init(void) ++{ ++ u8 err; ++ ++ err = i2c_add_driver(&ov5647_i2c_driver); ++ if (err != 0) ++ pr_err("%s:driver registration failed, error=%d\n", ++ __func__, err); ++ ++ return err; ++} ++ ++/*! ++ * OV5647 cleanup function ++ * Called on rmmod ov5647_camera.ko ++ * ++ * @return Error code indicating success or failure ++ */ ++static void __exit ov5647_clean(void) ++{ ++ i2c_del_driver(&ov5647_i2c_driver); ++} ++ ++module_init(ov5647_init); ++module_exit(ov5647_clean); ++ ++MODULE_AUTHOR("Viion Systems Inc."); ++MODULE_DESCRIPTION("OV5647 MIPI Camera Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0"); ++MODULE_ALIAS("CSI"); +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/capture/tc358743_h2c.c linux-3.14.72/drivers/media/platform/mxc/capture/tc358743_h2c.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/tc358743_h2c.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/tc358743_h2c.c 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,3674 @@ ++/* ++ * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2014 Boundary Devices ++ */ ++ ++/* ++ * Modifyed by: Edison Fernández ++ * Added support to use it with Nitrogen6x ++ * ++ * 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 "v4l2-int-device.h" ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include "mxc_v4l2_capture.h" ++ ++#define CODEC_CLOCK 16500000 ++/* SSI clock sources */ ++#define IMX_SSP_SYS_CLK 0 ++ ++#define MIN_FPS 30 ++#define MAX_FPS 60 ++#define DEFAULT_FPS 60 ++ ++#define TC358743_XCLK_MIN 27000000 ++#define TC358743_XCLK_MAX 42000000 ++ ++#define TC358743_CHIP_ID_HIGH_BYTE 0x0 ++#define TC358743_CHIP_ID_LOW_BYTE 0x0 ++#define TC3587430_HDMI_DETECT 0x0f //0x10 ++ ++#define TC_VOLTAGE_DIGITAL_IO 1800000 ++#define TC_VOLTAGE_DIGITAL_CORE 1500000 ++#define TC_VOLTAGE_DIGITAL_GPO 1500000 ++#define TC_VOLTAGE_ANALOG 2800000 ++ ++#define MAX_COLORBAR tc358743_mode_INIT6 ++#define IS_COLORBAR(a) (a <= MAX_COLORBAR) ++ ++enum tc358743_mode { ++ tc358743_mode_INIT, ++ tc358743_mode_INIT1, ++ tc358743_mode_INIT2, ++ tc358743_mode_INIT3, ++ tc358743_mode_INIT4, ++ tc358743_mode_INIT5, ++ tc358743_mode_INIT6, ++ tc358743_mode_480P_720_480, ++ tc358743_mode_720P_60_1280_720, ++ tc358743_mode_480P_640_480, ++ tc358743_mode_1080P_1920_1080, ++ tc358743_mode_720P_1280_720, ++ tc358743_mode_1024x768, ++ tc358743_mode_MAX, ++}; ++ ++enum tc358743_frame_rate { ++ tc358743_60_fps, ++ tc358743_30_fps, ++ tc358743_max_fps ++}; ++ ++struct reg_value { ++ u16 u16RegAddr; ++ u32 u32Val; ++ u32 u32Mask; ++ u8 u8Length; ++ u32 u32Delay_ms; ++}; ++ ++struct tc358743_mode_info { ++ const char *name; ++ enum tc358743_mode mode; ++ u32 width; ++ u32 height; ++ u32 vformat; ++ u32 fps; ++ u32 lanes; ++ u32 freq; ++ const struct reg_value *init_data_ptr; ++ u32 init_data_size; ++ __u32 flags; ++}; ++ ++/*! ++ * Maintains the information on the current state of the sensor. ++ */ ++struct tc_data { ++ struct sensor_data sensor; ++ struct delayed_work det_work; ++ struct mutex access_lock; ++ int det_work_enable; ++ int det_work_timeout; ++ int det_changed; ++#define REGULATOR_IO 0 ++#define REGULATOR_CORE 1 ++#define REGULATOR_GPO 2 ++#define REGULATOR_ANALOG 3 ++#define REGULATOR_CNT 4 ++ struct regulator *regulator[REGULATOR_CNT]; ++#ifdef CONFIG_TC358743_AUDIO ++ struct platform_device *snd_device; ++#endif ++ u32 lock; ++ u32 bounce; ++ enum tc358743_mode mode; ++ u32 fps; ++ u32 audio; ++ int pwn_gpio; ++ int rst_gpio; ++ u16 hpd_active; ++ int edid_initialized; ++}; ++ ++static struct tc_data *g_td; ++ ++ ++#define DET_WORK_TIMEOUT_DEFAULT 100 ++#define DET_WORK_TIMEOUT_DEFERRED 2000 ++#define MAX_BOUNCE 5 ++ ++static void tc_standby(struct tc_data *td, s32 standby) ++{ ++ if (gpio_is_valid(td->pwn_gpio)) ++ gpio_set_value(td->pwn_gpio, standby ? 1 : 0); ++ pr_debug("tc_standby: powerdown=%x, power_gp=0x%x\n", standby, td->pwn_gpio); ++ msleep(2); ++} ++ ++static void tc_reset(struct tc_data *td) ++{ ++ /* camera reset */ ++ gpio_set_value(td->rst_gpio, 1); ++ ++ /* camera power dowmn */ ++ if (gpio_is_valid(td->pwn_gpio)) { ++ gpio_set_value(td->pwn_gpio, 1); ++ msleep(5); ++ ++ gpio_set_value(td->pwn_gpio, 0); ++ } ++ msleep(5); ++ ++ gpio_set_value(td->rst_gpio, 0); ++ msleep(1); ++ ++ gpio_set_value(td->rst_gpio, 1); ++ msleep(20); ++ ++ if (gpio_is_valid(td->pwn_gpio)) ++ gpio_set_value(td->pwn_gpio, 1); ++} ++ ++static void tc_io_init(void) ++{ ++ return tc_reset(g_td); ++} ++ ++const char * const sregulator[REGULATOR_CNT] = { ++ [REGULATOR_IO] = "DOVDD", ++ [REGULATOR_CORE] = "DVDD", ++ [REGULATOR_GPO] = "DGPO", ++ [REGULATOR_ANALOG] = "AVDD", ++}; ++ ++static const int voltages[REGULATOR_CNT] = { ++ [REGULATOR_IO] = TC_VOLTAGE_DIGITAL_IO, ++ [REGULATOR_CORE] = TC_VOLTAGE_DIGITAL_CORE, ++ [REGULATOR_GPO] = TC_VOLTAGE_DIGITAL_GPO, ++ [REGULATOR_ANALOG] = TC_VOLTAGE_ANALOG, ++}; ++ ++static int tc_regulator_init(struct tc_data *td, struct device *dev) ++{ ++ int i; ++ int ret = 0; ++ ++ for (i = 0; i < REGULATOR_CNT; i++) { ++ td->regulator[i] = devm_regulator_get(dev, sregulator[i]); ++ if (!IS_ERR(td->regulator[i])) { ++ regulator_set_voltage(td->regulator[i], ++ voltages[i], voltages[i]); ++ } else { ++ pr_err("%s:%s devm_regulator_get failed\n", __func__, sregulator[i]); ++ td->regulator[i] = NULL; ++ } ++ } ++ return ret; ++} ++ ++static void det_work_enable(struct tc_data *td, int enable) ++{ ++ td->det_work_enable = enable; ++ td->det_work_timeout = DET_WORK_TIMEOUT_DEFERRED; ++ if (enable) ++ schedule_delayed_work(&td->det_work, msecs_to_jiffies(10)); ++ pr_debug("%s: %d %d\n", __func__, td->det_work_enable, td->det_work_timeout); ++} ++ ++static const u8 cHDMIEDID[256] = { ++ /* FIXME! This is the edid that my ASUS HDMI monitor returns */ ++ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, //0 - header[8] - fixed pattern ++ 0x04, 0x69, //8 - manufacturer_name[2] ++ 0xf3, 0x24, //10 - product_code[2] ++ 0xd6, 0x12, 0x00, 0x00, //12 - serial_number[4] ++ 0x16, //16 - week ++ 0x16, //17 - year 22+1990=2012 ++ 0x01, //18 - version ++ 0x03, //19 - revision ++ 0x80, //20 - video_input_definition(digital input) ++ 0x34, //21 - max_size_horizontal 52cm ++ 0x1d, //22 - max_size_vertical 29cm ++ 0x78, //23 - gamma ++ 0x3a, //24 - feature_support (RGB 4:4:4 + YCrCb 4:4:4 + YCrCb 4:2:2) ++ 0xc7, 0x20, 0xa4, 0x55, 0x49, 0x99, 0x27, 0x13, 0x50, 0x54, //25 - color_characteristics[10] ++ 0xbf, 0xef, 0x00, //35 - established_timings[3] ++ 0x71, 0x4f, 0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0xb3, 0x00, 0xd1, 0xc0, 0x01, 0x01, 0x01, 0x01, //38 - standard_timings[8] ++/* 1080P */ ++ 0x02, 0x3a, //54(0) - descriptor[0], 0x3a02 = 148.50 MHz ++ 0x80, //56(2) h - active 0x780 (1920) ++ 0x18, //57(3) h - blank 0x118 (280) ++ 0x71, //58(4) ++ 0x38, //59(5) v - active 0x438 (1080) ++ 0x2d, //60(6) v - blank 0x02d(45) ++ 0x40, //61(7) ++ 0x58, //62(8) - h sync offset(0x58) ++ 0x2c, //63(9) - h sync width(0x2c) ++ 0x45, //64(10) - v sync offset(0x4), v sync width(0x5) ++ 0x00, //65(11) ++ 0x09, //66(12) - h display size (0x209) 521 mm ++ 0x25, //67(13) - v display size (0x125) 293 mm ++ 0x21, //68(14) ++ 0x00, //69(15) - h border pixels ++ 0x00, //70(16) - v border pixels ++ 0x1e, //71(17) - no stereo, digital separate, hsync+, vsync+ ++ 0x00, 0x00, 0x00, 0xff, 0x00, //72 - descriptor[1] ++ 0x43, 0x36, 0x4c, 0x4d, 0x54, 0x46, 0x30, 0x30, 0x34, 0x38, 0x32, 0x32, 0x0a, //"C6LMTF004822\n" ++ 0x00, 0x00, 0x00, 0xfd, 0x00, //90 - descriptor[2] ++ 0x37, 0x4b, 0x1e, 0x55, 0x10, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x00, 0x00, 0x00, 0xfc, 0x00, //108 - descriptor[3] ++ 0x41, 0x53, 0x55, 0x53, 0x20, 0x56, 0x48, 0x32, 0x34, 0x32, 0x48, 0x0a, 0x20, //"ASUS VH242H\n " ++ 0x01, //126 - extension_flag ++ 0x68, //127 - checksum ++ ++ 0x02, //0 - cea-861 extension ++ 0x03, //1 - rev 3 ++ 0x22, //2 - detailed timings at offset 34 ++ 0x71, //3 - # of detailed timing descriptor ++ 0x4f, 0x01, 0x02, 0x03, 0x11, 0x12, //4 ++ 0x13, 0x04, 0x14, 0x05, 0x0e, 0x0f, //10 ++ 0x1d, 0x1e, 0x1f, 0x10, 0x23, 0x09, //16 ++ 0x07, 0x01, 0x83, 0x01, 0x00, 0x00, //22 ++ 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, //28 ++/* 720x480@59.94 27000000/858/525 = 59.94 Hz */ ++ 0x8c, 0x0a, //34 - descriptor[0] - 0x0a8c - 27 Mhz ++ 0xd0, //h - active 0x2d0 (720) ++ 0x8a, //h - blank 0x8a(138) ++ 0x20, ++ 0xe0, //v - active 0x1e0 (480) ++ 0x2d, //v - blank 0x2d (45) ++ 0x10, ++ 0x10, 0x3e, 0x96, 0x00, 0x09, 0x25, 0x21, 0x00, 0x00, 0x18, ++/* 1280x720@60 74250000/1650/750 = 60 Hz*/ ++ 0x01, 0x1d, //52 - 0x1d01 74.25MHz ++ 0x00, //h - active (0x500)1280 ++ 0x72, //h - blank (0x172)370 ++ 0x51, ++ 0xd0, //v active 0x2d0(720) ++ 0x1e, //v blank 0x1e(30) ++ 0x20, ++ 0x6e, 0x28, 0x55, 0x00, 0x09, 0x25, 0x21, 0x00, 0x00, 0x1e, ++/* 1280x720@50 74250000/1980/750 = 50 Hz */ ++ 0x01, 0x1d, //70 - 0x1d01 74.25MHz ++ 0x00, //h - active (0x500)1280 ++ 0xbc, //h - blank (0x2bc)700 ++ 0x52, ++ 0xd0, //v active 0x2d0 (720) ++ 0x1e, //v blank 0x1e(30) ++ 0x20, ++ 0xb8, 0x28, 0x55, 0x40, 0x09, 0x25, 0x21, 0x00, 0x00, 0x1e, ++/* 720x576@50 27000000/864/625 = 50 Hz */ ++ 0x8c, 0x0a, //88 0x0a8c - 27 Mhz ++ 0xd0, //h - active 0x2d0(720) ++ 0x90, //h - blank 0x90(144) ++ 0x20, ++ 0x40, //v active 0x240(576) ++ 0x31, //v blanking 0x31(49) ++ 0x20, ++ 0x0c, 0x40, 0x55, 0x00, 0x09, 0x25, 0x21, 0x00, 0x00, 0x18, ++/* done */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, //106 ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, //124 ++ 0x00, //126 - extension_flag ++ 0x73, //127 - checksum ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_2lane_30fps_720P_1280_720_125MHz[] = { ++ {0x0006, 0x00000040, 0x00000000, 2, 0}, ++ {0x0014, 0x00000000, 0x00000000, 2, 0}, ++ {0x0016, 0x000005ff, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x0000402d, 0x00000000, 2, 0}, ++ {0x0022, 0x00000213, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00000e00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000001, 0x00000000, 4, 0}, ++ {0x0218, 0x00000801, 0x00000000, 4, 0}, ++ {0x021c, 0x00000001, 0x00000000, 4, 0}, ++ {0x0220, 0x00000001, 0x00000000, 4, 0}, ++ {0x0224, 0x00004800, 0x00000000, 4, 0}, ++ {0x0228, 0x00000005, 0x00000000, 4, 0}, ++ {0x022c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, //non-continuous clock ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa300be82, 0x00000000, 4, 0}, ++// HDMI Interrupt Mask ++ {0x8502, 0x00000001, 0x00000000, 1, 0}, ++ {0x8512, 0x000000fe, 0x00000000, 1, 0}, ++ {0x8514, 0x00000000, 0x00000000, 1, 0}, ++ {0x8515, 0x00000000, 0x00000000, 1, 0}, ++ {0x8516, 0x00000000, 0x00000000, 1, 0}, ++// HDMI Audio ++ {0x8531, 0x00000001, 0x00000000, 1, 0}, ++ {0x8630, 0x000000b0, 0x00000000, 1, 0}, ++ {0x8631, 0x0000001e, 0x00000000, 1, 0}, ++ {0x8632, 0x00000004, 0x00000000, 1, 0}, ++ {0x8670, 0x00000001, 0x00000000, 1, 0}, ++// HDMI PHY ++ {0x8532, 0x00000080, 0x00000000, 1, 0}, ++ {0x8536, 0x00000040, 0x00000000, 1, 0}, ++ {0x853f, 0x0000000a, 0x00000000, 1, 0}, ++// HDMI System ++ {0x8545, 0x00000031, 0x00000000, 1, 0}, ++ {0x8546, 0x0000002d, 0x00000000, 1, 0}, ++// HDCP Setting ++ {0x85d1, 0x00000001, 0x00000000, 1, 0}, ++ {0x8560, 0x00000024, 0x00000000, 1, 0}, ++ {0x8563, 0x00000011, 0x00000000, 1, 0}, ++ {0x8564, 0x0000000f, 0x00000000, 1, 0}, ++// Video settings ++ {0x8573, 0x00000081, 0x00000000, 1, 0}, ++ {0x8571, 0x00000002, 0x00000000, 1, 0}, ++// HDMI Audio In Setting ++ {0x8600, 0x00000000, 0x00000000, 1, 0}, ++ {0x8602, 0x000000f3, 0x00000000, 1, 0}, ++ {0x8603, 0x00000002, 0x00000000, 1, 0}, ++ {0x8604, 0x0000000c, 0x00000000, 1, 0}, ++ {0x8606, 0x00000005, 0x00000000, 1, 0}, ++ {0x8607, 0x00000000, 0x00000000, 1, 0}, ++ {0x8620, 0x00000022, 0x00000000, 1, 0}, ++ {0x8640, 0x00000001, 0x00000000, 1, 0}, ++ {0x8641, 0x00000065, 0x00000000, 1, 0}, ++ {0x8642, 0x00000007, 0x00000000, 1, 0}, ++// {0x8651, 0x00000003, 0x00000000, 1, 0}, // Inverted LRCK polarity - (Sony) format ++ {0x8652, 0x00000002, 0x00000000, 1, 0}, // Left-justified I2S (Phillips) format ++// {0x8652, 0x00000000, 0x00000000, 1, 0}, // Right-justified (Sony) format ++ {0x8665, 0x00000010, 0x00000000, 1, 0}, ++// InfoFrame Extraction ++ {0x8709, 0x000000ff, 0x00000000, 1, 0}, ++ {0x870b, 0x0000002c, 0x00000000, 1, 0}, ++ {0x870c, 0x00000053, 0x00000000, 1, 0}, ++ {0x870d, 0x00000001, 0x00000000, 1, 0}, ++ {0x870e, 0x00000030, 0x00000000, 1, 0}, ++ {0x9007, 0x00000010, 0x00000000, 1, 0}, ++ {0x854a, 0x00000001, 0x00000000, 1, 0}, ++// Output Control ++ {0x0004, 0x00000cf7, 0x00000000, 2, 0}, ++ }; ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_1024x768_60fps_125MHz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0014, 0x0000ffff, 0x00000000, 2, 0}, ++ {0x0016, 0x000005ff, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x0000405c, 0x00000000, 2, 0}, /* Input divide 5(4+1), Feedback divide 92(0x5c+1)*/ ++ {0x0022, 0x00000613, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00000d00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000001, 0x00000000, 4, 0}, ++ {0x0218, 0x00000701, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000001, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000005, 0x00000000, 4, 0}, ++ {0x022c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa300be86, 0x00000000, 4, 0}, ++// HDMI Interrupt Mask ++ {0x8502, 0x00000001, 0x00000000, 1, 0}, ++ {0x8512, 0x000000fe, 0x00000000, 1, 0}, ++ {0x8514, 0x00000000, 0x00000000, 1, 0}, ++ {0x8515, 0x00000000, 0x00000000, 1, 0}, ++ {0x8516, 0x00000000, 0x00000000, 1, 0}, ++// HDMI Audio ++ {0x8531, 0x00000001, 0x00000000, 1, 0}, ++ {0x8630, 0x00041eb0, 0x00000000, 1, 0}, ++ {0x8670, 0x00000001, 0x00000000, 1, 0}, ++// HDMI PHY ++ {0x8532, 0x00000080, 0x00000000, 1, 0}, ++ {0x8536, 0x00000040, 0x00000000, 1, 0}, ++ {0x853f, 0x0000000a, 0x00000000, 1, 0}, ++// HDMI System ++ {0x8545, 0x00000031, 0x00000000, 1, 0}, ++ {0x8546, 0x0000002d, 0x00000000, 1, 0}, ++// HDCP Setting ++ {0x85d1, 0x00000001, 0x00000000, 1, 0}, ++ {0x8560, 0x00000024, 0x00000000, 1, 0}, ++ {0x8563, 0x00000011, 0x00000000, 1, 0}, ++ {0x8564, 0x0000000f, 0x00000000, 1, 0}, ++// RGB --> YUV Conversion ++// {0x8574, 0x00000000, 0x00000000, 1, 0}, ++ {0x8573, 0x00000081, 0x00000000, 1, 0}, ++ {0x8571, 0x00000002, 0x00000000, 1, 0}, ++// HDMI Audio In Setting ++ {0x8600, 0x00000000, 0x00000000, 1, 0}, ++ {0x8602, 0x000000f3, 0x00000000, 1, 0}, ++ {0x8603, 0x00000002, 0x00000000, 1, 0}, ++ {0x8604, 0x0000000c, 0x00000000, 1, 0}, ++ {0x8606, 0x00000005, 0x00000000, 1, 0}, ++ {0x8607, 0x00000000, 0x00000000, 1, 0}, ++ {0x8620, 0x00000022, 0x00000000, 1, 0}, ++ {0x8640, 0x00000001, 0x00000000, 1, 0}, ++ {0x8641, 0x00000065, 0x00000000, 1, 0}, ++ {0x8642, 0x00000007, 0x00000000, 1, 0}, ++ {0x8652, 0x00000002, 0x00000000, 1, 0}, ++ {0x8665, 0x00000010, 0x00000000, 1, 0}, ++// InfoFrame Extraction ++ {0x8709, 0x000000ff, 0x00000000, 1, 0}, ++ {0x870b, 0x0000002c, 0x00000000, 1, 0}, ++ {0x870c, 0x00000053, 0x00000000, 1, 0}, ++ {0x870d, 0x00000001, 0x00000000, 1, 0}, ++ {0x870e, 0x00000030, 0x00000000, 1, 0}, ++ {0x9007, 0x00000010, 0x00000000, 1, 0}, ++ {0x854a, 0x00000001, 0x00000000, 1, 0}, ++// Output Control ++ {0x0004, 0x00000cf7, 0x00000000, 2, 0}, ++ ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_720P_60fps_1280_720_133Mhz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0014, 0x0000ffff, 0x00000000, 2, 0}, ++ {0x0016, 0x000005ff, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x00004062, 0x00000000, 2, 0}, ++ {0x0022, 0x00000613, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00000d00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000001, 0x00000000, 4, 0}, ++ {0x0218, 0x00000701, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000001, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000005, 0x00000000, 4, 0}, ++ {0x022c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa300be86, 0x00000000, 4, 0}, ++// HDMI Interrupt Mask ++ {0x8502, 0x00000001, 0x00000000, 1, 0}, ++ {0x8512, 0x000000fe, 0x00000000, 1, 0}, ++ {0x8514, 0x00000000, 0x00000000, 1, 0}, ++ {0x8515, 0x00000000, 0x00000000, 1, 0}, ++ {0x8516, 0x00000000, 0x00000000, 1, 0}, ++// HDMI Audio ++ {0x8531, 0x00000001, 0x00000000, 1, 0}, ++ {0x8630, 0x00041eb0, 0x00000000, 1, 0}, ++ {0x8670, 0x00000001, 0x00000000, 1, 0}, ++// HDMI PHY ++ {0x8532, 0x00000080, 0x00000000, 1, 0}, ++ {0x8536, 0x00000040, 0x00000000, 1, 0}, ++ {0x853f, 0x0000000a, 0x00000000, 1, 0}, ++// HDMI System ++ {0x8545, 0x00000031, 0x00000000, 1, 0}, ++ {0x8546, 0x0000002d, 0x00000000, 1, 0}, ++// HDCP Setting ++ {0x85d1, 0x00000001, 0x00000000, 1, 0}, ++ {0x8560, 0x00000024, 0x00000000, 1, 0}, ++ {0x8563, 0x00000011, 0x00000000, 1, 0}, ++ {0x8564, 0x0000000f, 0x00000000, 1, 0}, ++// RGB --> YUV Conversion ++// {0x8574, 0x00000000, 0x00000000, 1, 0}, ++ {0x8573, 0x00000081, 0x00000000, 1, 0}, ++ {0x8571, 0x00000002, 0x00000000, 1, 0}, ++// HDMI Audio In Setting ++ {0x8600, 0x00000000, 0x00000000, 1, 0}, ++ {0x8602, 0x000000f3, 0x00000000, 1, 0}, ++ {0x8603, 0x00000002, 0x00000000, 1, 0}, ++ {0x8604, 0x0000000c, 0x00000000, 1, 0}, ++ {0x8606, 0x00000005, 0x00000000, 1, 0}, ++ {0x8607, 0x00000000, 0x00000000, 1, 0}, ++ {0x8620, 0x00000022, 0x00000000, 1, 0}, ++ {0x8640, 0x00000001, 0x00000000, 1, 0}, ++ {0x8641, 0x00000065, 0x00000000, 1, 0}, ++ {0x8642, 0x00000007, 0x00000000, 1, 0}, ++ {0x8652, 0x00000002, 0x00000000, 1, 0}, ++ {0x8665, 0x00000010, 0x00000000, 1, 0}, ++// InfoFrame Extraction ++ {0x8709, 0x000000ff, 0x00000000, 1, 0}, ++ {0x870b, 0x0000002c, 0x00000000, 1, 0}, ++ {0x870c, 0x00000053, 0x00000000, 1, 0}, ++ {0x870d, 0x00000001, 0x00000000, 1, 0}, ++ {0x870e, 0x00000030, 0x00000000, 1, 0}, ++ {0x9007, 0x00000010, 0x00000000, 1, 0}, ++ {0x854a, 0x00000001, 0x00000000, 1, 0}, ++// Output Control ++ {0x0004, 0x00000cf7, 0x00000000, 2, 0}, ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x0000405c, 0x00000000, 2, 0}, ++ {0x0022, 0x00000613, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00000e00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000001, 0x00000000, 4, 0}, ++ {0x0218, 0x00000801, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000001, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000006, 0x00000000, 4, 0}, ++ {0x022c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0234, 0x00000007, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, //non-continuous clock ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa30080a2, 0x00000000, 4, 0}, ++// 1280x720 colorbar ++ {0x000a, 0x00000a00, 0x00000000, 2, 0}, ++ {0x7080, 0x00000082, 0x00000000, 2, 0}, ++// 128 pixel black - repeat 128 times ++ {0x7000, 0x0000007f, 0x00000000, 2, (1<<24)|(128<<16)}, ++// 128 pixel blue - repeat 64 times ++ {0x7000, 0x000000ff, 0x00000000, 2, 0}, ++ {0x7000, 0x00000000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel red - repeat 64 times ++ {0x7000, 0x00000000, 0x00000000, 2, 0}, ++ {0x7000, 0x000000ff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel pink - repeat 64 times ++ {0x7000, 0x00007fff, 0x00000000, 2, 0}, ++ {0x7000, 0x00007fff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel green - repeat 64 times ++ {0x7000, 0x00007f00, 0x00000000, 2, 0}, ++ {0x7000, 0x00007f00, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel light blue - repeat 64 times ++ {0x7000, 0x0000c0ff, 0x00000000, 2, 0}, ++ {0x7000, 0x0000c000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel yellow - repeat 64 times ++ {0x7000, 0x0000ff00, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ffff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel white - repeat 64 times ++ {0x7000, 0x0000ff7f, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ff7f, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 720 lines ++ {0x7090, 0x000002cf, 0x00000000, 2, 0}, ++ {0x7092, 0x00000580, 0x00000000, 2, 0}, ++ {0x7094, 0x00000010, 0x00000000, 2, 0}, ++ {0x7080, 0x00000083, 0x00000000, 2, 0}, ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_color_bar_1280_720_125MHz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x0000405c, 0x00000000, 2, 0}, ++ {0x0022, 0x00000613, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00000e00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000001, 0x00000000, 4, 0}, ++ {0x0218, 0x00000801, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000001, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000006, 0x00000000, 4, 0}, ++ {0x022c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001F, 0x00000000, 4, 0}, //{0x0234, 0x00000007, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, //non-continuous clock ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa30080a6, 0x00000000, 4, 0}, //{0x0500, 0xa30080a2, 0x00000000, 4, 0}, ++// 1280x720 colorbar ++ {0x000a, 0x00000a00, 0x00000000, 2, 0}, ++ {0x7080, 0x00000082, 0x00000000, 2, 0}, ++// 128 pixel black - repeat 128 times ++ {0x7000, 0x0000007f, 0x00000000, 2, (1<<24)|(128<<16)}, ++// 128 pixel blue - repeat 64 times ++ {0x7000, 0x000000ff, 0x00000000, 2, 0}, ++ {0x7000, 0x00000000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel red - repeat 64 times ++ {0x7000, 0x00000000, 0x00000000, 2, 0}, ++ {0x7000, 0x000000ff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel pink - repeat 64 times ++ {0x7000, 0x00007fff, 0x00000000, 2, 0}, ++ {0x7000, 0x00007fff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel green - repeat 64 times ++ {0x7000, 0x00007f00, 0x00000000, 2, 0}, ++ {0x7000, 0x00007f00, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel light blue - repeat 64 times ++ {0x7000, 0x0000c0ff, 0x00000000, 2, 0}, ++ {0x7000, 0x0000c000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel yellow - repeat 64 times ++ {0x7000, 0x0000ff00, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ffff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel white - repeat 64 times ++ {0x7000, 0x0000ff7f, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ff7f, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 720 lines ++ {0x7090, 0x000002cf, 0x00000000, 2, 0}, ++ {0x7092, 0x00000300, 0x00000000, 2, 0}, //{0x7092, 0x00000580, 0x00000000, 2, 0}, ++ {0x7094, 0x00000010, 0x00000000, 2, 0}, ++ {0x7080, 0x00000083, 0x00000000, 2, 0}, ++}; ++ ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_color_bar_1024_720_200MHz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x00004050, 0x00000000, 2, 0}, ++ {0x0022, 0x00000213, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00001800, 0x00000000, 4, 0}, ++ {0x0214, 0x00000002, 0x00000000, 4, 0}, ++ {0x0218, 0x00001102, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000003, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000007, 0x00000000, 4, 0}, ++ {0x022c, 0x00000001, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, //non-continuous clock ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa30080a6, 0x00000000, 4, 0}, ++// 1280x720 colorbar ++ {0x000a, 0x00000800, 0x00000000, 2, 0}, ++ {0x7080, 0x00000082, 0x00000000, 2, 0}, ++// 128 pixel black - repeat 128 times ++ {0x7000, 0x0000007f, 0x00000000, 2, (1<<24)|(128<<16)}, ++// 128 pixel blue - repeat 64 times ++ {0x7000, 0x000000ff, 0x00000000, 2, 0}, ++ {0x7000, 0x00000000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel red - repeat 64 times ++ {0x7000, 0x00000000, 0x00000000, 2, 0}, ++ {0x7000, 0x000000ff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel pink - repeat 64 times ++ {0x7000, 0x00007fff, 0x00000000, 2, 0}, ++ {0x7000, 0x00007fff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel green - repeat 64 times ++ {0x7000, 0x00007f00, 0x00000000, 2, 0}, ++ {0x7000, 0x00007f00, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel light blue - repeat 64 times ++ {0x7000, 0x0000c0ff, 0x00000000, 2, 0}, ++ {0x7000, 0x0000c000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel yellow - repeat 64 times ++ {0x7000, 0x0000ff00, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ffff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel white - repeat 64 times ++ {0x7000, 0x0000ff7f, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ff7f, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 720 lines ++ {0x0020, 0x0000406f, 0x00000000, 2, 100}, ++ {0x7090, 0x000002cf, 0x00000000, 2, 0}, ++ {0x7092, 0x00000540, 0x00000000, 2, 0}, ++ {0x7094, 0x00000010, 0x00000000, 2, 0}, ++ {0x7080, 0x00000083, 0x00000000, 2, 0}, ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x000080c7, 0x00000000, 2, 0}, ++ {0x0022, 0x00000213, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00001e00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000003, 0x00000000, 4, 0}, ++ {0x0218, 0x00001402, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000003, 0x00000000, 4, 0}, ++ {0x0224, 0x00004a00, 0x00000000, 4, 0}, ++ {0x0228, 0x00000008, 0x00000000, 4, 0}, ++ {0x022c, 0x00000002, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, //non-continuous clock ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa30080a6, 0x00000000, 4, 0}, ++// 1280x720 colorbar ++ {0x000a, 0x00000a00, 0x00000000, 2, 0}, ++ {0x7080, 0x00000082, 0x00000000, 2, 0}, ++// 128 pixel black - repeat 128 times ++ {0x7000, 0x0000007f, 0x00000000, 2, (1<<24)|(128<<16)}, ++// 128 pixel blue - repeat 64 times ++ {0x7000, 0x000000ff, 0x00000000, 2, 0}, ++ {0x7000, 0x00000000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel red - repeat 64 times ++ {0x7000, 0x00000000, 0x00000000, 2, 0}, ++ {0x7000, 0x000000ff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel pink - repeat 64 times ++ {0x7000, 0x00007fff, 0x00000000, 2, 0}, ++ {0x7000, 0x00007fff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel green - repeat 64 times ++ {0x7000, 0x00007f00, 0x00000000, 2, 0}, ++ {0x7000, 0x00007f00, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel light blue - repeat 64 times ++ {0x7000, 0x0000c0ff, 0x00000000, 2, 0}, ++ {0x7000, 0x0000c000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel yellow - repeat 64 times ++ {0x7000, 0x0000ff00, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ffff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel white - repeat 64 times ++ {0x7000, 0x0000ff7f, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ff7f, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 720 lines ++ {0x7090, 0x000002cf, 0x00000000, 2, 0}, ++ {0x7092, 0x000006b8, 0x00000000, 2, 0}, ++ {0x7094, 0x00000010, 0x00000000, 2, 0}, ++ {0x7080, 0x00000083, 0x00000000, 2, 0}, ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_color_bar_1920_1023_300MHz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x000080c7, 0x00000000, 2, 0}, ++ {0x0022, 0x00000213, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00001e00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000003, 0x00000000, 4, 0}, ++ {0x0218, 0x00001402, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000003, 0x00000000, 4, 0}, ++ {0x0224, 0x00004a00, 0x00000000, 4, 0}, ++ {0x0228, 0x00000008, 0x00000000, 4, 0}, ++ {0x022c, 0x00000002, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, //non-continuous clock ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa30080a6, 0x00000000, 4, 0}, ++// 1920x1023 colorbar ++ {0x000a, 0x00000f00, 0x00000000, 2, 0}, ++ {0x7080, 0x00000082, 0x00000000, 2, 0}, ++// 128 pixel black - repeat 128 times ++ {0x7000, 0x0000007f, 0x00000000, 2, (1<<24)|(128<<16)}, ++// 128 pixel blue - repeat 64 times ++ {0x7000, 0x000000ff, 0x00000000, 2, 0}, ++ {0x7000, 0x00000000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel red - repeat 64 times ++ {0x7000, 0x00000000, 0x00000000, 2, 0}, ++ {0x7000, 0x000000ff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel pink - repeat 64 times ++ {0x7000, 0x00007fff, 0x00000000, 2, 0}, ++ {0x7000, 0x00007fff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel green - repeat 64 times ++ {0x7000, 0x00007f00, 0x00000000, 2, 0}, ++ {0x7000, 0x00007f00, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel light blue - repeat 64 times ++ {0x7000, 0x0000c0ff, 0x00000000, 2, 0}, ++ {0x7000, 0x0000c000, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel yellow - repeat 64 times ++ {0x7000, 0x0000ff00, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ffff, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 128 pixel white - repeat 64 times ++ {0x7000, 0x0000ff7f, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ff7f, 0x00000000, 2, (2<<24)|(64<<16)}, ++// 1023 lines ++ {0x7090, 0x000003fe, 0x00000000, 2, 0}, ++ {0x7092, 0x000004d8, 0x00000000, 2, 0}, ++ {0x7094, 0x0000002d, 0x00000000, 2, 0}, ++ {0x7080, 0x00000083, 0x00000000, 2, 0}, ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_2lane_color_bar_640_480_174MHz[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x00008073, 0x00000000, 2, 0}, ++ {0x0022, 0x00000213, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++// {0x014c, 0x00000000, 0x00000000, 4, 0}, ++// {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00001200, 0x00000000, 4, 0}, ++ {0x0214, 0x00000002, 0x00000000, 4, 0}, ++ {0x0218, 0x00000b02, 0x00000000, 4, 0}, ++ {0x021c, 0x00000001, 0x00000000, 4, 0}, ++ {0x0220, 0x00000103, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000008, 0x00000000, 4, 0}, ++ {0x022c, 0x00000002, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000000, 0x00000000, 4, 0}, ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xA3008082, 0x00000000, 4, 0}, ++// 640x480 colorbar ++ {0x000a, 0x00000500, 0x00000000, 2, 0}, ++ {0x7080, 0x00000082, 0x00000000, 2, 0}, ++// 80 pixel black - repeate 80 times ++ {0x7000, 0x0000007f, 0x00000000, 2, (1<<24)|(80<<16)}, ++// 80 pixel blue - repeate 40 times ++ {0x7000, 0x000000ff, 0x00000000, 2, 0}, ++ {0x7000, 0x00000000, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel red - repeate 40 times ++ {0x7000, 0x00000000, 0x00000000, 2, 0}, ++ {0x7000, 0x000000ff, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel pink - repeate 40 times ++ {0x7000, 0x00007fff, 0x00000000, 2, 0}, ++ {0x7000, 0x00007fff, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel green - repeate 40 times ++ {0x7000, 0x00007f00, 0x00000000, 2, 0}, ++ {0x7000, 0x00007f00, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel light blue - repeate 40 times ++ {0x7000, 0x0000c0ff, 0x00000000, 2, 0}, ++ {0x7000, 0x0000c000, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel yellow - repeate 40 times ++ {0x7000, 0x0000ff00, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ffff, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel white - repeate 40 times ++ {0x7000, 0x0000ff7f, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ff7f, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 480 lines ++ {0x7090, 0x000001df, 0x00000000, 2, 0}, ++ {0x7092, 0x00000898, 0x00000000, 2, 0}, ++ {0x7094, 0x00000285, 0x00000000, 2, 0}, ++ {0x7080, 0x00000083, 0x00000000, 2, 0}, ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_2lane_color_bar_640_480_108MHz_cont[] = { ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x0000404F, 0x00000000, 2, 0}, ++ {0x0022, 0x00000613, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00001800, 0x00000000, 4, 0}, ++ {0x0214, 0x00000002, 0x00000000, 4, 0}, ++ {0x0218, 0x00001102, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000003, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000007, 0x00000000, 4, 0}, ++ {0x022c, 0x00000001, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xA30080A2, 0x00000000, 4, 0}, ++// 640x480 colorbar ++ {0x000a, 0x00000500, 0x00000000, 2, 0}, ++ {0x7080, 0x00000082, 0x00000000, 2, 0}, ++// 80 pixel black - repeate 80 times ++ {0x7000, 0x0000007f, 0x00000000, 2, (1<<24)|(80<<16)}, ++// 80 pixel blue - repeate 40 times ++ {0x7000, 0x000000ff, 0x00000000, 2, 0}, ++ {0x7000, 0x00000000, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel red - repeate 40 times ++ {0x7000, 0x00000000, 0x00000000, 2, 0}, ++ {0x7000, 0x000000ff, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel pink - repeate 40 times ++ {0x7000, 0x00007fff, 0x00000000, 2, 0}, ++ {0x7000, 0x00007fff, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel green - repeate 40 times ++ {0x7000, 0x00007f00, 0x00000000, 2, 0}, ++ {0x7000, 0x00007f00, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel light blue - repeate 40 times ++ {0x7000, 0x0000c0ff, 0x00000000, 2, 0}, ++ {0x7000, 0x0000c000, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel yellow - repeate 40 times ++ {0x7000, 0x0000ff00, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ffff, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 80 pixel white - repeate 40 times ++ {0x7000, 0x0000ff7f, 0x00000000, 2, 0}, ++ {0x7000, 0x0000ff7f, 0x00000000, 2, (2<<24)|(40<<16)}, ++// 480 lines ++ {0x7090, 0x000001df, 0x00000000, 2, 0}, ++ {0x7092, 0x00000700, 0x00000000, 2, 0}, ++ {0x7094, 0x00000010, 0x00000000, 2, 0}, ++ {0x7080, 0x00000083, 0x00000000, 2, 0}, ++}; ++ ++//480p RGB2YUV442 ++static const struct reg_value tc358743_setting_YUV422_2lane_60fps_640_480_125Mhz[] = { ++ {0x0006, 0x00000040, 0x00000000, 2, 0}, ++// {0x000a, 0x000005a0, 0x00000000, 2, 0}, ++// {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++ {0x0014, 0x00000000, 0x00000000, 2, 0}, ++ {0x0016, 0x000005ff, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x0000405c, 0x00000000, 2, 0}, ++ {0x0022, 0x00000613, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00000d00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000001, 0x00000000, 4, 0}, ++ {0x0218, 0x00000701, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000001, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000005, 0x00000000, 4, 0}, ++ {0x022c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xA30080A2, 0x00000000, 4, 0}, ++// HDMI Interrupt Mask ++ {0x8502, 0x00000001, 0x00000000, 1, 0}, ++ {0x8512, 0x000000fe, 0x00000000, 1, 0}, ++ {0x8514, 0x00000000, 0x00000000, 1, 0}, ++ {0x8515, 0x00000000, 0x00000000, 1, 0}, ++ {0x8516, 0x00000000, 0x00000000, 1, 0}, ++// HDMI Audio ++ {0x8531, 0x00000001, 0x00000000, 1, 0}, ++ {0x8630, 0x00041eb0, 0x00000000, 1, 0}, ++ {0x8670, 0x00000001, 0x00000000, 1, 0}, ++// HDMI PHY ++ {0x8532, 0x00000080, 0x00000000, 1, 0}, ++ {0x8536, 0x00000040, 0x00000000, 1, 0}, ++ {0x853f, 0x0000000a, 0x00000000, 1, 0}, ++// HDMI System ++ {0x8545, 0x00000031, 0x00000000, 1, 0}, ++ {0x8546, 0x0000002d, 0x00000000, 1, 0}, ++// HDCP Setting ++ {0x85d1, 0x00000001, 0x00000000, 1, 0}, ++ {0x8560, 0x00000024, 0x00000000, 1, 0}, ++ {0x8563, 0x00000011, 0x00000000, 1, 0}, ++ {0x8564, 0x0000000f, 0x00000000, 1, 0}, ++// RGB --> YUV Conversion ++ {0x8573, 0x00000081, 0x00000000, 1, 0}, ++ {0x8571, 0x00000002, 0x00000000, 1, 0}, ++// HDMI Audio In Setting ++ {0x8600, 0x00000000, 0x00000000, 1, 0}, ++ {0x8602, 0x000000f3, 0x00000000, 1, 0}, ++ {0x8603, 0x00000002, 0x00000000, 1, 0}, ++ {0x8604, 0x0000000c, 0x00000000, 1, 0}, ++ {0x8606, 0x00000005, 0x00000000, 1, 0}, ++ {0x8607, 0x00000000, 0x00000000, 1, 0}, ++ {0x8620, 0x00000022, 0x00000000, 1, 0}, ++ {0x8640, 0x00000001, 0x00000000, 1, 0}, ++ {0x8641, 0x00000065, 0x00000000, 1, 0}, ++ {0x8642, 0x00000007, 0x00000000, 1, 0}, ++ {0x8652, 0x00000002, 0x00000000, 1, 0}, ++ {0x8665, 0x00000010, 0x00000000, 1, 0}, ++// InfoFrame Extraction ++ {0x8709, 0x000000ff, 0x00000000, 1, 0}, ++ {0x870b, 0x0000002c, 0x00000000, 1, 0}, ++ {0x870c, 0x00000053, 0x00000000, 1, 0}, ++ {0x870d, 0x00000001, 0x00000000, 1, 0}, ++ {0x870e, 0x00000030, 0x00000000, 1, 0}, ++ {0x9007, 0x00000010, 0x00000000, 1, 0}, ++ {0x854a, 0x00000001, 0x00000000, 1, 0}, ++// Output Control ++ {0x0004, 0x00000cf7, 0x00000000, 2, 0}, ++ }; ++ ++//480p RGB2YUV442 ++static const struct reg_value tc358743_setting_YUV422_2lane_60fps_720_480_125Mhz[] = { ++ {0x0006, 0x00000040, 0x00000000, 2, 0}, ++ {0x000a, 0x000005a0, 0x00000000, 2, 0}, ++// {0x0010, 0x0000001e, 0x00000000, 2, 0}, ++ {0x0014, 0x00000000, 0x00000000, 2, 0}, ++ {0x0016, 0x000005ff, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x0000405b, 0x00000000, 2, 0}, ++ {0x0022, 0x00000613, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00000d00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000001, 0x00000000, 4, 0}, ++ {0x0218, 0x00000701, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000001, 0x00000000, 4, 0}, ++ {0x0224, 0x00004000, 0x00000000, 4, 0}, ++ {0x0228, 0x00000005, 0x00000000, 4, 0}, ++ {0x022c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xA30080A2, 0x00000000, 4, 0}, ++// HDMI Interrupt Mask ++ {0x8502, 0x00000001, 0x00000000, 1, 0}, ++ {0x8512, 0x000000fe, 0x00000000, 1, 0}, ++ {0x8514, 0x00000000, 0x00000000, 1, 0}, ++ {0x8515, 0x00000000, 0x00000000, 1, 0}, ++ {0x8516, 0x00000000, 0x00000000, 1, 0}, ++// HDMI Audio ++ {0x8531, 0x00000001, 0x00000000, 1, 0}, ++ {0x8630, 0x00041eb0, 0x00000000, 1, 0}, ++ {0x8670, 0x00000001, 0x00000000, 1, 0}, ++// HDMI PHY ++ {0x8532, 0x00000080, 0x00000000, 1, 0}, ++ {0x8536, 0x00000040, 0x00000000, 1, 0}, ++ {0x853f, 0x0000000a, 0x00000000, 1, 0}, ++// HDMI System ++ {0x8545, 0x00000031, 0x00000000, 1, 0}, ++ {0x8546, 0x0000002d, 0x00000000, 1, 0}, ++// HDCP Setting ++ {0x85d1, 0x00000001, 0x00000000, 1, 0}, ++ {0x8560, 0x00000024, 0x00000000, 1, 0}, ++ {0x8563, 0x00000011, 0x00000000, 1, 0}, ++ {0x8564, 0x0000000f, 0x00000000, 1, 0}, ++// RGB --> YUV Conversion ++ {0x8573, 0x00000081, 0x00000000, 1, 0}, ++ {0x8571, 0x00000002, 0x00000000, 1, 0}, ++// HDMI Audio In Setting ++ {0x8600, 0x00000000, 0x00000000, 1, 0}, ++ {0x8602, 0x000000f3, 0x00000000, 1, 0}, ++ {0x8603, 0x00000002, 0x00000000, 1, 0}, ++ {0x8604, 0x0000000c, 0x00000000, 1, 0}, ++ {0x8606, 0x00000005, 0x00000000, 1, 0}, ++ {0x8607, 0x00000000, 0x00000000, 1, 0}, ++ {0x8620, 0x00000022, 0x00000000, 1, 0}, ++ {0x8640, 0x00000001, 0x00000000, 1, 0}, ++ {0x8641, 0x00000065, 0x00000000, 1, 0}, ++ {0x8642, 0x00000007, 0x00000000, 1, 0}, ++ {0x8652, 0x00000002, 0x00000000, 1, 0}, ++ {0x8665, 0x00000010, 0x00000000, 1, 0}, ++// InfoFrame Extraction ++ {0x8709, 0x000000ff, 0x00000000, 1, 0}, ++ {0x870b, 0x0000002c, 0x00000000, 1, 0}, ++ {0x870c, 0x00000053, 0x00000000, 1, 0}, ++ {0x870d, 0x00000001, 0x00000000, 1, 0}, ++ {0x870e, 0x00000030, 0x00000000, 1, 0}, ++ {0x9007, 0x00000010, 0x00000000, 1, 0}, ++ {0x854a, 0x00000001, 0x00000000, 1, 0}, ++// Output Control ++ {0x0004, 0x00000cf7, 0x00000000, 2, 0}, ++ }; ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_1080P_60fps_1920_1080_300MHz[] = { ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, ++ {0x0006, 0x00000000, 0x00000000, 2, 0}, ++ {0x0014, 0x00000000, 0x00000000, 2, 0}, ++ {0x0016, 0x000005ff, 0x00000000, 2, 0}, ++// Program CSI Tx PLL ++ {0x0020, 0x000080c7, 0x00000000, 2, 0}, ++ {0x0022, 0x00000213, 0x00000000, 2, 0}, ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00001e00, 0x00000000, 4, 0}, ++ {0x0214, 0x00000003, 0x00000000, 4, 0}, ++ {0x0218, 0x00001402, 0x00000000, 4, 0}, ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, ++ {0x0220, 0x00000003, 0x00000000, 4, 0}, ++ {0x0224, 0x00004a00, 0x00000000, 4, 0}, ++ {0x0228, 0x00000008, 0x00000000, 4, 0}, ++ {0x022c, 0x00000002, 0x00000000, 4, 0}, ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, ++ {0x0500, 0xa30080a6, 0x00000000, 4, 0}, ++// HDMI Interrupt Mask ++ {0x8502, 0x00000001, 0x00000000, 1, 0}, ++ {0x8512, 0x000000fe, 0x00000000, 1, 0}, ++ {0x8514, 0x00000000, 0x00000000, 1, 0}, ++ {0x8515, 0x00000000, 0x00000000, 1, 0}, ++ {0x8516, 0x00000000, 0x00000000, 1, 0}, ++// HDMI Audio ++ {0x8531, 0x00000001, 0x00000000, 1, 0}, ++ {0x8630, 0x00041eb0, 0x00000000, 1, 0}, ++ {0x8670, 0x00000001, 0x00000000, 1, 0}, ++// HDMI PHY ++ {0x8532, 0x00000080, 0x00000000, 1, 0}, ++ {0x8536, 0x00000040, 0x00000000, 1, 0}, ++ {0x853f, 0x0000000a, 0x00000000, 1, 0}, ++// HDMI System ++ {0x8545, 0x00000031, 0x00000000, 1, 0}, ++ {0x8546, 0x0000002d, 0x00000000, 1, 0}, ++// HDCP Setting ++ {0x85d1, 0x00000001, 0x00000000, 1, 0}, ++ {0x8560, 0x00000024, 0x00000000, 1, 0}, ++ {0x8563, 0x00000011, 0x00000000, 1, 0}, ++ {0x8564, 0x0000000f, 0x00000000, 1, 0}, ++// RGB --> YUV Conversion ++ {0x8571, 0x00000002, 0x00000000, 1, 0}, ++ {0x8573, 0x00000081, 0x00000000, 1, 0}, ++ {0x8576, 0x00000060, 0x00000000, 1, 0}, ++// HDMI Audio In Setting ++ {0x8600, 0x00000000, 0x00000000, 1, 0}, ++ {0x8602, 0x000000f3, 0x00000000, 1, 0}, ++ {0x8603, 0x00000002, 0x00000000, 1, 0}, ++ {0x8604, 0x0000000c, 0x00000000, 1, 0}, ++ {0x8606, 0x00000005, 0x00000000, 1, 0}, ++ {0x8607, 0x00000000, 0x00000000, 1, 0}, ++ {0x8620, 0x00000022, 0x00000000, 1, 0}, ++ {0x8640, 0x00000001, 0x00000000, 1, 0}, ++ {0x8641, 0x00000065, 0x00000000, 1, 0}, ++ {0x8642, 0x00000007, 0x00000000, 1, 0}, ++ {0x8652, 0x00000002, 0x00000000, 1, 0}, ++ {0x8665, 0x00000010, 0x00000000, 1, 0}, ++// InfoFrame Extraction ++ {0x8709, 0x000000ff, 0x00000000, 1, 0}, ++ {0x870b, 0x0000002c, 0x00000000, 1, 0}, ++ {0x870c, 0x00000053, 0x00000000, 1, 0}, ++ {0x870d, 0x00000001, 0x00000000, 1, 0}, ++ {0x870e, 0x00000030, 0x00000000, 1, 0}, ++ {0x9007, 0x00000010, 0x00000000, 1, 0}, ++ {0x854a, 0x00000001, 0x00000000, 1, 0}, ++// Output Control ++ {0x0004, 0x00000cf7, 0x00000000, 2, 0}, ++}; ++ ++static const struct reg_value tc358743_setting_YUV422_4lane_1080P_30fps_1920_1080_300MHz[] = { ++ {0x0004, 0x00000084, 0x00000000, 2, 0}, // Internal Generated output pattern,Do not send InfoFrame data out to CSI2,Audio output to CSI2-TX i/f,I2C address index increments on every data byte transfer, disable audio and video TX buffers ++ {0x0006, 0x000001f8, 0x00000000, 2, 0}, // FIFO level = 1f8 = 504 ++ {0x0014, 0x00000000, 0x00000000, 2, 0}, // Clear interrupt status bits ++ {0x0016, 0x000005ff, 0x00000000, 2, 0}, // Mask audio mute, CSI-TX, and the other interrups ++// Program CSI Tx PLL ++ //{0x0020, 0x000080c7, 0x00000000, 2, 0}, // Input divider setting = 0x8 -> Division ratio = (PRD3..0) + 1 = 9, Feedback divider setting = 0xc7 -> Division ratio = (FBD8...0) + 1 = 200 ++ {0x0020, 0x000080c7, 0x00000000, 2, 0}, // Input divider setting = 0x8 -> Division ratio = (PRD3..0) + 1 = 9, Feedback divider setting = 0xc7 -> Division ratio = (FBD8...0) + 1 = 200 ++ {0x0022, 0x00000213, 0x00000000, 2, 0}, // HSCK frequency = 500MHz – 1GHz HSCK frequency, Loop bandwidth setting = 50% of maximum loop bandwidth (default), REFCLK toggling –> normal operation, REFCLK stops -> no oscillation, Bypass clock = normal operation, clocks switched off (output LOW), PLL Reset normal operation, PLL Enable = PLL on ++// CSI Tx PHY (32-bit Registers) ++ {0x0140, 0x00000000, 0x00000000, 4, 0}, // Clock Lane DPHY Control: Bypass Lane Enable from PPI Layer enable. ++ {0x0144, 0x00000000, 0x00000000, 4, 0}, // Data Lane 0 DPHY Control: Bypass Lane Enable from PPI Layer enable. ++ {0x0148, 0x00000000, 0x00000000, 4, 0}, // Data Lane 1 DPHY Control: Bypass Lane Enable from PPI Layer enable. ++ {0x014c, 0x00000000, 0x00000000, 4, 0}, // Data Lane 2 DPHY Control: Bypass Lane Enable from PPI Layer enable. ++ {0x0150, 0x00000000, 0x00000000, 4, 0}, // Data Lane 3 DPHY Control: Bypass Lane Enable from PPI Layer enable. ++// CSI Tx PPI (32-bit Registers) ++ {0x0210, 0x00001e00, 0x00000000, 4, 0}, // LINEINITCNT: Line Initialization Wait Counter = 0x1e00 = 7680 ++ {0x0214, 0x00000003, 0x00000000, 4, 0}, // LPTXTIMECNT: SYSLPTX Timing Generation Counter = 3 ++ {0x0218, 0x00001402, 0x00000000, 4, 0}, // TCLK_HEADERCNT: TCLK_ZERO Counter = 0x14 = 20, TCLK_PREPARE Counter = 0x02 = 2 ++ {0x021c, 0x00000000, 0x00000000, 4, 0}, // TCLK_TRAILCNT: TCLK_TRAIL Counter = 0 ++ {0x0220, 0x00000003, 0x00000000, 4, 0}, // THS_HEADERCNT: THS_ZERO Counter = 0, THS_PREPARE Counter = 3 ++ {0x0224, 0x00004a00, 0x00000000, 4, 0}, // TWAKEUP: TWAKEUP Counter = 0x4a00 = 18944 ++ {0x0228, 0x00000008, 0x00000000, 4, 0}, // TCLK_POSTCNT: TCLK_POST Counter = 8 ++ {0x022c, 0x00000002, 0x00000000, 4, 0}, // THS_TRAILCNT: THS_TRAIL Counter = 2 ++ {0x0234, 0x0000001f, 0x00000000, 4, 0}, // HSTXVREGEN: Enable voltage regulators for lanes and clk ++ {0x0238, 0x00000001, 0x00000000, 4, 0}, // TXOPTIONCNTRL: Set Continuous Clock Mode ++ {0x0204, 0x00000001, 0x00000000, 4, 0}, // PPI STARTCNTRL: start PPI function ++ {0x0518, 0x00000001, 0x00000000, 4, 0}, // CSI_START: start ++ {0x0500, 0xa30080a6, 0x00000000, 4, 0}, // CSI Configuration Register: set register 0x040C with data 0x80a6 (CSI MOde, Disables the HTX_TO timer, High-Speed data transfer is performed to Tx, DSCClk Stays in HS mode when Data Lane goes to LP, 4 Data Lanes,The EOT packet is automatically granted at the end of HS transfer then is transmitted) ++// HDMI Interrupt Mask ++ {0x8502, 0x00000001, 0x00000000, 1, 0}, // SYSTEM INTERRUPT: clear DDC power change detection interrupt ++ {0x8512, 0x000000fe, 0x00000000, 1, 0}, // SYS INTERRUPT MASK: DDC power change detection interrupt not masked ++ {0x8514, 0x00000000, 0x00000000, 1, 0}, // PACKET INTERRUPT MASK: unmask all ++ {0x8515, 0x00000000, 0x00000000, 1, 0}, // CBIT INTERRUPT MASK: unmask all ++ {0x8516, 0x00000000, 0x00000000, 1, 0}, // AUDIO INTERRUPT MASK: unmask all ++// HDMI Audio ++ {0x8531, 0x00000001, 0x00000000, 1, 0}, // PHY CONTROL0: 27MHz, DDC5V detection operation. ++ {0x8630, 0x00041eb0, 0x00000000, 1, 0}, // Audio FS Lock Detect Control: for 27MHz ++ {0x8670, 0x00000001, 0x00000000, 1, 0}, ++// HDMI PHY ++ {0x8532, 0x00000080, 0x00000000, 1, 0}, // ++ {0x8536, 0x00000040, 0x00000000, 1, 0}, // ++ {0x853f, 0x0000000a, 0x00000000, 1, 0}, // ++// HDMI System ++ {0x8545, 0x00000031, 0x00000000, 1, 0}, // ANA CONTROL: PLL charge pump setting for Audio = normal, DAC/PLL power ON/OFF setting for Audio = ON ++ {0x8546, 0x0000002d, 0x00000000, 1, 0}, // AVMUTE CONTROL: AVM_CTL = 0x2d ++// HDCP Setting ++ {0x85d1, 0x00000001, 0x00000000, 1, 0}, // ++ {0x8560, 0x00000024, 0x00000000, 1, 0}, // HDCP MODE: HDCP automatic reset when DVI⇔HDMI switched = on, HDCP Line Rekey timing switch = 7clk mode (Data island delay ON), Bcaps[5] KSVINFO_READY(0x8840[5]) auto clear mode = Auto clear using AKSV write ++ {0x8563, 0x00000011, 0x00000000, 1, 0}, // ++ {0x8564, 0x0000000f, 0x00000000, 1, 0}, // ++// RGB --> YUV Conversion ++ {0x8571, 0x00000002, 0x00000000, 1, 0}, // ++ {0x8573, 0x000000c1, 0x00000000, 1, 0}, // VOUT SET2 REGISTER: 422 fixed output, Video Output 422 conversion mode selection 000: During 444 input, 3tap filter; during 422 input, simple decimation, Enable RGB888 to YUV422 Conversion (Fixed Color output) ++ {0x8574, 0x00000008, 0x00000000, 1, 0}, // VOUT SET3 REGISTER (VOUT_SET3): Follow register bit 0x8573[7] setting ++ {0x8576, 0x00000060, 0x00000000, 1, 0}, // VOUT_COLOR: Output Color = 601 YCbCr Limited, Input Pixel Repetition judgment = automatic, Input Pixel Repetition HOST setting = no repetition ++// HDMI Audio In Setting ++ {0x8600, 0x00000000, 0x00000000, 1, 0}, ++ {0x8602, 0x000000f3, 0x00000000, 1, 0}, ++ {0x8603, 0x00000002, 0x00000000, 1, 0}, ++ {0x8604, 0x0000000c, 0x00000000, 1, 0}, ++ {0x8606, 0x00000005, 0x00000000, 1, 0}, ++ {0x8607, 0x00000000, 0x00000000, 1, 0}, ++ {0x8620, 0x00000022, 0x00000000, 1, 0}, ++ {0x8640, 0x00000001, 0x00000000, 1, 0}, ++ {0x8641, 0x00000065, 0x00000000, 1, 0}, ++ {0x8642, 0x00000007, 0x00000000, 1, 0}, ++ {0x8652, 0x00000002, 0x00000000, 1, 0}, ++ {0x8665, 0x00000010, 0x00000000, 1, 0}, ++// InfoFrame Extraction ++ {0x8709, 0x000000ff, 0x00000000, 1, 0}, // PACKET INTERRUPT MODE: all enable ++ {0x870b, 0x0000002c, 0x00000000, 1, 0}, // NO PACKET LIMIT: NO_ACP_LIMIT = 0x2, NO_AVI_LIMIT = 0xC ++ {0x870c, 0x00000053, 0x00000000, 1, 0}, // When VS receive interrupt is detected, VS storage register automatic clear, When ACP receive interrupt is detected, ACP storage register automatic clear, When AVI receive interrupt occurs, judge input video signal with RGB and no Repetition, When AVI receive interrupt is detected, AVI storage register automatic clear. ++ {0x870d, 0x00000001, 0x00000000, 1, 0}, // ERROR PACKET LIMIT: Packet continuing receive error occurrence detection threshold = 1 ++ {0x870e, 0x00000030, 0x00000000, 1, 0}, // NO PACKET LIMIT: ++ {0x9007, 0x00000010, 0x00000000, 1, 0}, // ++ {0x854a, 0x00000001, 0x00000000, 1, 0}, // Initialization completed flag ++// Output Control ++ {0x0004, 0x00000cf7, 0x00000000, 2, 0}, // Configuration Control Register: Power Island Normal, I2S/TDM clock are free running, Enable 2 Audio channels, Audio channel number Auto detect by HW, I2S/TDM Data no delay, Select YCbCr422 8-bit (HDMI YCbCr422 12-bit data format), Send InfoFrame data out to CSI2, Audio output to I2S i/f (valid for 2 channel only), I2C address index increments on every data byte transfer, Audio and Video tx buffres enable. ++}; ++ ++/* list of image formats supported by TCM825X sensor */ ++static const struct v4l2_fmtdesc tc358743_formats[] = { ++ { ++ .description = "RGB888 (RGB24)", ++ .pixelformat = V4L2_PIX_FMT_RGB24, /* 24 RGB-8-8-8 */ ++ .flags = MIPI_DT_RGB888 // 0x24 ++ }, ++ { ++ .description = "RAW12 (Y/CbCr 4:2:0)", ++ .pixelformat = V4L2_PIX_FMT_UYVY, /* 12 Y/CbCr 4:2:0 */ ++ .flags = MIPI_DT_RAW12 // 0x2c ++ }, ++ { ++ .description = "YUV 4:2:2 8-bit", ++ .pixelformat = V4L2_PIX_FMT_YUYV, /* 8 8-bit color */ ++ .flags = MIPI_DT_YUV422 // 0x1e /* UYVY... */ ++ }, ++}; ++ ++ ++static const struct tc358743_mode_info tc358743_mode_info_data[2][tc358743_mode_MAX] = { ++/* Color bar test settings */ ++ [1][tc358743_mode_INIT] = ++ {"cb640x480-108MHz@30", tc358743_mode_INIT, 640, 480, ++ 6, 1, 2, 108, ++ tc358743_setting_YUV422_2lane_color_bar_640_480_108MHz_cont, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_color_bar_640_480_108MHz_cont), ++ MIPI_DT_YUV422 ++ }, ++ [0][tc358743_mode_INIT] = ++ {"cb640x480-108MHz@60", tc358743_mode_INIT, 640, 480, ++ 6, 1, 2, 108, ++ tc358743_setting_YUV422_2lane_color_bar_640_480_108MHz_cont, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_color_bar_640_480_108MHz_cont), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_INIT4] = ++ {"cb640x480-174Mhz@30", tc358743_mode_INIT4, 640, 480, ++ 6, 1, 2, 174, ++ tc358743_setting_YUV422_2lane_color_bar_640_480_174MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_color_bar_640_480_174MHz), ++ MIPI_DT_YUV422 ++ }, ++ [0][tc358743_mode_INIT4] = ++ {"cb640x480-174MHz@60", tc358743_mode_INIT4, 640, 480, ++ 6, 1, 2, 174, ++ tc358743_setting_YUV422_2lane_color_bar_640_480_174MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_color_bar_640_480_174MHz), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_INIT3] = ++ {"cb1024x720-4lane@30", tc358743_mode_INIT3, 1024, 720, ++ 6, 1, 4, 300, ++ tc358743_setting_YUV422_4lane_color_bar_1024_720_200MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1024_720_200MHz), ++ MIPI_DT_YUV422 ++ }, ++ [0][tc358743_mode_INIT3] = ++ {"cb1024x720-4lane@60", tc358743_mode_INIT3, 1024, 720, ++ 6, 1, 4, 300, ++ tc358743_setting_YUV422_4lane_color_bar_1024_720_200MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1024_720_200MHz), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_INIT1] = ++ {"cb1280x720-2lane@30", tc358743_mode_INIT1, 1280, 720, ++ 12, 0, 2, 125, ++ tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz), ++ MIPI_DT_YUV422 ++ }, ++ [0][tc358743_mode_INIT1] = ++ {"cb1280x720-2lane@60", tc358743_mode_INIT1, 1280, 720, ++ 12, 0, 2, 125, ++ tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_INIT2] = ++ {"cb1280x720-4lane-125MHz@30", tc358743_mode_INIT2, 1280, 720, ++ 12, 0, 4, 125, ++ tc358743_setting_YUV422_4lane_color_bar_1280_720_125MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1280_720_125MHz), ++ MIPI_DT_YUV422 ++ }, ++ [0][tc358743_mode_INIT2] = ++ {"cb1280x720-4lane-125MHz@60", tc358743_mode_INIT2, 1280, 720, ++ 12, 0, 4, 125, ++ tc358743_setting_YUV422_4lane_color_bar_1280_720_125MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1280_720_125MHz), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_INIT5] = ++ {"cb1280x720-4lane-300MHz@30", tc358743_mode_INIT5, 1280, 720, ++ 12, 0, 4, 300, ++ tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz), ++ MIPI_DT_YUV422 ++ }, ++ [0][tc358743_mode_INIT5] = ++ {"cb1280x720-4lane-300MHz@60", tc358743_mode_INIT5, 1280, 720, ++ 12, 0, 4, 300, ++ tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_INIT6] = ++ {"cb1920x1023@30", tc358743_mode_INIT6, 1920, 1023, ++ 15, 0, 4, 300, ++ tc358743_setting_YUV422_4lane_color_bar_1920_1023_300MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1920_1023_300MHz), ++ MIPI_DT_YUV422 ++ }, ++ [0][tc358743_mode_INIT6] = ++ {"cb1920x1023@60", tc358743_mode_INIT6, 1920, 1023, ++ 15, 0, 4, 300, ++ tc358743_setting_YUV422_4lane_color_bar_1920_1023_300MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1920_1023_300MHz), ++ MIPI_DT_YUV422 ++ }, ++/* Input settings */ ++ [tc358743_60_fps][tc358743_mode_480P_640_480] = ++ {"640x480@60", tc358743_mode_480P_640_480, 640, 480, ++ 1, (0x02)<<8|(0x00), 2, 125, ++ tc358743_setting_YUV422_2lane_60fps_640_480_125Mhz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_60fps_640_480_125Mhz), ++ MIPI_DT_YUV422, ++ }, ++ [1][tc358743_mode_480P_720_480] = ++ {"720x480@30", tc358743_mode_480P_720_480, 720, 480, ++ 6, (0x02)<<8|(0x00), 2, 125, ++ tc358743_setting_YUV422_2lane_60fps_720_480_125Mhz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_60fps_720_480_125Mhz), ++ MIPI_DT_YUV422, ++ }, ++ [tc358743_60_fps][tc358743_mode_480P_720_480] = ++ {"720x480@60", tc358743_mode_480P_720_480, 720, 480, ++ 6, (0x02)<<8|(0x00), 2, 125, ++ tc358743_setting_YUV422_2lane_60fps_720_480_125Mhz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_60fps_720_480_125Mhz), ++ MIPI_DT_YUV422, ++ }, ++ [tc358743_60_fps][tc358743_mode_1024x768] = ++ {"1024x768@60", tc358743_mode_1024x768, 1024, 768, ++ 16, 60, 4, 125, ++ tc358743_setting_YUV422_4lane_1024x768_60fps_125MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_1024x768_60fps_125MHz), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_720P_1280_720] = ++ {"1280x720-2lane@30", tc358743_mode_720P_1280_720, 1280, 720, ++ 12, (0x3e)<<8|(0x3c), 2, 125, ++ tc358743_setting_YUV422_2lane_30fps_720P_1280_720_125MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_30fps_720P_1280_720_125MHz), ++ MIPI_DT_YUV422, ++ }, ++ [0][tc358743_mode_720P_1280_720] = ++ {"1280x720-2lane@60", tc358743_mode_720P_1280_720, 1280, 720, ++ 12, (0x3e)<<8|(0x3c), 2, 125, ++ tc358743_setting_YUV422_2lane_30fps_720P_1280_720_125MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_2lane_30fps_720P_1280_720_125MHz), ++ MIPI_DT_YUV422, ++ }, ++ [1][tc358743_mode_720P_60_1280_720] = ++ {"1280x720-4lane-133Mhz@30", tc358743_mode_720P_60_1280_720, 1280, 720, ++ 12, 0, 4, 133, ++ tc358743_setting_YUV422_4lane_720P_60fps_1280_720_133Mhz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_720P_60fps_1280_720_133Mhz), ++ MIPI_DT_YUV422 ++ }, ++ [tc358743_60_fps][tc358743_mode_720P_60_1280_720] = ++ {"1280x720-4lane@60", tc358743_mode_720P_60_1280_720, 1280, 720, ++ 12, 0, 4, 133, ++ tc358743_setting_YUV422_4lane_720P_60fps_1280_720_133Mhz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_720P_60fps_1280_720_133Mhz), ++ MIPI_DT_YUV422 ++ }, ++ [1][tc358743_mode_1080P_1920_1080] = ++ {"1920x1080@30", tc358743_mode_1080P_1920_1080, 1920, 1080, ++ 15, 0xa, 4, 300, ++ tc358743_setting_YUV422_4lane_1080P_30fps_1920_1080_300MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_1080P_30fps_1920_1080_300MHz), ++ MIPI_DT_YUV422 ++ }, ++ [tc358743_60_fps][tc358743_mode_1080P_1920_1080] = ++ {"1920x1080@60", tc358743_mode_1080P_1920_1080, 1920, 1080, ++ 15, 0x0b, 4, 300, ++ tc358743_setting_YUV422_4lane_1080P_60fps_1920_1080_300MHz, ++ ARRAY_SIZE(tc358743_setting_YUV422_4lane_1080P_60fps_1920_1080_300MHz), ++ MIPI_DT_YUV422 ++ }, ++}; ++ ++static int tc358743_probe(struct i2c_client *adapter, ++ const struct i2c_device_id *device_id); ++static int tc358743_remove(struct i2c_client *client); ++ ++static const struct i2c_device_id tc358743_id[] = { ++ {"tc358743_mipi", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, tc358743_id); ++ ++static struct i2c_driver tc358743_i2c_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "tc358743_mipi", ++ }, ++ .probe = tc358743_probe, ++ .remove = tc358743_remove, ++ .id_table = tc358743_id, ++}; ++ ++struct _reg_size ++{ ++ u16 startaddr, endaddr; ++ int size; ++}; ++ ++static const struct _reg_size tc358743_read_reg_size[] = ++{ ++ {0x0000, 0x005a, 2}, ++ {0x0140, 0x0150, 4}, ++ {0x0204, 0x0238, 4}, ++ {0x040c, 0x0418, 4}, ++ {0x044c, 0x0454, 4}, ++ {0x0500, 0x0518, 4}, ++ {0x0600, 0x06cc, 4}, ++ {0x7000, 0x7100, 2}, ++ {0x8500, 0x8bff, 1}, ++ {0x8c00, 0x8fff, 4}, ++ {0x9000, 0x90ff, 1}, ++ {0x9100, 0x92ff, 1}, ++ {0, 0, 0}, ++}; ++ ++int get_reg_size(u16 reg, int len) ++{ ++ const struct _reg_size *p = tc358743_read_reg_size; ++ int size; ++ ++#if 0 //later #ifndef DEBUG ++ if (len) ++ return len; ++#endif ++ while (p->size) { ++ if ((p->startaddr <= reg) && (reg <= p->endaddr)) { ++ size = p->size; ++ if (len && (size != len)) { ++ pr_err("%s:reg len error:reg=%x %d instead of %d\n", ++ __func__, reg, len, size); ++ return 0; ++ } ++ if (reg % size) { ++ pr_err("%s:cannot read from the middle of a register, reg(%x) size(%d)\n", ++ __func__, reg, size); ++ return 0; ++ } ++ return size; ++ } ++ p++; ++ } ++ pr_err("%s:reg=%x size is not defined\n",__func__, reg); ++ return 0; ++} ++ ++static s32 tc358743_read_reg(struct sensor_data *sensor, u16 reg, void *rxbuf) ++{ ++ struct i2c_client *client = sensor->i2c_client; ++ struct i2c_msg msgs[2]; ++ u8 txbuf[2]; ++ int ret; ++ int size = get_reg_size(reg, 0); ++ ++ if (!size) ++ return -EINVAL; ++ ++ txbuf[0] = reg >> 8; ++ txbuf[1] = reg & 0xff; ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = 2; ++ msgs[0].buf = txbuf; ++ ++ msgs[1].addr = client->addr; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = size; ++ msgs[1].buf = rxbuf; ++ ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if (ret < 0) { ++ pr_err("%s:reg=%x ret=%d\n", __func__, reg, ret); ++ return ret; ++ } ++// pr_debug("%s:reg=%x,val=%x\n", __func__, reg, ((char *)rxbuf)[0]); ++ return 0; ++} ++ ++static s32 tc358743_read_reg_val(struct sensor_data *sensor, u16 reg) ++{ ++ u32 val = 0; ++ tc358743_read_reg(sensor, reg, &val); ++ return val; ++} ++ ++static s32 tc358743_read_reg_val16(struct sensor_data *sensor, u16 reg) ++{ ++#if 0 ++ struct i2c_client *client = sensor->i2c_client; ++ struct i2c_msg msgs[3]; ++ u8 txbuf[4]; ++ u8 rxbuf1[4]; ++ u8 rxbuf2[4]; ++ int ret; ++ int size = get_reg_size(reg, 0); ++ ++ if (size != 1) ++ return -EINVAL; ++ ++ txbuf[0] = reg >> 8; ++ txbuf[1] = reg & 0xff; ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = 2; ++ msgs[0].buf = txbuf; ++ ++ msgs[1].addr = client->addr; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = size; ++ msgs[1].buf = rxbuf1; ++ ++ msgs[2].addr = client->addr; ++ msgs[2].flags = I2C_M_RD; ++ msgs[2].len = size; ++ msgs[2].buf = rxbuf2; ++ ++ ret = i2c_transfer(client->adapter, msgs, 3); ++ if (ret < 0) { ++ pr_err("%s:reg=%x ret=%d\n", __func__, reg, ret); ++ return ret; ++ } ++// pr_debug("%s:reg=%x,val=%x\n", __func__, reg, ((char *)rxbuf)[0]); ++ return rxbuf1[0] | (rxbuf2[0] << 8); ++#else ++ u32 val1 = 0; ++ u32 val2 = 0; ++ tc358743_read_reg(sensor, reg, &val1); ++ tc358743_read_reg(sensor, reg+1, &val2); ++ return val1 | (val2 << 8); ++ ++#endif ++} ++ ++static s32 tc358743_write_reg(struct sensor_data *sensor, u16 reg, u32 val, int len) ++{ ++ int ret; ++ int i = 0; ++ u32 data = val; ++ u8 au8Buf[6] = {0}; ++ int size = get_reg_size(reg, len); ++ ++ if (!size) ++ return -EINVAL; ++ ++ au8Buf[i++] = reg >> 8; ++ au8Buf[i++] = reg & 0xff; ++ while (size-- > 0) { ++ au8Buf[i++] = (u8)data; ++ data >>= 8; ++ } ++ ++ ret = i2c_master_send(sensor->i2c_client, au8Buf, i); ++ if (ret < 0) { ++ pr_err("%s:write reg error(%d):reg=%x,val=%x\n", ++ __func__, ret, reg, val); ++ return ret; ++ } ++ if ((reg < 0x7000) || (reg >= 0x7100)) { ++ if (0) pr_debug("%s:reg=%x,val=%x 8543=%02x\n", __func__, reg, val, tc358743_read_reg_val(sensor, 0x8543)); ++ } ++ return 0; ++} ++ ++static void tc358743_software_reset(struct sensor_data *sensor) ++{ ++ int freq = sensor->mclk / 10000; ++ tc358743_write_reg(sensor, 0x7080, 0, 2); ++ tc358743_write_reg(sensor, 0x0002, 0x0f00, 2); ++ msleep(100); ++ tc358743_write_reg(sensor, 0x0002, 0x0000, 2); ++ msleep(1000); ++ tc358743_write_reg(sensor, 0x0004, 0x0004, 2); /* autoinc */ ++ pr_debug("%s:freq=%d\n", __func__, freq); ++ tc358743_write_reg(sensor, 0x8540, freq, 1); ++ tc358743_write_reg(sensor, 0x8541, freq >> 8, 1); ++} ++ ++static void tc358743_enable_edid(struct sensor_data *sensor) ++{ ++ pr_debug("Activate EDID\n"); ++ // EDID ++ tc358743_write_reg(sensor, 0x85c7, 0x01, 1); // EDID MODE REGISTER: nternal EDID-RAM & DDC2B mode ++ tc358743_write_reg(sensor, 0x85ca, 0x00, 1); ++ tc358743_write_reg(sensor, 0x85cb, 0x01, 1); // 0x85cb:0x85ca - EDID Length = 0x01:00 (Size = 0x100 = 256) ++ tc358743_write_reg(sensor, 0x8543, 0x36, 1); // DDC CONTROL: DDC_ACK output terminal H active, DDC5V_active detect delay 200ms ++ tc358743_write_reg(sensor, 0x854a, 0x01, 1); // mark init done ++ if (0) pr_debug("%s: c7=%02x ca=%02x cb=%02x 43=%02x 4a=%02x\n", __func__, ++ tc358743_read_reg_val(sensor, 0x85c7), ++ tc358743_read_reg_val(sensor, 0x85ca), ++ tc358743_read_reg_val(sensor, 0x85cb), ++ tc358743_read_reg_val(sensor, 0x8543), ++ tc358743_read_reg_val(sensor, 0x854a)); ++} ++ ++static int tc358743_write_edid(struct sensor_data *sensor, const u8 *edid, int len) ++{ ++ int i = 0, off = 0; ++ u8 au8Buf[16+2] = {0}; ++ int size = 0; ++ int checksum = 0; ++ u16 reg; ++ ++ reg = 0x8C00; ++ off = 0; ++ size = ARRAY_SIZE(au8Buf) - 2; ++ pr_debug("Write EDID: %d (%d)\n", len, size); ++ while (len > 0) { ++ i = 0; ++ au8Buf[i++] = (reg >> 8) & 0xff; ++ au8Buf[i++] = reg & 0xff; ++ if (size > len) ++ size = len; ++ while (i < size + 2) { ++ u8 byte = edid[off++]; ++ if ((off & 0x7f) == 0) { ++ checksum &= 0xff; ++ if (checksum != byte) { ++ pr_info("%schecksum=%x, byte=%x\n", __func__, checksum, byte); ++ byte = checksum; ++ checksum = 0; ++ } ++ } else { ++ checksum -= byte; ++ } ++ au8Buf[i++] = byte; ++ } ++ ++ if (i2c_master_send(sensor->i2c_client, au8Buf, i) < 0) { ++ pr_err("%s:write reg error:reg=%x,val=%x\n", ++ __func__, reg, off); ++ return -1; ++ } ++ len -= (u8)size; ++ reg += (u16)size; ++ } ++ tc358743_enable_edid(sensor); ++ return 0; ++} ++ ++static s32 power_control(struct tc_data *td, int on) ++{ ++ struct sensor_data *sensor = &td->sensor; ++ int i; ++ int ret = 0; ++ ++ pr_debug("%s: %d\n", __func__, on); ++ if (sensor->on != on) { ++ if (on) { ++ for (i = 0; i < REGULATOR_CNT; i++) { ++ if (td->regulator[i]) { ++ ret = regulator_enable(td->regulator[i]); ++ if (ret) { ++ pr_err("%s:regulator_enable failed(%d)\n", ++ __func__, ret); ++ on = 0; /* power all off */ ++ break; ++ } ++ } ++ } ++ } ++ tc_standby(td, on ? 0 : 1); ++ sensor->on = on; ++ if (!on) { ++ for (i = REGULATOR_CNT - 1; i >= 0; i--) { ++ if (td->regulator[i]) ++ regulator_disable(td->regulator[i]); ++ } ++ } ++ } ++ return ret; ++} ++ ++static int tc358743_toggle_hpd(struct sensor_data *sensor, int active) ++{ ++ int ret = 0; ++ if (active) { ++ ret += tc358743_write_reg(sensor, 0x8544, 0x00, 1); ++ mdelay(500); ++ ret += tc358743_write_reg(sensor, 0x8544, 0x10, 1); ++ } else { ++ ret += tc358743_write_reg(sensor, 0x8544, 0x10, 1); ++ mdelay(500); ++ ret += tc358743_write_reg(sensor, 0x8544, 0x00, 1); ++ } ++ return ret; ++} ++ ++static int get_format_index(enum tc358743_frame_rate frame_rate, enum tc358743_mode mode) ++{ ++ int ifmt; ++ u32 flags = tc358743_mode_info_data[frame_rate][mode].flags; ++ ++ for (ifmt = 0; ifmt < ARRAY_SIZE(tc358743_formats); ifmt++) { ++ if (flags == tc358743_formats[ifmt].flags) ++ return ifmt; ++ } ++ return -1; ++} ++ ++static int get_pixelformat(enum tc358743_frame_rate frame_rate, enum tc358743_mode mode) ++{ ++ int ifmt = get_format_index(frame_rate, mode); ++ ++ if (ifmt < 0) { ++ pr_debug("%s: unsupported format, %d, %d\n", __func__, frame_rate, mode); ++ return 0; ++ } ++ pr_debug("%s: %s (%x, %x)\n", __func__, ++ tc358743_formats[ifmt].description, ++ tc358743_formats[ifmt].pixelformat, ++ tc358743_formats[ifmt].flags); ++ return tc358743_formats[ifmt].pixelformat; ++} ++ ++int set_frame_rate_mode(struct tc_data *td, ++ enum tc358743_frame_rate frame_rate, enum tc358743_mode mode) ++{ ++ struct sensor_data *sensor = &td->sensor; ++ const struct reg_value *pModeSetting = NULL; ++ s32 i = 0; ++ s32 iModeSettingArySize = 0; ++ register u32 RepeateLines = 0; ++ register int RepeateTimes = 0; ++ register u32 Delay_ms = 0; ++ register u16 RegAddr = 0; ++ register u32 Mask = 0; ++ register u32 Val = 0; ++ u8 Length; ++ int retval = 0; ++ ++ pModeSetting = ++ tc358743_mode_info_data[frame_rate][mode].init_data_ptr; ++ iModeSettingArySize = ++ tc358743_mode_info_data[frame_rate][mode].init_data_size; ++ ++ sensor->pix.pixelformat = get_pixelformat(frame_rate, mode); ++ sensor->pix.width = ++ tc358743_mode_info_data[frame_rate][mode].width; ++ sensor->pix.height = ++ tc358743_mode_info_data[frame_rate][mode].height; ++ pr_debug("%s: Set %d regs from %p for frs %d mode %d with width %d height %d\n", __func__, ++ iModeSettingArySize, ++ pModeSetting, ++ frame_rate, ++ mode, ++ sensor->pix.width, ++ sensor->pix.height); ++ for (i = 0; i < iModeSettingArySize; ++i) { ++ pModeSetting = tc358743_mode_info_data[frame_rate][mode].init_data_ptr + i; ++ ++ Delay_ms = pModeSetting->u32Delay_ms & (0xffff); ++ RegAddr = pModeSetting->u16RegAddr; ++ Val = pModeSetting->u32Val; ++ Mask = pModeSetting->u32Mask; ++ Length = pModeSetting->u8Length; ++ if (Mask) { ++ u32 RegVal = 0; ++ ++ retval = tc358743_read_reg(sensor, RegAddr, &RegVal); ++ if (retval < 0) { ++ pr_err("%s: read failed, reg=0x%x\n", __func__, RegAddr); ++ return retval; ++ } ++ RegVal &= ~(u8)Mask; ++ Val &= Mask; ++ Val |= RegVal; ++ } ++ ++ retval = tc358743_write_reg(sensor, RegAddr, Val, Length); ++ if (retval < 0) { ++ pr_err("%s: write failed, reg=0x%x\n", __func__, RegAddr); ++ return retval; ++ } ++ if (Delay_ms) ++ msleep(Delay_ms); ++ ++ if (0 != ((pModeSetting->u32Delay_ms>>16) & (0xff))) { ++ if (!RepeateTimes) { ++ RepeateTimes = (pModeSetting->u32Delay_ms>>16) & (0xff); ++ RepeateLines = (pModeSetting->u32Delay_ms>>24) & (0xff); ++ } ++ if (--RepeateTimes > 0) { ++ i -= RepeateLines; ++ } ++ } ++ } ++ tc358743_enable_edid(sensor); ++ if (!td->edid_initialized) { ++ retval = tc358743_write_edid(sensor, cHDMIEDID, ARRAY_SIZE(cHDMIEDID)); ++ if (retval) ++ pr_err("%s: Fail to write EDID(%d) to tc35874!\n", __func__, retval); ++ else ++ td->edid_initialized = 1; ++ } ++ ++ return retval; ++} ++ ++void mipi_csi2_swreset(struct mipi_csi2_info *info); ++#include "../../../../mxc/mipi/mxc_mipi_csi2.h" ++ ++int mipi_reset(void *mipi_csi2_info, ++ enum tc358743_frame_rate frame_rate, ++ enum tc358743_mode mode) ++{ ++ int lanes = tc358743_mode_info_data[frame_rate][mode].lanes; ++ ++ if (!lanes) ++ lanes = 4; ++ ++ pr_debug("%s: mipi_csi2_info:\n" ++ "mipi_en: %d\n" ++ "datatype: %d\n" ++ "dphy_clk: %p\n" ++ "pixel_clk: %p\n" ++ "mipi_csi2_base:%p\n" ++ "pdev: %p\n" ++ , __func__, ++ ((struct mipi_csi2_info *)mipi_csi2_info)->mipi_en, ++ ((struct mipi_csi2_info *)mipi_csi2_info)->datatype, ++ ((struct mipi_csi2_info *)mipi_csi2_info)->dphy_clk, ++ ((struct mipi_csi2_info *)mipi_csi2_info)->pixel_clk, ++ ((struct mipi_csi2_info *)mipi_csi2_info)->mipi_csi2_base, ++ ((struct mipi_csi2_info *)mipi_csi2_info)->pdev ++ ); ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ mipi_csi2_disable(mipi_csi2_info); ++ msleep(1); ++ } ++ 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; ++ } ++ lanes = mipi_csi2_set_lanes(mipi_csi2_info, lanes); ++ pr_debug("Now Using %d lanes\n", lanes); ++ ++ mipi_csi2_reset(mipi_csi2_info); ++ mipi_csi2_set_datatype(mipi_csi2_info, tc358743_mode_info_data[frame_rate][mode].flags); ++ return 0; ++} ++ ++int mipi_wait(void *mipi_csi2_info) ++{ ++ unsigned i = 0; ++ unsigned j; ++ u32 mipi_reg; ++ u32 mipi_reg_test[10]; ++ ++ /* wait for mipi sensor ready */ ++ for (;;) { ++ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); ++ mipi_reg_test[i++] = mipi_reg; ++ if (mipi_reg != 0x200) ++ break; ++ if (i >= 10) { ++ pr_err("mipi csi2 can not receive sensor clk!\n"); ++ return -1; ++ } ++ msleep(10); ++ } ++ ++ for (j = 0; j < i; j++) { ++ pr_debug("%d mipi csi2 dphy status %x\n", j, mipi_reg_test[j]); ++ } ++ ++ i = 0; ++ ++ /* wait for mipi stable */ ++ for (;;) { ++ mipi_reg = mipi_csi2_get_error1(mipi_csi2_info); ++ mipi_reg_test[i++] = mipi_reg; ++ if (!mipi_reg) ++ break; ++ if (i >= 10) { ++ pr_err("mipi csi2 can not reveive data correctly!\n"); ++ return -1; ++ } ++ msleep(10); ++ } ++ ++ for (j = 0; j < i; j++) { ++ pr_debug("%d mipi csi2 err1 %x\n", j, mipi_reg_test[j]); ++ } ++ return 0; ++} ++ ++static int tc358743_init_mode(struct tc_data *td, ++ enum tc358743_frame_rate frame_rate, ++ enum tc358743_mode mode) ++{ ++ struct sensor_data *sensor = &td->sensor; ++ int retval = 0; ++ void *mipi_csi2_info; ++ ++ pr_debug("%s rate: %d mode: %d\n", __func__, frame_rate, mode); ++ if ((mode >= tc358743_mode_MAX || mode < 0) ++ && (mode != tc358743_mode_INIT)) { ++ pr_debug("%s Wrong tc358743 mode detected! %d. Set mode 0\n", __func__, mode); ++ mode = 0; ++ } ++ /* initial mipi dphy */ ++ tc358743_toggle_hpd(sensor, 0); ++ tc358743_software_reset(sensor); ++ ++ mipi_csi2_info = mipi_csi2_get_info(); ++ pr_debug("%s rate: %d mode: %d, info %p\n", __func__, frame_rate, mode, mipi_csi2_info); ++ ++ if (!mipi_csi2_info) { ++ pr_err("Fail to get mipi_csi2_info!\n"); ++ return -1; ++ } ++ retval = mipi_reset(mipi_csi2_info, frame_rate, tc358743_mode_INIT); ++ if (retval) ++ return retval; ++ retval = set_frame_rate_mode(td, frame_rate, tc358743_mode_INIT); ++ if (retval) ++ return retval; ++ retval = mipi_wait(mipi_csi2_info); ++ ++ if (mode != tc358743_mode_INIT) { ++ tc358743_software_reset(sensor); ++ retval = mipi_reset(mipi_csi2_info, frame_rate, mode); ++ if (retval) ++ return retval; ++ retval = set_frame_rate_mode(td, frame_rate, mode); ++ if (retval) ++ return retval; ++ retval = mipi_wait(mipi_csi2_info); ++ } ++ if (td->hpd_active) ++ tc358743_toggle_hpd(sensor, td->hpd_active); ++ return retval; ++} ++ ++static int tc358743_minit(struct tc_data *td) ++{ ++ struct sensor_data *sensor = &td->sensor; ++ int ret; ++ enum tc358743_frame_rate frame_rate = tc358743_60_fps; ++ u32 tgt_fps = sensor->streamcap.timeperframe.denominator / ++ sensor->streamcap.timeperframe.numerator; ++ ++ if (tgt_fps == 60) ++ frame_rate = tc358743_60_fps; ++ else if (tgt_fps == 30) ++ frame_rate = tc358743_30_fps; ++ ++ pr_debug("%s: capture mode: %d fps: %d\n", __func__, ++ sensor->streamcap.capturemode, tgt_fps); ++ ++ ret = tc358743_init_mode(td, frame_rate, sensor->streamcap.capturemode); ++ if (ret) ++ pr_err("%s: Fail to init tc35874!\n", __func__); ++ return ret; ++} ++ ++static int tc358743_reset(struct tc_data *td) ++{ ++ int loop = 0; ++ int ret; ++ ++ det_work_enable(td, 0); ++ for (;;) { ++ pr_debug("%s: RESET\n", __func__); ++ power_control(td, 0); ++ mdelay(100); ++ power_control(td, 1); ++ mdelay(1000); ++ ++ ret = tc358743_minit(td); ++ if (!ret) ++ break; ++ if (loop++ >= 3) { ++ pr_err("%s:failed(%d)\n", __func__, ret); ++ break; ++ } ++ } ++ det_work_enable(td, 1); ++ return ret; ++} ++ ++/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ ++ ++static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) ++{ ++ struct tc_data *td = s->priv; ++ struct sensor_data *sensor = &td->sensor; ++ ++ pr_debug("%s\n", __func__); ++ ++ memset(p, 0, sizeof(*p)); ++ p->u.bt656.clock_curr = TC358743_XCLK_MIN; //sensor->mclk; ++ pr_debug("%s: clock_curr=mclk=%d\n", __func__, sensor->mclk); ++ p->if_type = V4L2_IF_TYPE_BT656; ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; ++ p->u.bt656.clock_min = TC358743_XCLK_MIN; ++ p->u.bt656.clock_max = TC358743_XCLK_MAX; ++ ++ 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 tc_data *td = s->priv; ++ int ret; ++ ++ mutex_lock(&td->access_lock); ++ if (on && !td->mode) { ++ ret = tc358743_reset(td); ++ } else { ++ ret = power_control(td, on); ++ } ++ mutex_unlock(&td->access_lock); ++ return ret; ++} ++ ++/*! ++ * 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 tc_data *td = s->priv; ++ struct sensor_data *sensor = &td->sensor; ++ struct v4l2_captureparm *cparm = &a->parm.capture; ++ int ret = 0; ++ ++ pr_debug("%s type: %x\n", __func__, a->type); ++ 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; ++ cparm->extendedmode = sensor->streamcap.extendedmode; ++ 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; ++ } ++ pr_debug("%s done %d\n", __func__, ret); ++ 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 tc_data *td = s->priv; ++ struct sensor_data *sensor = &td->sensor; ++ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; ++ u32 tgt_fps; /* target frames per secound */ ++ enum tc358743_frame_rate frame_rate = tc358743_60_fps, frame_rate_now = tc358743_60_fps; ++ enum tc358743_mode mode; ++ int ret = 0; ++ ++ pr_debug("%s\n", __func__); ++ mutex_lock(&td->access_lock); ++ det_work_enable(td, 0); ++ /* Make sure power on */ ++ power_control(td, 1); ++ ++ 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 == 60) ++ frame_rate = tc358743_60_fps; ++ else if (tgt_fps == 30) ++ frame_rate = tc358743_30_fps; ++ else { ++ pr_err(" The camera frame rate is not supported!\n"); ++ ret = -EINVAL; ++ break; ++ } ++ ++ if ((u32)a->parm.capture.capturemode >= tc358743_mode_MAX) { ++ a->parm.capture.capturemode = 0; ++ pr_debug("%s: Force mode: %d \n", __func__, ++ (u32)a->parm.capture.capturemode); ++ } ++ ++ tgt_fps = sensor->streamcap.timeperframe.denominator / ++ sensor->streamcap.timeperframe.numerator; ++ ++ if (tgt_fps == 60) ++ frame_rate_now = tc358743_60_fps; ++ else if (tgt_fps == 30) ++ frame_rate_now = tc358743_30_fps; ++ ++ mode = td->mode; ++ if (IS_COLORBAR(mode)) { ++ mode = (u32)a->parm.capture.capturemode; ++ } else { ++ a->parm.capture.capturemode = mode; ++ frame_rate = td->fps; ++ timeperframe->denominator = (frame_rate == tc358743_60_fps) ? 60 : 30; ++ timeperframe->numerator = 1; ++ } ++ ++ if (frame_rate_now != frame_rate || ++ sensor->streamcap.capturemode != mode || ++ sensor->streamcap.extendedmode != (u32)a->parm.capture.extendedmode) { ++ ++ if (mode != tc358743_mode_INIT) { ++ sensor->streamcap.capturemode = mode; ++ sensor->streamcap.timeperframe = *timeperframe; ++ sensor->streamcap.extendedmode = ++ (u32)a->parm.capture.extendedmode; ++ pr_debug("%s: capture mode: %d\n", __func__, ++ mode); ++ ret = tc358743_init_mode(td, frame_rate, mode); ++ } else { ++ a->parm.capture.capturemode = sensor->streamcap.capturemode; ++ *timeperframe = sensor->streamcap.timeperframe; ++ a->parm.capture.extendedmode = sensor->streamcap.extendedmode; ++ } ++ } else { ++ pr_debug("%s: Keep current settings\n", __func__); ++ } ++ 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; ++ } ++ ++ det_work_enable(td, 1); ++ mutex_unlock(&td->access_lock); ++ return ret; ++} ++ ++/*! ++ * 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) ++{ ++ struct tc_data *td = s->priv; ++ struct sensor_data *sensor = &td->sensor; ++ int ret = 0; ++ ++ pr_debug("%s\n", __func__); ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ vc->value = sensor->brightness; ++ break; ++ case V4L2_CID_HUE: ++ vc->value = sensor->hue; ++ break; ++ case V4L2_CID_CONTRAST: ++ vc->value = sensor->contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ vc->value = sensor->saturation; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ vc->value = sensor->red; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ vc->value = sensor->blue; ++ break; ++ case V4L2_CID_EXPOSURE: ++ vc->value = sensor->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 tc358743: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) ++{ ++ struct tc_data *td = s->priv; ++ enum tc358743_mode query_mode= fsize->index; ++ enum tc358743_mode mode = td->mode; ++ ++ if (IS_COLORBAR(mode)) { ++ if (query_mode > MAX_COLORBAR) ++ return -EINVAL; ++ mode = query_mode; ++ } else { ++ if (query_mode) ++ return -EINVAL; ++ } ++ pr_debug("%s, mode: %d\n", __func__, mode); ++ ++ fsize->pixel_format = get_pixelformat(0, mode); ++ fsize->discrete.width = ++ tc358743_mode_info_data[0][mode].width; ++ fsize->discrete.height = ++ tc358743_mode_info_data[0][mode].height; ++ pr_debug("%s %d:%d format: %x\n", __func__, fsize->discrete.width, fsize->discrete.height, fsize->pixel_format); ++ 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, ++ "tc358743_mipi"); ++ ++ 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) ++{ ++ pr_debug("%s\n", __func__); ++ 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) ++{ ++ struct tc_data *td = s->priv; ++ struct sensor_data *sensor = &td->sensor; ++ int index = fmt->index; ++ ++ if (!index) ++ index = sensor->streamcap.capturemode; ++ pr_debug("%s, INDEX: %d\n", __func__, index); ++ if (index >= tc358743_mode_MAX) ++ return -EINVAL; ++ ++ fmt->pixelformat = get_pixelformat(0, index); ++ ++ pr_debug("%s: format: %x\n", __func__, fmt->pixelformat); ++ return 0; ++} ++ ++static int ioctl_try_fmt_cap(struct v4l2_int_device *s, ++ struct v4l2_format *f) ++{ ++ struct tc_data *td = s->priv; ++ struct sensor_data *sensor = &td->sensor; ++ u32 tgt_fps; /* target frames per secound */ ++ enum tc358743_frame_rate frame_rate; ++// enum image_size isize; ++ int ret = 0; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ int mode; ++ ++ pr_debug("%s\n", __func__); ++ ++ mutex_lock(&td->access_lock); ++ tgt_fps = sensor->streamcap.timeperframe.denominator / ++ sensor->streamcap.timeperframe.numerator; ++ ++ if (tgt_fps == 60) { ++ frame_rate = tc358743_60_fps; ++ } else if (tgt_fps == 30) { ++ frame_rate = tc358743_30_fps; ++ } else { ++ pr_debug("%s: %d fps (%d,%d) is not supported\n", __func__, tgt_fps, sensor->streamcap.timeperframe.denominator,sensor->streamcap.timeperframe.numerator); ++ ret = -EINVAL; ++ goto out; ++ } ++ mode = sensor->streamcap.capturemode; ++ sensor->pix.pixelformat = get_pixelformat(frame_rate, mode); ++ sensor->pix.width = pix->width = tc358743_mode_info_data[frame_rate][mode].width; ++ sensor->pix.height = pix->height = tc358743_mode_info_data[frame_rate][mode].height; ++ pr_debug("%s: %dx%d\n", __func__, sensor->pix.width, sensor->pix.height); ++ ++ pix->pixelformat = sensor->pix.pixelformat; ++ pix->field = V4L2_FIELD_NONE; ++ pix->bytesperline = pix->width * 4; ++ pix->sizeimage = pix->bytesperline * pix->height; ++ pix->priv = 0; ++ ++ switch (pix->pixelformat) { ++ case V4L2_PIX_FMT_UYVY: ++ default: ++ pix->colorspace = V4L2_COLORSPACE_SRGB; ++ break; ++ } ++ ++ { ++ pr_debug("SYS_STATUS: 0x%x\n", tc358743_read_reg_val(sensor, 0x8520)); ++ pr_debug("VI_STATUS0: 0x%x\n", tc358743_read_reg_val(sensor, 0x8521)); ++ pr_debug("VI_STATUS1: 0x%x\n", tc358743_read_reg_val(sensor, 0x8522)); ++ pr_debug("VI_STATUS2: 0x%x\n", tc358743_read_reg_val(sensor, 0x8525)); ++ pr_debug("VI_STATUS3: 0x%x\n", tc358743_read_reg_val(sensor, 0x8528)); ++ pr_debug("%s %d:%d format: %x\n", __func__, pix->width, pix->height, pix->pixelformat); ++ } ++out: ++ mutex_unlock(&td->access_lock); ++ 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 tc_data *td = s->priv; ++ struct sensor_data *sensor = &td->sensor; ++ int mode = sensor->streamcap.capturemode; ++ ++ sensor->pix.pixelformat = get_pixelformat(0, mode); ++ sensor->pix.width = tc358743_mode_info_data[0][mode].width; ++ sensor->pix.height = tc358743_mode_info_data[0][mode].height; ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ f->fmt.pix = sensor->pix; ++ pr_debug("%s: %dx%d\n", __func__, sensor->pix.width, sensor->pix.height); ++ break; ++ ++ case V4L2_BUF_TYPE_SENSOR: ++ pr_debug("%s: left=%d, top=%d, %dx%d\n", __func__, ++ sensor->spix.left, sensor->spix.top, ++ sensor->spix.swidth, sensor->spix.sheight); ++ f->fmt.spix = sensor->spix; ++ break; ++ ++ case V4L2_BUF_TYPE_PRIVATE: ++ pr_debug("%s: private\n", __func__); ++ break; ++ ++ default: ++ f->fmt.pix = sensor->pix; ++ pr_debug("%s: type=%d, %dx%d\n", __func__, f->type, sensor->pix.width, sensor->pix.height); ++ break; ++ } ++ 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 tc_data *td = s->priv; ++ ++ if (td->det_changed) { ++ mutex_lock(&td->access_lock); ++ td->det_changed = 0; ++ pr_debug("%s\n", __func__); ++ tc358743_minit(td); ++ mutex_unlock(&td->access_lock); ++ } ++ pr_debug("%s\n", __func__); ++ return 0; ++} ++ ++/*! ++ * 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 tc358743_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_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_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_g_chip_ident_num, ++ (v4l2_int_ioctl_func *) ioctl_g_chip_ident}, ++}; ++ ++static struct v4l2_int_slave tc358743_slave = { ++ .ioctls = tc358743_ioctl_desc, ++ .num_ioctls = ARRAY_SIZE(tc358743_ioctl_desc), ++}; ++ ++static struct v4l2_int_device tc358743_int_device = { ++ .module = THIS_MODULE, ++ .name = "tc358743", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &tc358743_slave, ++ }, ++}; ++ ++ ++#ifdef CONFIG_TC358743_AUDIO ++struct imx_ssi { ++ struct platform_device *ac97_dev; ++ ++ struct snd_soc_dai *imx_ac97; ++ struct clk *clk; ++ void __iomem *base; ++ int irq; ++ int fiq_enable; ++ unsigned int offset; ++ ++ unsigned int flags; ++ ++ void (*ac97_reset) (struct snd_ac97 *ac97); ++ void (*ac97_warm_reset)(struct snd_ac97 *ac97); ++ ++ struct imx_pcm_dma_params dma_params_rx; ++ struct imx_pcm_dma_params dma_params_tx; ++ ++ int enabled; ++ ++ struct platform_device *soc_platform_pdev; ++ struct platform_device *soc_platform_pdev_fiq; ++}; ++#define SSI_SCR 0x10 ++#define SSI_SRCR 0x20 ++#define SSI_STCCR 0x24 ++#define SSI_SRCCR 0x28 ++#define SSI_SCR_I2S_MODE_NORM (0 << 5) ++#define SSI_SCR_I2S_MODE_MSTR (1 << 5) ++#define SSI_SCR_I2S_MODE_SLAVE (2 << 5) ++#define SSI_I2S_MODE_MASK (3 << 5) ++#define SSI_SCR_SYN (1 << 4) ++#define SSI_SRCR_RSHFD (1 << 4) ++#define SSI_SRCR_RSCKP (1 << 3) ++#define SSI_SRCR_RFSI (1 << 2) ++#define SSI_SRCR_REFS (1 << 0) ++#define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13) ++#define SSI_STCCR_WL_MASK (0xf << 13) ++#define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13) ++#define SSI_SRCCR_WL_MASK (0xf << 13) ++/* Audio setup */ ++ ++static int imxpac_tc358743_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ int ret; ++ ++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_IF | ++ SND_SOC_DAIFMT_CBM_CFM); ++ if (ret) { ++ pr_err("%s: failed set cpu dai format\n", __func__); ++ return ret; ++ } ++ ++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM); ++ if (ret) { ++ pr_err("%s: failed set codec dai format\n", __func__); ++ return ret; ++ } ++ ++ ret = snd_soc_dai_set_sysclk(codec_dai, 0, ++ CODEC_CLOCK, SND_SOC_CLOCK_OUT); ++ if (ret) { ++ pr_err("%s: failed setting codec sysclk\n", __func__); ++ return ret; ++ } ++ snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); ++ ++ ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, ++ SND_SOC_CLOCK_IN); ++ if (ret) { ++ pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); ++ return ret; ++ } ++#if 1 ++// clear SSI_SRCR_RXBIT0 and SSI_SRCR_RSHFD in order to push Right-justified MSB data fro ++ { ++ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); ++ u32 scr = 0, srcr = 0, stccr = 0, srccr = 0; ++ ++ pr_debug("%s: base %p\n", __func__, (void *)ssi->base); ++ scr = readl(ssi->base + SSI_SCR); ++ pr_debug("%s: SSI_SCR before: %p\n", __func__, (void *)scr); ++ writel(scr, ssi->base + SSI_SCR); ++ pr_debug("%s: SSI_SCR after: %p\n", __func__, (void *)scr); ++ ++ srcr = readl(ssi->base + SSI_SRCR); ++ pr_debug("%s: SSI_SRCR before: %p\n", __func__, (void *)srcr); ++ writel(srcr, ssi->base + SSI_SRCR); ++ pr_debug("%s: SSI_SRCR after: %p\n", __func__, (void *)srcr); ++ ++ stccr = readl(ssi->base + SSI_STCCR); ++ pr_debug("%s: SSI_STCCR before: %p\n", __func__, (void *)stccr); ++ stccr &= ~SSI_STCCR_WL_MASK; ++ stccr |= SSI_STCCR_WL(16); ++ writel(stccr, ssi->base + SSI_STCCR); ++ pr_debug("%s: SSI_STCCR after: %p\n", __func__, (void *)stccr); ++ ++ srccr = readl(ssi->base + SSI_SRCCR); ++ pr_debug("%s: SSI_SRCCR before: %p\n", __func__, (void *)srccr); ++ srccr &= ~SSI_SRCCR_WL_MASK; ++ srccr |= SSI_SRCCR_WL(16); ++ writel(srccr, ssi->base + SSI_SRCCR); ++ pr_debug("%s: SSI_SRCCR after: %p\n", __func__, (void *)srccr); ++ } ++#endif ++ return 0; ++} ++ ++ ++ ++/* imx_3stack card dapm widgets */ ++static const struct snd_soc_dapm_widget imx_3stack_dapm_widgets_a[] = { ++}; ++ ++ ++ ++static const struct snd_kcontrol_new tc358743_machine_controls_a[] = { ++}; ++ ++/* imx_3stack machine connections to the codec pins */ ++static const struct snd_soc_dapm_route audio_map_a[] = { ++}; ++ ++static int imx_3stack_tc358743_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_codec *codec = rtd->codec; ++ int ret; ++ ++ const struct snd_soc_dapm_widget *imx_3stack_dapm_widgets; ++ int imx_3stack_dapm_widgets_size; ++ const struct snd_kcontrol_new *tc358743_machine_controls; ++ int tc358743_machine_controls_size; ++ const struct snd_soc_dapm_route *audio_map; ++ int audio_map_size; ++ int gpio_num = -1; ++ char *gpio_name; ++ ++ pr_debug("%s started\n", __func__); ++ ++ imx_3stack_dapm_widgets = imx_3stack_dapm_widgets_a; ++ imx_3stack_dapm_widgets_size = ARRAY_SIZE(imx_3stack_dapm_widgets_a); ++ tc358743_machine_controls = tc358743_machine_controls_a; ++ tc358743_machine_controls_size = ARRAY_SIZE(tc358743_machine_controls_a); ++ audio_map = audio_map_a; ++ audio_map_size = ARRAY_SIZE(audio_map_a); ++ gpio_num = -1; //card_a_gpio_num; ++ gpio_name = NULL; ++ ++ ret = snd_soc_add_controls(codec, tc358743_machine_controls, ++ tc358743_machine_controls_size); ++ if (ret) { ++ pr_err("%s: snd_soc_add_controls failed. err = %d\n", __func__, ret); ++ return ret; ++ } ++ /* Add imx_3stack specific widgets */ ++ snd_soc_dapm_new_controls(&codec->dapm, imx_3stack_dapm_widgets, ++ imx_3stack_dapm_widgets_size); ++ ++ /* Set up imx_3stack specific audio path audio_map */ ++ snd_soc_dapm_add_routes(&codec->dapm, audio_map, audio_map_size); ++ snd_soc_dapm_sync(&codec->dapm); ++ return 0; ++} ++ ++ ++static struct snd_soc_ops imxpac_tc358743_snd_ops = { ++ .hw_params = imxpac_tc358743_hw_params, ++}; ++ ++static struct snd_soc_dai_link imxpac_tc358743_dai = { ++ .name = "tc358743", ++ .stream_name = "TC358743", ++ .codec_dai_name = "tc358743-hifi", ++ .platform_name = "imx-pcm-audio.2", ++ .codec_name = "tc358743_mipi.1-000f", ++ .cpu_dai_name = "imx-ssi.2", ++ .init = imx_3stack_tc358743_init, ++ .ops = &imxpac_tc358743_snd_ops, ++}; ++ ++static struct snd_soc_card imxpac_tc358743 = { ++ .name = "cpuimx-audio_hdmi_in", ++ .dai_link = &imxpac_tc358743_dai, ++ .num_links = 1, ++}; ++ ++static int imx_audmux_config(int slave, int master) ++{ ++ unsigned int ptcr, pdcr; ++ slave = slave - 1; ++ master = master - 1; ++ ++ /* SSI0 mastered by port 5 */ ++ ptcr = MXC_AUDMUX_V2_PTCR_SYN | ++ MXC_AUDMUX_V2_PTCR_TFSDIR | ++ MXC_AUDMUX_V2_PTCR_TFSEL(master | 0x8) | ++ MXC_AUDMUX_V2_PTCR_TCLKDIR | ++ MXC_AUDMUX_V2_PTCR_RFSDIR | ++ MXC_AUDMUX_V2_PTCR_RFSEL(master | 0x8) | ++ MXC_AUDMUX_V2_PTCR_RCLKDIR | ++ MXC_AUDMUX_V2_PTCR_RCSEL(master | 0x8) | ++ MXC_AUDMUX_V2_PTCR_TCSEL(master | 0x8); ++ pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(master); ++ mxc_audmux_v2_configure_port(slave, ptcr, pdcr); ++ ++ ptcr = MXC_AUDMUX_V2_PTCR_SYN; ++ pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(master); ++ mxc_audmux_v2_configure_port(master, ptcr, pdcr); ++ return 0; ++} ++ ++static int __devinit imx_tc358743_probe(struct platform_device *pdev) ++{ ++ struct mxc_audio_platform_data *plat = pdev->dev.platform_data; ++ int ret = 0; ++ ++ ++ imx_audmux_config(plat->src_port, plat->ext_port); ++ ++ ret = -EINVAL; ++ if (plat->init && plat->init()) ++ return ret; ++ ++ printk("%s %d %s\n",__func__,__LINE__,pdev->name); ++ return 0; ++} ++ ++static int imx_tc358743_remove(struct platform_device *pdev) ++{ ++ struct mxc_audio_platform_data *plat = pdev->dev.platform_data; ++ ++ if (plat->finit) ++ plat->finit(); ++ ++ return 0; ++} ++ ++static struct platform_driver imx_tc358743_audio1_driver = { ++ .probe = imx_tc358743_probe, ++ .remove = imx_tc358743_remove, ++ .driver = { ++ .name = "imx-tc358743", ++ }, ++}; ++ ++ ++/* Codec setup */ ++static int tc358743_codec_probe(struct snd_soc_codec *codec) ++{ ++ return 0; ++} ++ ++static int tc358743_codec_remove(struct snd_soc_codec *codec) ++{ ++ return 0; ++} ++ ++static int tc358743_codec_suspend(struct snd_soc_codec *codec, pm_message_t state) ++{ ++// tc358743_set_bias_level(codec, SND_SOC_BIAS_OFF); ++ return 0; ++} ++ ++static int tc358743_codec_resume(struct snd_soc_codec *codec) ++{ ++// tc358743_set_bias_level(codec, SND_SOC_BIAS_STANDBY); ++ return 0; ++} ++ ++static int tc358743_set_bias_level(struct snd_soc_codec *codec, ++ enum snd_soc_bias_level level) ++{ ++ return 0; ++} ++ ++static const u8 tc358743_reg[0] = { ++}; ++ ++static struct snd_soc_codec_driver soc_codec_dev_tc358743 = { ++ .set_bias_level = tc358743_set_bias_level, ++ .reg_cache_size = ARRAY_SIZE(tc358743_reg), ++ .reg_word_size = sizeof(u8), ++ .reg_cache_default = tc358743_reg, ++ .probe = tc358743_codec_probe, ++ .remove = tc358743_codec_remove, ++ .suspend = tc358743_codec_suspend, ++ .resume = tc358743_codec_resume, ++}; ++ ++#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 ++#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ ++ SNDRV_PCM_FMTBIT_S24_LE) ++ ++static int tc358743_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ return 0; ++} ++ ++static int tc358743_mute(struct snd_soc_dai *dai, int mute) ++{ ++ return 0; ++} ++ ++static int tc358743_set_dai_sysclk(struct snd_soc_dai *codec_dai, ++ int clk_id, unsigned int freq, int dir) ++{ ++ return 0; ++} ++ ++static int tc358743_set_dai_fmt(struct snd_soc_dai *codec_dai, ++ unsigned int fmt) ++{ ++ return 0; ++} ++ ++static struct snd_soc_dai_ops tc358743_dai_ops = { ++ .hw_params = tc358743_hw_params, ++ .digital_mute = tc358743_mute, ++ .set_sysclk = tc358743_set_dai_sysclk, ++ .set_fmt = tc358743_set_dai_fmt, ++}; ++ ++static struct snd_soc_dai_driver tc358743_dai = { ++ .name = "tc358743-hifi", ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = AIC3X_RATES, ++ .formats = AIC3X_FORMATS,}, ++ .ops = &tc358743_dai_ops, ++ .symmetric_rates = 1, ++}; ++ ++#endif ++ ++struct tc_mode_list { ++ const char *name; ++ enum tc358743_mode mode; ++}; ++ ++static const struct tc_mode_list tc358743_mode_list[] = ++{ ++ {"None", 0}, /* 0 */ ++ {"VGA", tc358743_mode_480P_640_480}, /* 1 */ ++ {"240p/480i", 0}, /* 2 */ ++ {"288p/576i", 0}, /* 3 */ ++ {"W240p/480i", 0}, /* 4 */ ++ {"W288p/576i", 0}, /* 5 */ ++ {"480p", 0}, /* 6 */ ++ {"576p", 0}, /* 7 */ ++ {"W480p", tc358743_mode_480P_720_480}, /* 8 */ ++ {"W576p", 0}, /* 9 */ ++ {"WW480p", 0}, /* 10 */ ++ {"WW576p", 0}, /* 11 */ ++ {"720p", tc358743_mode_720P_60_1280_720}, /* 12 */ ++ {"1035i", 0}, /* 13 */ ++ {"1080i", 0}, /* 14 */ ++ {"1080p", tc358743_mode_1080P_1920_1080}, /* 15 */ ++}; ++ ++static char tc358743_fps_list[tc358743_max_fps+1] = ++{ ++[tc358743_60_fps] = 60, ++[tc358743_30_fps] = 30, ++[tc358743_max_fps] = 0 ++}; ++ ++static int tc358743_audio_list[16] = ++{ ++ 44100, ++ 0, ++ 48000, ++ 32000, ++ 22050, ++ 384000, ++ 24000, ++ 352800, ++ 88200, ++ 768000, ++ 96000, ++ 705600, ++ 176400, ++ 0, ++ 192000, ++ 0 ++}; ++ ++static char str_on[80]; ++static void report_netlink(struct tc_data *td) ++{ ++ struct sensor_data *sensor = &td->sensor; ++ char *envp[2]; ++ envp[0] = &str_on[0]; ++ envp[1] = NULL; ++ sprintf(envp[0], "HDMI RX: %d (%s) %d %d", ++ td->mode, ++ tc358743_mode_info_data[td->fps][td->mode].name, ++ tc358743_fps_list[td->fps], tc358743_audio_list[td->audio]); ++ kobject_uevent_env(&(sensor->i2c_client->dev.kobj), KOBJ_CHANGE, envp); ++ td->det_work_timeout = DET_WORK_TIMEOUT_DEFAULT; ++ pr_debug("%s: HDMI RX (%d) mode: %s fps: %d (%d, %d) audio: %d\n", ++ __func__, td->mode, ++ tc358743_mode_info_data[td->fps][td->mode].name, td->fps, td->bounce, ++ td->det_work_timeout, tc358743_audio_list[td->audio]); ++} ++ ++static void tc_det_worker(struct work_struct *work) ++{ ++ struct tc_data *td = container_of(work, struct tc_data, det_work.work); ++ struct sensor_data *sensor = &td->sensor; ++ int ret; ++ u32 u32val, u852f; ++ enum tc358743_mode mode = tc358743_mode_INIT; ++ ++ ++ if (!td->det_work_enable) ++ return; ++ mutex_lock(&td->access_lock); ++ ++ if (!td->det_work_enable) { ++ goto out2; ++ } ++ u32val = 0; ++ ret = tc358743_read_reg(sensor, 0x8621, &u32val); ++ if (ret >= 0) { ++ if (td->audio != (((unsigned char)u32val) & 0x0f)) { ++ td->audio = ((unsigned char)u32val) & 0x0f; ++ report_netlink(td); ++ } ++ } ++ u852f = 0; ++ ret = tc358743_read_reg(sensor, 0x852f, &u852f); ++ if (ret < 0) { ++ pr_err("%s: Error reading lock\n", __func__); ++ td->det_work_timeout = DET_WORK_TIMEOUT_DEFERRED; ++ goto out; ++ } ++// pr_info("%s: 852f=%x\n", __func__, u32val); ++ if (u852f & TC3587430_HDMI_DETECT) { ++ pr_info("%s: hdmi detect %x\n", __func__, u852f); ++ td->lock = u852f & TC3587430_HDMI_DETECT; ++ u32val = 0; ++ ret = tc358743_read_reg(sensor, 0x8521, &u32val); ++ if (ret < 0) { ++ pr_err("%s: Error reading mode\n", __func__); ++ } ++ pr_info("%s: detect 8521=%x\n", __func__, u32val); ++ u32val &= 0x0f; ++ td->fps = tc358743_60_fps; ++ if (!u32val) { ++ int hsize, vsize; ++ ++ hsize = tc358743_read_reg_val16(sensor, 0x8582); ++ vsize = tc358743_read_reg_val16(sensor, 0x8588); ++ pr_info("%s: detect hsize=%d, vsize=%d\n", __func__, hsize, vsize); ++ if ((hsize == 1024) && (vsize == 768)) ++ mode = tc358743_mode_1024x768; ++ } else { ++ mode = tc358743_mode_list[u32val].mode; ++ if (td->mode != mode) ++ pr_debug("%s: %s detected\n", __func__, tc358743_mode_list[u32val].name); ++ if (u852f >= 0xe) ++ td->fps = ((u852f & 0x0f) > 0xa)? tc358743_60_fps: tc358743_30_fps; ++ } ++ } else { ++ if (td->lock) ++ td->lock = 0; ++ u32val = 0; ++ ret = tc358743_read_reg(sensor, 0x8521, &u32val); ++ if (ret < 0) { ++ pr_err("%s: Error reading mode\n", __func__); ++ } ++// pr_info("%s: 8521=%x\n", __func__, u32val); ++ } ++ if (td->mode != mode) { ++ td->det_work_timeout = DET_WORK_TIMEOUT_DEFAULT; ++ td->bounce = MAX_BOUNCE; ++ pr_debug("%s: HDMI RX (%d != %d) mode: %s fps: %d (%d, %d)\n", ++ __func__, td->mode, mode, ++ tc358743_mode_info_data[td->fps][mode].name, ++ td->fps, td->bounce, td->det_work_timeout); ++ td->mode = mode; ++ sensor->streamcap.capturemode = mode; ++ sensor->spix.swidth = tc358743_mode_info_data[td->fps][mode].width; ++ sensor->spix.sheight = tc358743_mode_info_data[td->fps][mode].height; ++ td->det_changed = 1; ++ } else if (td->bounce) { ++ td->bounce--; ++ td->det_work_timeout = DET_WORK_TIMEOUT_DEFAULT; ++ ++ if (!td->bounce) { ++ u32val = 0; ++ ret = tc358743_read_reg(sensor, 0x8621, &u32val); ++ if (ret >= 0) { ++ td->audio = ((unsigned char)u32val) & 0x0f; ++ report_netlink(td); ++ } ++ if (td->mode) { ++ td->det_work_timeout = DET_WORK_TIMEOUT_DEFERRED; ++ goto out2; ++ } ++ } ++ } else if (td->mode && !td->bounce) { ++ goto out2; ++ } ++out: ++ schedule_delayed_work(&td->det_work, msecs_to_jiffies(td->det_work_timeout)); ++out2: ++ mutex_unlock(&td->access_lock); ++} ++ ++static irqreturn_t tc358743_detect_handler(int irq, void *data) ++{ ++ struct tc_data *td = data; ++ struct sensor_data *sensor = &td->sensor; ++ ++ pr_debug("%s: IRQ %d\n", __func__, sensor->i2c_client->irq); ++ schedule_delayed_work(&td->det_work, msecs_to_jiffies(10)); ++ return IRQ_HANDLED; ++} ++ ++ ++/*! ++ * tc358743 I2C probe function ++ * ++ * @param adapter struct i2c_adapter * ++ * @return Error code indicating success or failure ++ */ ++#define DUMP_LENGTH 256 ++static u16 regoffs = 0; ++ ++static ssize_t tc358743_show_regdump(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct tc_data *td = g_td; ++ struct sensor_data *sensor = &td->sensor; ++ int i, len = 0; ++ int retval; ++ ++ if (!td) ++ return len; ++ mutex_lock(&td->access_lock); ++ for (i=0; iaccess_lock); ++ len += sprintf(buf+len, "\n"); ++ return len; ++} ++ ++static DEVICE_ATTR(regdump, S_IRUGO, tc358743_show_regdump, NULL); ++ ++static ssize_t tc358743_store_regoffs(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ u32 val; ++ int retval; ++ retval = sscanf(buf, "%x", &val); ++ if (1 == retval) ++ regoffs = (u16)val; ++ return count; ++} ++ ++static ssize_t tc358743_show_regoffs(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int len = 0; ++ ++ len += sprintf(buf+len, "0x%04X\n", regoffs); ++ return len; ++} ++ ++static DEVICE_ATTR(regoffs, S_IRUGO|S_IWUSR, tc358743_show_regoffs, tc358743_store_regoffs); ++ ++static ssize_t tc358743_store_hpd(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct tc_data *td = g_td; ++ u32 val; ++ int retval; ++ retval = sscanf(buf, "%d", &val); ++ if (1 == retval) ++ td->hpd_active = (u16)val; ++ return count; ++} ++ ++static ssize_t tc358743_show_hpd(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct tc_data *td = g_td; ++ int len = 0; ++ ++ len += sprintf(buf+len, "%d\n", td->hpd_active); ++ return len; ++} ++ ++static DEVICE_ATTR(hpd, S_IRUGO|S_IWUSR, tc358743_show_hpd, tc358743_store_hpd); ++ ++static ssize_t tc358743_show_hdmirx(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct tc_data *td = g_td; ++ int len = 0; ++ ++ len += sprintf(buf+len, "%d\n", td->mode); ++ return len; ++} ++ ++static DEVICE_ATTR(hdmirx, S_IRUGO, tc358743_show_hdmirx, NULL); ++ ++static ssize_t tc358743_show_fps(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct tc_data *td = g_td; ++ int len = 0; ++ ++ len += sprintf(buf+len, "%d\n", tc358743_fps_list[td->fps]); ++ return len; ++} ++ ++static DEVICE_ATTR(fps, S_IRUGO, tc358743_show_fps, NULL); ++ ++#ifdef CONFIG_TC358743_AUDIO ++static ssize_t tc358743_show_audio(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct tc_data *td = g_td; ++ int len = 0; ++ ++ len += sprintf(buf+len, "%d\n", tc358743_audio_list[td->audio]); ++ return len; ++} ++ ++static DEVICE_ATTR(audio, S_IRUGO, tc358743_show_audio, NULL); ++#endif ++ ++static int tc358743_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ int retval; ++ struct tc_data *td; ++ struct sensor_data *sensor; ++ u8 chip_id_high; ++ u32 u32val; ++ int mode = tc358743_mode_INIT; ++ ++ td = kzalloc(sizeof(*td), GFP_KERNEL); ++ if (!td) ++ return -ENOMEM; ++ td->hpd_active = 1; ++ td->det_work_timeout = DET_WORK_TIMEOUT_DEFAULT; ++ td->audio = 2; ++ mutex_init(&td->access_lock); ++ mutex_lock(&td->access_lock); ++ sensor = &td->sensor; ++ ++ /* request power down pin */ ++ td->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); ++ if (!gpio_is_valid(td->pwn_gpio)) { ++ dev_warn(dev, "no sensor pwdn pin available"); ++ } else { ++ retval = devm_gpio_request_one(dev, td->pwn_gpio, GPIOF_OUT_INIT_HIGH, ++ "tc_mipi_pwdn"); ++ if (retval < 0) { ++ dev_warn(dev, "request of pwn_gpio failed"); ++ return retval; ++ } ++ } ++ /* request reset pin */ ++ td->rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); ++ if (!gpio_is_valid(td->rst_gpio)) { ++ dev_warn(dev, "no sensor reset pin available"); ++ return -EINVAL; ++ } ++ retval = devm_gpio_request_one(dev, td->rst_gpio, GPIOF_OUT_INIT_HIGH, ++ "tc_mipi_reset"); ++ if (retval < 0) { ++ dev_warn(dev, "request of tc_mipi_reset failed"); ++ return retval; ++ } ++ ++ /* Set initial values for the sensor struct. */ ++ sensor->mipi_camera = 1; ++ sensor->virtual_channel = 0; ++ sensor->sensor_clk = devm_clk_get(dev, "csi_mclk"); ++ ++ retval = of_property_read_u32(dev->of_node, "mclk", ++ &(sensor->mclk)); ++ if (retval) { ++ dev_err(dev, "mclk missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk_source", ++ (u32 *) &(sensor->mclk_source)); ++ if (retval) { ++ dev_err(dev, "mclk_source missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "ipu_id", ++ &sensor->ipu_id); ++ if (retval) { ++ dev_err(dev, "ipu_id missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "csi_id", ++ &(sensor->csi)); ++ if (retval) { ++ dev_err(dev, "csi id missing or invalid\n"); ++ return retval; ++ } ++ if ((unsigned)sensor->ipu_id || (unsigned)sensor->csi) { ++ dev_err(dev, "invalid ipu/csi\n"); ++ return -EINVAL; ++ } ++ ++ if (!IS_ERR(sensor->sensor_clk)) ++ clk_prepare_enable(sensor->sensor_clk); ++ ++ sensor->io_init = tc_io_init; ++ sensor->i2c_client = client; ++ sensor->streamcap.capability = V4L2_MODE_HIGHQUALITY | ++ V4L2_CAP_TIMEPERFRAME; ++ sensor->streamcap.capturemode = mode; ++ sensor->streamcap.timeperframe.denominator = DEFAULT_FPS; ++ sensor->streamcap.timeperframe.numerator = 1; ++ ++ sensor->pix.pixelformat = get_pixelformat(0, mode); ++ sensor->pix.width = tc358743_mode_info_data[0][mode].width; ++ sensor->pix.height = tc358743_mode_info_data[0][mode].height; ++ pr_debug("%s: format: %x, capture mode: %d fps: %d width: %d height: %d\n", ++ __func__, sensor->pix.pixelformat, mode, ++ sensor->streamcap.timeperframe.denominator * ++ sensor->streamcap.timeperframe.numerator, ++ sensor->pix.width, ++ sensor->pix.height); ++ ++ tc_regulator_init(td, dev); ++ power_control(td, 1); ++ tc_reset(td); ++ ++ u32val = 0; ++ retval = tc358743_read_reg(sensor, TC358743_CHIP_ID_HIGH_BYTE, &u32val); ++ if (retval < 0) { ++ pr_err("%s:cannot find camera\n", __func__); ++ retval = -ENODEV; ++ goto err4; ++ } ++ chip_id_high = (u8)u32val; ++ ++ tc358743_int_device.priv = td; ++ if (!g_td) ++ g_td = td; ++ ++#ifdef CONFIG_TC358743_AUDIO ++ retval = device_create_file(&client->dev, &dev_attr_audio); ++#endif ++ retval = device_create_file(&client->dev, &dev_attr_fps); ++ retval = device_create_file(&client->dev, &dev_attr_hdmirx); ++ retval = device_create_file(&client->dev, &dev_attr_hpd); ++ retval = device_create_file(&client->dev, &dev_attr_regoffs); ++ retval = device_create_file(&client->dev, &dev_attr_regdump); ++ ++ if (retval) { ++ pr_err("%s: create bin file failed, error=%d\n", ++ __func__, retval); ++ goto err4; ++ } ++ ++#ifdef CONFIG_TC358743_AUDIO ++/* Audio setup */ ++ retval = snd_soc_register_codec(&client->dev, ++ &soc_codec_dev_tc358743, &tc358743_dai, 1); ++ if (retval) { ++ pr_err("%s: register failed, error=%d\n", ++ __func__, retval); ++ goto err4; ++ } ++ ++ retval = platform_driver_register(&imx_tc358743_audio1_driver); ++ if (retval) { ++ pr_err("%s: Platform driver register failed, error=%d\n", ++ __func__, retval); ++ goto err4; ++ } ++ ++ td->snd_device = platform_device_alloc("soc-audio", 5); ++ if (!td->snd_device) { ++ pr_err("%s: Platform device allocation failed, error=%d\n", ++ __func__, retval); ++ goto err4; ++ } ++ ++ platform_set_drvdata(td->snd_device, &imxpac_tc358743); ++ retval = platform_device_add(td->snd_device); ++ ++ if (retval) { ++ pr_err("%s: Platform device add failed, error=%d\n", ++ __func__, retval); ++ platform_device_put(td->snd_device); ++ goto err4; ++ } ++#endif ++ ++#if 1 ++ INIT_DELAYED_WORK(&td->det_work, tc_det_worker); ++ if (sensor->i2c_client->irq) { ++ retval = request_irq(sensor->i2c_client->irq, tc358743_detect_handler, ++ IRQF_SHARED | IRQF_TRIGGER_FALLING, ++ "tc358743_det", td); ++ if (retval < 0) ++ dev_warn(&sensor->i2c_client->dev, ++ "cound not request det irq %d\n", ++ sensor->i2c_client->irq); ++ } ++ ++ schedule_delayed_work(&td->det_work, msecs_to_jiffies(td->det_work_timeout)); ++#endif ++ retval = tc358743_reset(td); ++ if (retval) ++ goto err4; ++ ++ i2c_set_clientdata(client, td); ++ mutex_unlock(&td->access_lock); ++ retval = v4l2_int_device_register(&tc358743_int_device); ++ mutex_lock(&td->access_lock); ++ if (retval) { ++ pr_err("%s: v4l2_int_device_register failed, error=%d\n", ++ __func__, retval); ++ goto err4; ++ } ++ power_control(td, 0); ++ mutex_unlock(&td->access_lock); ++ pr_debug("%s: finished, error=%d\n", __func__, retval); ++ return retval; ++ ++err4: ++ power_control(td, 0); ++ mutex_unlock(&td->access_lock); ++ pr_err("%s: failed, error=%d\n", __func__, retval); ++ if (g_td == td) ++ g_td = NULL; ++ mutex_destroy(&td->access_lock); ++ kfree(td); ++ return retval; ++} ++ ++/*! ++ * tc358743 I2C detach function ++ * ++ * @param client struct i2c_client * ++ * @return Error code indicating success or failure ++ */ ++static int tc358743_remove(struct i2c_client *client) ++{ ++ int i; ++ struct tc_data *td = i2c_get_clientdata(client); ++ struct sensor_data *sensor = &td->sensor; ++ ++ // Stop delayed work ++ cancel_delayed_work_sync(&td->det_work); ++ mutex_lock(&td->access_lock); ++ ++ power_control(td, 0); ++ // Remove IRQ ++ if (sensor->i2c_client->irq) { ++ free_irq(sensor->i2c_client->irq, sensor); ++ } ++ ++#ifdef CONFIG_TC358743_AUDIO ++/* Audio breakdown */ ++ snd_soc_unregister_codec(&client->dev); ++ platform_driver_unregister(&imx_tc358743_audio1_driver); ++ platform_device_unregister(td->snd_device); ++#endif ++ /*Remove sysfs entries*/ ++#ifdef CONFIG_TC358743_AUDIO ++ device_remove_file(&client->dev, &dev_attr_audio); ++#endif ++ device_remove_file(&client->dev, &dev_attr_fps); ++ device_remove_file(&client->dev, &dev_attr_hdmirx); ++ device_remove_file(&client->dev, &dev_attr_hpd); ++ device_remove_file(&client->dev, &dev_attr_regoffs); ++ device_remove_file(&client->dev, &dev_attr_regdump); ++ ++ mutex_unlock(&td->access_lock); ++ v4l2_int_device_unregister(&tc358743_int_device); ++ ++ for (i = REGULATOR_CNT - 1; i >= 0; i--) { ++ if (td->regulator[i]) { ++ regulator_disable(td->regulator[i]); ++ } ++ } ++ mutex_destroy(&td->access_lock); ++ if (g_td == td) ++ g_td = NULL; ++ kfree(td); ++ return 0; ++} ++ ++/*! ++ * tc358743 init function ++ * Called by insmod tc358743_camera.ko. ++ * ++ * @return Error code indicating success or failure ++ */ ++static __init int tc358743_init(void) ++{ ++ int err; ++ ++ err = i2c_add_driver(&tc358743_i2c_driver); ++ if (err != 0) ++ pr_err("%s:driver registration failed, error=%d\n", ++ __func__, err); ++ ++ return err; ++} ++ ++/*! ++ * tc358743 cleanup function ++ * Called on rmmod tc358743_camera.ko ++ * ++ * @return Error code indicating success or failure ++ */ ++static void __exit tc358743_clean(void) ++{ ++ i2c_del_driver(&tc358743_i2c_driver); ++} ++ ++module_init(tc358743_init); ++module_exit(tc358743_clean); ++ ++MODULE_AUTHOR("Panasonic Avionics Corp."); ++MODULE_DESCRIPTION("Toshiba TC358743 HDMI-to-CSI2 Bridge MIPI Input Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0"); ++MODULE_ALIAS("CSI"); +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/capture/tda1997x.c linux-3.14.72/drivers/media/platform/mxc/capture/tda1997x.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/tda1997x.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/tda1997x.c 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,451 @@ ++/* ++ * tda1997x.c -- MXC video capture driver for i.MX boards with ++ * tda1997x HDMI receiver ++ * ++ * Copyright (C) 2013 Gateworks Corporation ++ * ++ * 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 ++ * ++ */ ++ ++/* The tda1997x-core driver manages the i2c interface with the device. ++ * This driver merely calls into that driver for current video parameters ++ * when necessary. The platform data for the core driver contains the ++ * video output bus configuration that configures the video port ++ * mapping between the tda1997x and a i.MX6 CSI parallel bus for 8bit ++ * bt656 with embedded syncs as this is the only video format compatible ++ * between the tda1997x and the i.MX6 CSI. ++ * ++ * see for details ++ */ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "v4l2-int-device.h" ++#include "mxc_v4l2_capture.h" ++ ++/*! ++ * Maintains the information on the current state of the sensor. ++ */ ++struct sensor { ++ struct sensor_data sen; ++ tda1997x_videofmt_t vidfmt; ++} tda1997x_data; ++ ++/*********************************************************************** ++ * mxc_v4l2_capture interface. ++ ***********************************************************************/ ++ ++/*********************************************************************** ++ * 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) ++{ ++ struct sensor *sensor = s->priv; ++ tda1997x_vidout_fmt_t fmt; ++ ++ if (s == NULL) { ++ pr_err(" ERROR!! no slave device set!\n"); ++ return -ENODEV; ++ } ++ ++ if (tda1997x_get_vidout_fmt(&fmt)) ++ return -ENODEV; ++ pr_debug("%s: %dx%d%c@%dfps\n", __func__, fmt.width, fmt.height, ++ fmt.interlaced?'i':'p', fmt.fps); ++ ++ /* 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. */ ++ ++ if (sensor->vidfmt == VIDEOFMT_422_SMP) { /* YCbCr 4:2:2 semi-planar */ ++ p->u.bt656.nobt_vs_inv = 0; ++ p->u.bt656.nobt_hs_inv = 1; ++ p->u.bt656.bt_sync_correct = 1; ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_16BIT; ++ p->u.bt656.clock_curr = -1; /* gated clock mode */ ++ } else if (sensor->vidfmt == VIDEOFMT_422_CCIR) { /* YCbCr 4:2:2 CCIR656 */ ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; ++ p->u.bt656.clock_curr = (fmt.interlaced)?0:1; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * Sets the device power. ++ * ++ * s pointer to the device 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; ++ ++ if (on && !sensor->sen.on) { ++ } else if (!on && sensor->sen.on) { ++ } ++ ++ 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; ++ ++ 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) ++{ ++ 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; ++ tda1997x_vidout_fmt_t fmt; ++ ++ if (tda1997x_get_vidout_fmt(&fmt)) ++ return -ENODEV; ++ ++ pr_debug("%s: %dx%d%c@%dfps\n", __func__, fmt.width, fmt.height, ++ fmt.interlaced?'i':'p', fmt.fps); ++ sensor->sen.pix.height = fmt.height; ++ sensor->sen.pix.width = fmt.width; ++ sensor->sen.streamcap.timeperframe.denominator = fmt.fps; ++ sensor->sen.streamcap.timeperframe.numerator = 1; ++ 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; ++ pr_debug(" Returning format of %s\n", (char*)&f->fmt.pix.pixelformat); ++ break; ++ ++ case V4L2_BUF_TYPE_PRIVATE: { ++ } ++ break; ++ ++ default: ++ f->fmt.pix = sensor->sen.pix; ++ break; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * 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) ++{ ++ struct sensor *sensor = s->priv; ++ tda1997x_vidout_fmt_t fmt; ++ ++ if (fsize->index >= 1) ++ return -EINVAL; ++ ++ if (tda1997x_get_vidout_fmt(&fmt)) ++ return -ENODEV; ++ ++ pr_debug("%s: %dx%d%c@%dfps\n", __func__, fmt.height, fmt.width, ++ fmt.interlaced?'i':'p', fmt.fps); ++ sensor->sen.pix.height = fmt.height; ++ sensor->sen.pix.width = fmt.width; ++ fsize->discrete.width = sensor->sen.pix.width; ++ fsize->discrete.height = sensor->sen.pix.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 sensor *sensor = s->priv; ++ ((struct v4l2_dbg_chip_ident *)id)->match.type = ++ V4L2_CHIP_MATCH_I2C_DRIVER; ++ if (sensor->vidfmt == VIDEOFMT_422_SMP) { /* YCbCr 4:2:2 semi-planar */ ++ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, ++ "tda1997x_decoder_yuv422"); ++ } else ++ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, ++ "tda1997x_decoder_bt656"); ++ ((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_TDA19971; ++ ++ return 0; ++} ++ ++/*! ++ * This structure defines all the ioctls for this module. ++ */ ++static struct v4l2_int_ioctl_desc tda1997x_ioctl_desc[] = { ++ ++/* {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_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_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm}, ++ {vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm}, ++ {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 tda1997x_slave = { ++ .ioctls = tda1997x_ioctl_desc, ++ .num_ioctls = ARRAY_SIZE(tda1997x_ioctl_desc), ++}; ++ ++static struct v4l2_int_device tda1997x_int_device = { ++ .module = THIS_MODULE, ++ .name = "tda1997x-video", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &tda1997x_slave, ++ }, ++}; ++ ++static int tda1997x_video_probe(struct platform_device *pdev) ++{ ++ struct sensor *sens = &tda1997x_data; ++ struct pinctrl *pinctrl; ++ struct device *dev = &pdev->dev; ++ struct regmap *gpr; ++ tda1997x_vidout_fmt_t fmt; ++ int ret; ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ /* pinctrl */ ++ pinctrl = devm_pinctrl_get_select_default(dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(dev, "setup pinctrl failed\n"); ++ return PTR_ERR(pinctrl); ++ } ++ ++ /* Set initial values for the sensor struct. */ ++ memset(sens, 0, sizeof(tda1997x_data)); ++ if (tda1997x_get_vidout_fmt(&fmt)) ++ return -ENODEV; ++ sens->vidfmt = fmt.sensor_vidfmt; ++ sens->sen.streamcap.timeperframe.denominator = 0; ++ sens->sen.streamcap.timeperframe.numerator = 0; ++ sens->sen.pix.width = 0; ++ sens->sen.pix.height = 0; ++ if (sens->vidfmt == VIDEOFMT_422_SMP) ++ sens->sen.pix.pixelformat = IPU_PIX_FMT_GENERIC_16; ++ else ++ sens->sen.pix.pixelformat = V4L2_PIX_FMT_UYVY; ++ sens->sen.on = true; ++ ++ ret = of_property_read_u32(dev->of_node, "csi_id", ++ &(sens->sen.csi)); ++ if (ret) { ++ dev_err(dev, "csi_id invalid\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(dev->of_node, "ipu_id", ++ &(sens->sen.ipu_id)); ++ if (ret) { ++ dev_err(dev, "ipu_id invalid\n"); ++ return ret; ++ } ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ if (of_machine_is_compatible("fsl,imx6q")) { ++ int mask = sens->sen.csi ? (1 << 20) : (1 << 19); ++ ++ regmap_update_bits(gpr, IOMUXC_GPR1, mask, mask); ++ } else if (of_machine_is_compatible("fsl,imx6dl")) { ++ int mask = sens->sen.csi ? (7 << 3) : (7 << 0); ++ int val = sens->sen.csi ? (4 << 3) : (4 << 0); ++ ++ regmap_update_bits(gpr, IOMUXC_GPR13, mask, val); ++ } ++ } else { ++ pr_err("%s: failed to find fsl,imx6q-iomux-gpr regmap\n", ++ __func__); ++ } ++ ++ dev_dbg(dev, "IPU%d_CSI%d\n", sens->sen.ipu_id + 1, sens->sen.csi); ++ dev_dbg(dev, "type is %d (expect %d)\n", ++ tda1997x_int_device.type, v4l2_int_type_slave); ++ dev_dbg(dev, "num ioctls is %d\n", ++ tda1997x_int_device.u.slave->num_ioctls); ++ ++ /* This function attaches this structure to the /dev/video device */ ++ tda1997x_int_device.priv = sens; ++ ret = v4l2_int_device_register(&tda1997x_int_device); ++ ++ return ret; ++} ++ ++static int tda1997x_video_remove(struct platform_device *pdev) ++{ ++ v4l2_int_device_unregister(&tda1997x_int_device); ++ ++ return 0; ++} ++ ++static const struct of_device_id tda1997x_video_driver_ids[] = { ++ { .compatible = "fsl,imx-tda1997x-video", }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver tda1997x_video_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "imx-tda1997x-video", ++ .of_match_table = tda1997x_video_driver_ids, ++ }, ++ .probe = tda1997x_video_probe, ++ .remove = tda1997x_video_remove, ++}; ++module_platform_driver(tda1997x_video_driver); ++ ++MODULE_AUTHOR("Tim Harvey "); ++MODULE_DESCRIPTION("TDA1997X hdmi receiver MXC video capture driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:imx-tda1997x-video"); +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/capture/v4l2-int-device.c linux-3.14.72/drivers/media/platform/mxc/capture/v4l2-int-device.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/v4l2-int-device.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/v4l2-int-device.c 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,165 @@ ++/* ++ * drivers/media/video/v4l2-int-device.c ++ * ++ * V4L2 internal ioctl interface. ++ * ++ * Copyright 2005-2014 Freescale Semiconductor, Inc. ++ * Copyright (C) 2007 Nokia Corporation. ++ * ++ * Contact: Sakari Ailus ++ * ++ * This program is free software; you can 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "v4l2-int-device.h" ++ ++static DEFINE_MUTEX(mutex); ++static LIST_HEAD(int_list); ++ ++void v4l2_int_device_try_attach_all(void) ++{ ++ struct v4l2_int_device *m, *s; ++ ++ list_for_each_entry(m, &int_list, head) { ++ if (m->type != v4l2_int_type_master) ++ continue; ++ ++ list_for_each_entry(s, &int_list, head) { ++ if (s->type != v4l2_int_type_slave) ++ continue; ++ ++ /* Slave is connected? */ ++ if (s->u.slave->master) ++ continue; ++ ++ /* Slave wants to attach to master? */ ++ if (s->u.slave->attach_to[0] != 0 ++ && strncmp(m->name, s->u.slave->attach_to, ++ V4L2NAMESIZE)) ++ continue; ++ ++ if (!try_module_get(m->module)) ++ continue; ++ ++ s->u.slave->master = m; ++ if (m->u.master->attach(s)) { ++ s->u.slave->master = NULL; ++ module_put(m->module); ++ continue; ++ } ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all); ++ ++static int ioctl_sort_cmp(const void *a, const void *b) ++{ ++ const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; ++ ++ if (d1->num > d2->num) ++ return 1; ++ ++ if (d1->num < d2->num) ++ return -1; ++ ++ return 0; ++} ++ ++int v4l2_int_device_register(struct v4l2_int_device *d) ++{ ++ if (d->type == v4l2_int_type_slave) ++ sort(d->u.slave->ioctls, d->u.slave->num_ioctls, ++ sizeof(struct v4l2_int_ioctl_desc), ++ &ioctl_sort_cmp, NULL); ++ mutex_lock(&mutex); ++ list_add(&d->head, &int_list); ++ v4l2_int_device_try_attach_all(); ++ mutex_unlock(&mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(v4l2_int_device_register); ++ ++void v4l2_int_device_unregister(struct v4l2_int_device *d) ++{ ++ mutex_lock(&mutex); ++ list_del(&d->head); ++ if (d->type == v4l2_int_type_slave ++ && d->u.slave->master != NULL) { ++ d->u.slave->master->u.master->detach(d); ++ module_put(d->u.slave->master->module); ++ d->u.slave->master = NULL; ++ } ++ mutex_unlock(&mutex); ++} ++EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); ++ ++/* Adapted from search_extable in extable.c. */ ++static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, ++ v4l2_int_ioctl_func *no_such_ioctl) ++{ ++ const struct v4l2_int_ioctl_desc *first = slave->ioctls; ++ const struct v4l2_int_ioctl_desc *last = ++ first + slave->num_ioctls - 1; ++ ++ while (first <= last) { ++ const struct v4l2_int_ioctl_desc *mid; ++ ++ mid = (last - first) / 2 + first; ++ ++ if (mid->num < cmd) ++ first = mid + 1; ++ else if (mid->num > cmd) ++ last = mid - 1; ++ else ++ return mid->func; ++ } ++ ++ return no_such_ioctl; ++} ++ ++static int no_such_ioctl_0(struct v4l2_int_device *d) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) ++{ ++ return ((v4l2_int_ioctl_func_0 *) ++ find_ioctl(d->u.slave, cmd, ++ (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); ++} ++EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0); ++ ++static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) ++{ ++ return ((v4l2_int_ioctl_func_1 *) ++ find_ioctl(d->u.slave, cmd, ++ (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); ++} ++EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1); ++ ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/capture/v4l2-int-device.h linux-3.14.72/drivers/media/platform/mxc/capture/v4l2-int-device.h +--- linux-3.14.72.orig/drivers/media/platform/mxc/capture/v4l2-int-device.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/capture/v4l2-int-device.h 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,317 @@ ++/* ++ * include/media/v4l2-int-device.h ++ * ++ * V4L2 internal ioctl interface. ++ * ++ * Copyright 2005-2014 Freescale Semiconductor, Inc. ++ * Copyright (C) 2007 Nokia Corporation. ++ * ++ * Contact: Sakari Ailus ++ * ++ * This program is free software; you can 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#ifndef V4L2_INT_DEVICE_H ++#define V4L2_INT_DEVICE_H ++ ++#include ++ ++#define V4L2NAMESIZE 32 ++ ++/* ++ * ++ * The internal V4L2 device interface core. ++ * ++ */ ++ ++enum v4l2_int_type { ++ v4l2_int_type_master = 1, ++ v4l2_int_type_slave ++}; ++ ++struct module; ++ ++struct v4l2_int_device; ++ ++struct v4l2_int_master { ++ int (*attach)(struct v4l2_int_device *slave); ++ void (*detach)(struct v4l2_int_device *slave); ++}; ++ ++typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); ++typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); ++typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); ++ ++struct v4l2_int_ioctl_desc { ++ int num; ++ v4l2_int_ioctl_func *func; ++}; ++ ++struct v4l2_int_slave { ++ /* Don't touch master. */ ++ struct v4l2_int_device *master; ++ ++ char attach_to[V4L2NAMESIZE]; ++ ++ int num_ioctls; ++ struct v4l2_int_ioctl_desc *ioctls; ++}; ++ ++struct v4l2_int_device { ++ /* Don't touch head. */ ++ struct list_head head; ++ ++ struct module *module; ++ ++ char name[V4L2NAMESIZE]; ++ ++ enum v4l2_int_type type; ++ union { ++ struct v4l2_int_master *master; ++ struct v4l2_int_slave *slave; ++ } u; ++ ++ void *priv; ++}; ++ ++void v4l2_int_device_try_attach_all(void); ++ ++int v4l2_int_device_register(struct v4l2_int_device *d); ++void v4l2_int_device_unregister(struct v4l2_int_device *d); ++ ++int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); ++int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); ++ ++/* ++ * ++ * Types and definitions for IOCTL commands. ++ * ++ */ ++ ++enum v4l2_power { ++ V4L2_POWER_OFF = 0, ++ V4L2_POWER_ON, ++ V4L2_POWER_STANDBY, ++}; ++ ++/* Slave interface type. */ ++enum v4l2_if_type { ++ /* ++ * Parallel 8-, 10- or 12-bit interface, used by for example ++ * on certain image sensors. ++ */ ++ V4L2_IF_TYPE_BT656, ++ V4L2_IF_TYPE_BT1120_PROGRESSIVE_DDR, ++ V4L2_IF_TYPE_BT1120_PROGRESSIVE_SDR, ++ V4L2_IF_TYPE_BT1120_INTERLACED_DDR, ++ V4L2_IF_TYPE_BT1120_INTERLACED_SDR, ++ V4L2_IF_TYPE_BT656_PROGRESSIVE, ++ V4L2_IF_TYPE_BT656_INTERLACED ++}; ++ ++enum v4l2_if_type_bt656_mode { ++ /* ++ * Modes without Bt synchronisation codes. Separate ++ * synchronisation signal lines are used. ++ */ ++ V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT, ++ V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT, ++ V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT, ++ /* ++ * Use Bt synchronisation codes. The vertical and horizontal ++ * synchronisation is done based on synchronisation codes. ++ */ ++ V4L2_IF_TYPE_BT656_MODE_BT_8BIT, ++ V4L2_IF_TYPE_BT656_MODE_BT_10BIT, ++}; ++ ++struct v4l2_if_type_bt656 { ++ /* ++ * 0: Frame begins when vsync is high. ++ * 1: Frame begins when vsync changes from low to high. ++ */ ++ unsigned frame_start_on_rising_vs:1; ++ /* Use Bt synchronisation codes for sync correction. */ ++ unsigned bt_sync_correct:1; ++ /* Swap every two adjacent image data elements. */ ++ unsigned swap:1; ++ /* Inverted latch clock polarity from slave. */ ++ unsigned latch_clk_inv:1; ++ /* Hs polarity. 0 is active high, 1 active low. */ ++ unsigned nobt_hs_inv:1; ++ /* Vs polarity. 0 is active high, 1 active low. */ ++ unsigned nobt_vs_inv:1; ++ enum v4l2_if_type_bt656_mode mode; ++ /* Minimum accepted bus clock for slave (in Hz). */ ++ u32 clock_min; ++ /* Maximum accepted bus clock for slave. */ ++ u32 clock_max; ++ /* ++ * Current wish of the slave. May only change in response to ++ * ioctls that affect image capture. ++ */ ++ u32 clock_curr; ++}; ++ ++struct v4l2_ifparm { ++ enum v4l2_if_type if_type; ++ union { ++ struct v4l2_if_type_bt656 bt656; ++ } u; ++}; ++ ++/* IOCTL command numbers. */ ++enum v4l2_int_ioctl_num { ++ /* ++ * ++ * "Proper" V4L ioctls, as in struct video_device. ++ * ++ */ ++ vidioc_int_enum_fmt_cap_num = 1, ++ vidioc_int_g_fmt_cap_num, ++ vidioc_int_s_fmt_cap_num, ++ vidioc_int_try_fmt_cap_num, ++ vidioc_int_queryctrl_num, ++ vidioc_int_g_ctrl_num, ++ vidioc_int_s_ctrl_num, ++ vidioc_int_cropcap_num, ++ vidioc_int_g_crop_num, ++ vidioc_int_s_crop_num, ++ vidioc_int_g_parm_num, ++ vidioc_int_s_parm_num, ++ vidioc_int_querystd_num, ++ vidioc_int_s_std_num, ++ vidioc_int_s_video_routing_num, ++ vidioc_int_send_command_num, ++ ++ /* ++ * ++ * Strictly internal ioctls. ++ * ++ */ ++ /* Initialise the device when slave attaches to the master. */ ++ vidioc_int_dev_init_num = 1000, ++ /* Delinitialise the device at slave detach. */ ++ vidioc_int_dev_exit_num, ++ /* Set device power state. */ ++ vidioc_int_s_power_num, ++ /* ++ * Get slave private data, e.g. platform-specific slave ++ * configuration used by the master. ++ */ ++ vidioc_int_g_priv_num, ++ /* Get slave interface parameters. */ ++ vidioc_int_g_ifparm_num, ++ /* Does the slave need to be reset after VIDIOC_DQBUF? */ ++ vidioc_int_g_needs_reset_num, ++ vidioc_int_enum_framesizes_num, ++ vidioc_int_enum_frameintervals_num, ++ ++ /* ++ * ++ * VIDIOC_INT_* ioctls. ++ * ++ */ ++ /* VIDIOC_INT_RESET */ ++ vidioc_int_reset_num, ++ /* VIDIOC_INT_INIT */ ++ vidioc_int_init_num, ++ /* VIDIOC_DBG_G_CHIP_IDENT */ ++ vidioc_int_g_chip_ident_num, ++ ++ /* ++ * ++ * Start of private ioctls. ++ * ++ */ ++ vidioc_int_priv_start_num = 2000, ++}; ++ ++/* ++ * ++ * IOCTL wrapper functions for better type checking. ++ * ++ */ ++ ++#define V4L2_INT_WRAPPER_0(name) \ ++ static inline int vidioc_int_##name(struct v4l2_int_device *d) \ ++ { \ ++ return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \ ++ } \ ++ \ ++ static inline struct v4l2_int_ioctl_desc \ ++ vidioc_int_##name##_cb(int (*func) \ ++ (struct v4l2_int_device *)) \ ++ { \ ++ struct v4l2_int_ioctl_desc desc; \ ++ \ ++ desc.num = vidioc_int_##name##_num; \ ++ desc.func = (v4l2_int_ioctl_func *)func; \ ++ \ ++ return desc; \ ++ } ++ ++#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \ ++ static inline int vidioc_int_##name(struct v4l2_int_device *d, \ ++ arg_type asterisk arg) \ ++ { \ ++ return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ ++ (void *)(unsigned long)arg); \ ++ } \ ++ \ ++ static inline struct v4l2_int_ioctl_desc \ ++ vidioc_int_##name##_cb(int (*func) \ ++ (struct v4l2_int_device *, \ ++ arg_type asterisk)) \ ++ { \ ++ struct v4l2_int_ioctl_desc desc; \ ++ \ ++ desc.num = vidioc_int_##name##_num; \ ++ desc.func = (v4l2_int_ioctl_func *)func; \ ++ \ ++ return desc; \ ++ } ++ ++V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *); ++V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *); ++V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *); ++V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *); ++V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *); ++V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *); ++V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *); ++V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *); ++V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *); ++V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *); ++V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *); ++V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); ++V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *); ++V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *); ++V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *); ++V4L2_INT_WRAPPER_1(send_command, struct v4l2_send_command_control, *); ++ ++V4L2_INT_WRAPPER_0(dev_init); ++V4L2_INT_WRAPPER_0(dev_exit); ++V4L2_INT_WRAPPER_1(s_power, enum v4l2_power, /*dummy arg*/); ++V4L2_INT_WRAPPER_1(g_priv, void, *); ++V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); ++V4L2_INT_WRAPPER_1(g_needs_reset, void, *); ++V4L2_INT_WRAPPER_1(enum_framesizes, struct v4l2_frmsizeenum, *); ++V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *); ++ ++V4L2_INT_WRAPPER_0(reset); ++V4L2_INT_WRAPPER_0(init); ++V4L2_INT_WRAPPER_1(g_chip_ident, int, *); ++ ++#endif +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/output/Kconfig linux-3.14.72/drivers/media/platform/mxc/output/Kconfig +--- linux-3.14.72.orig/drivers/media/platform/mxc/output/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/output/Kconfig 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,16 @@ ++config VIDEO_MXC_IPU_OUTPUT ++ tristate "IPU v4l2 output support" ++ depends on VIDEO_MXC_OUTPUT && MXC_IPU ++ ---help--- ++ This is the video4linux2 driver for IPU post processing video output. ++ ++config VIDEO_MXC_PXP_V4L2 ++ tristate "MXC PxP V4L2 driver" ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ select VIDEOBUF_DMA_CONTIG ++ ---help--- ++ This is a video4linux driver for the Freescale PxP ++ (Pixel Pipeline). This module supports output overlay of ++ the MXC framebuffer on a video stream. ++ ++ To compile this driver as a module, choose M here. +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/output/Makefile linux-3.14.72/drivers/media/platform/mxc/output/Makefile +--- linux-3.14.72.orig/drivers/media/platform/mxc/output/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/output/Makefile 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc_vout.o ++obj-$(CONFIG_VIDEO_MXC_PXP_V4L2) += mxc_pxp_v4l2.o +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c linux-3.14.72/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,1338 @@ ++/* ++ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++/* ++ * Based on STMP378X PxP driver ++ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "mxc_pxp_v4l2.h" ++ ++#define PXP_DRIVER_NAME "pxp-v4l2" ++#define PXP_DRIVER_MAJOR 2 ++#define PXP_DRIVER_MINOR 0 ++ ++#define PXP_DEF_BUFS 2 ++#define PXP_MIN_PIX 8 ++ ++#define V4L2_OUTPUT_TYPE_INTERNAL 4 ++ ++static int video_nr = -1; /* -1 ==> auto assign */ ++static struct pxp_data_format pxp_s0_formats[] = { ++ { ++ .name = "24-bit RGB", ++ .bpp = 4, ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, { ++ .name = "16-bit RGB 5:6:5", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, { ++ .name = "16-bit RGB 5:5:5", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_RGB555, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, { ++ .name = "YUV 4:2:0 Planar", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, { ++ .name = "YUV 4:2:2 Planar", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_YUV422P, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, { ++ .name = "UYVY", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, { ++ .name = "YUYV", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, { ++ .name = "YUV32", ++ .bpp = 4, ++ .fourcc = V4L2_PIX_FMT_YUV32, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++}; ++ ++static unsigned int v4l2_fmt_to_pxp_fmt(u32 v4l2_pix_fmt) ++{ ++ u32 pxp_fmt = 0; ++ ++ if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB24) ++ pxp_fmt = PXP_PIX_FMT_RGB24; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB565) ++ pxp_fmt = PXP_PIX_FMT_RGB565; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555) ++ pxp_fmt = PXP_PIX_FMT_RGB555; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555) ++ pxp_fmt = PXP_PIX_FMT_RGB555; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV420) ++ pxp_fmt = PXP_PIX_FMT_YUV420P; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV422P) ++ pxp_fmt = PXP_PIX_FMT_YUV422P; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_UYVY) ++ pxp_fmt = PXP_PIX_FMT_UYVY; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV32) ++ pxp_fmt = PXP_PIX_FMT_VUY444; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUYV) ++ pxp_fmt = PXP_PIX_FMT_YUYV; ++ ++ return pxp_fmt; ++} ++struct v4l2_queryctrl pxp_controls[] = { ++ { ++ .id = V4L2_CID_HFLIP, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .name = "Horizontal Flip", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_VFLIP, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .name = "Vertical Flip", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Rotation", ++ .minimum = 0, ++ .maximum = 270, ++ .step = 90, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE + 1, ++ .name = "Background Color", ++ .minimum = 0, ++ .maximum = 0xFFFFFF, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE + 2, ++ .name = "Set S0 Chromakey", ++ .minimum = -1, ++ .maximum = 0xFFFFFF, ++ .step = 1, ++ .default_value = -1, ++ .flags = 0, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE + 3, ++ .name = "YUV Colorspace", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ }, ++}; ++ ++static void free_dma_buf(struct pxps *pxp, struct dma_mem *buf) ++{ ++ dma_free_coherent(&pxp->pdev->dev, buf->size, buf->vaddr, buf->paddr); ++ dev_dbg(&pxp->pdev->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 pxps *pxp, struct dma_mem *buf) ++{ ++ ++ buf->vaddr = dma_alloc_coherent(&pxp->pdev->dev, buf->size, &buf->paddr, ++ GFP_DMA | GFP_KERNEL); ++ if (!buf->vaddr) { ++ dev_err(&pxp->pdev->dev, ++ "cannot get dma buf size:0x%x\n", buf->size); ++ return -ENOMEM; ++ } ++ dev_dbg(&pxp->pdev->dev, ++ "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr); ++ return 0; ++} ++ ++/* callback function */ ++static void video_dma_done(void *arg) ++{ ++ struct pxp_tx_desc *tx_desc = to_tx_desc(arg); ++ struct dma_chan *chan = tx_desc->txd.chan; ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ struct pxps *pxp = pxp_chan->client; ++ struct videobuf_buffer *vb; ++ ++ dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", ++ tx_desc->txd.cookie, ++ pxp->active ? sg_dma_address(&pxp->active->sg[0]) : 0); ++ ++ spin_lock(&pxp->lock); ++ if (pxp->active) { ++ vb = &pxp->active->vb; ++ ++ list_del_init(&vb->queue); ++ vb->state = VIDEOBUF_DONE; ++ do_gettimeofday(&vb->ts); ++ vb->field_count++; ++ wake_up(&vb->done); ++ } ++ ++ if (list_empty(&pxp->outq)) { ++ pxp->active = NULL; ++ spin_unlock(&pxp->lock); ++ ++ return; ++ } ++ ++ pxp->active = list_entry(pxp->outq.next, ++ struct pxp_buffer, vb.queue); ++ pxp->active->vb.state = VIDEOBUF_ACTIVE; ++ spin_unlock(&pxp->lock); ++} ++ ++static int acquire_dma_channel(struct pxps *pxp) ++{ ++ dma_cap_mask_t mask; ++ struct dma_chan *chan; ++ struct pxp_channel **pchan = &pxp->pxp_channel[0]; ++ ++ if (*pchan) { ++ struct videobuf_buffer *vb, *_vb; ++ dma_release_channel(&(*pchan)->dma_chan); ++ *pchan = NULL; ++ pxp->active = NULL; ++ list_for_each_entry_safe(vb, _vb, &pxp->outq, queue) { ++ list_del_init(&vb->queue); ++ vb->state = VIDEOBUF_ERROR; ++ wake_up(&vb->done); ++ } ++ } ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ dma_cap_set(DMA_PRIVATE, mask); ++ chan = dma_request_channel(mask, NULL, NULL); ++ if (!chan) ++ return -EBUSY; ++ ++ *pchan = to_pxp_channel(chan); ++ (*pchan)->client = pxp; ++ ++ return 0; ++} ++ ++static int _get_fbinfo(struct fb_info **fbi) ++{ ++ int i; ++ for (i = 0; i < num_registered_fb; i++) { ++ char *idstr = registered_fb[i]->fix.id; ++ if (strncmp(idstr, "mxs", 3) == 0) { ++ *fbi = registered_fb[i]; ++ return 0; ++ } ++ } ++ ++ return -ENODEV; ++} ++ ++static int pxp_set_fbinfo(struct pxps *pxp) ++{ ++ struct v4l2_framebuffer *fb = &pxp->fb; ++ int err; ++ ++ err = _get_fbinfo(&pxp->fbi); ++ if (err) ++ return err; ++ ++ fb->fmt.width = pxp->fbi->var.xres; ++ fb->fmt.height = pxp->fbi->var.yres; ++ pxp->pxp_conf.out_param.stride = pxp->fbi->var.xres; ++ if (pxp->fbi->var.bits_per_pixel == 16) ++ fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565; ++ else ++ fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24; ++ ++ fb->base = (void *)pxp->fbi->fix.smem_start; ++ ++ return 0; ++} ++ ++static int _get_cur_fb_blank(struct pxps *pxp) ++{ ++ struct fb_info *fbi; ++ mm_segment_t old_fs; ++ int err = 0; ++ ++ err = _get_fbinfo(&fbi); ++ if (err) ++ return err; ++ ++ if (fbi->fbops->fb_ioctl) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK, ++ (unsigned int)(&pxp->fb_blank)); ++ set_fs(old_fs); ++ } ++ ++ return err; ++} ++ ++static int pxp_show_buf(struct pxps *pxp, unsigned long paddr) ++{ ++ struct fb_info *fbi = pxp->fbi; ++ int ret = -EINVAL; ++ ++ if (paddr == 0) { ++ dev_err(&pxp->pdev->dev, "Invalid paddr\n"); ++ return ret; ++ } ++ ++ console_lock(); ++ fbi->fix.smem_start = paddr; ++ ret = fb_pan_display(fbi, &fbi->var); ++ console_unlock(); ++ ++ return ret; ++} ++ ++static int set_fb_blank(int blank) ++{ ++ struct fb_info *fbi; ++ int err = 0; ++ ++ err = _get_fbinfo(&fbi); ++ if (err) ++ return err; ++ ++ console_lock(); ++ fb_blank(fbi, blank); ++ console_unlock(); ++ ++ return err; ++} ++ ++static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc) ++{ ++ ++ if (vc->id == V4L2_CID_HFLIP) { ++ pxp->pxp_conf.proc_data.hflip = vc->value; ++ } else if (vc->id == V4L2_CID_VFLIP) { ++ pxp->pxp_conf.proc_data.vflip = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE) { ++ if (vc->value % 90) ++ return -ERANGE; ++ pxp->pxp_conf.proc_data.rotate = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) { ++ pxp->pxp_conf.proc_data.bgcolor = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) { ++ pxp->pxp_conf.s0_param.color_key = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) { ++ pxp->pxp_conf.proc_data.yuv = vc->value; ++ } ++ ++ return 0; ++} ++ ++static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc) ++{ ++ if (vc->id == V4L2_CID_HFLIP) ++ vc->value = pxp->pxp_conf.proc_data.hflip; ++ else if (vc->id == V4L2_CID_VFLIP) ++ vc->value = pxp->pxp_conf.proc_data.vflip; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE) ++ vc->value = pxp->pxp_conf.proc_data.rotate; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) ++ vc->value = pxp->pxp_conf.proc_data.bgcolor; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) ++ vc->value = pxp->pxp_conf.s0_param.color_key; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) ++ vc->value = pxp->pxp_conf.proc_data.yuv; ++ ++ return 0; ++} ++ ++static int pxp_enumoutput(struct file *file, void *fh, ++ struct v4l2_output *o) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ if ((o->index < 0) || (o->index > 1)) ++ return -EINVAL; ++ ++ memset(o, 0, sizeof(struct v4l2_output)); ++ if (o->index == 0) { ++ strcpy(o->name, "PxP Display Output"); ++ pxp->output = 0; ++ } else { ++ strcpy(o->name, "PxP Virtual Output"); ++ pxp->output = 1; ++ } ++ o->type = V4L2_OUTPUT_TYPE_INTERNAL; ++ o->std = 0; ++ o->reserved[0] = pxp->outbuf.paddr; ++ ++ return 0; ++} ++ ++static int pxp_g_output(struct file *file, void *fh, ++ unsigned int *i) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ *i = pxp->output; ++ ++ return 0; ++} ++ ++static int pxp_s_output(struct file *file, void *fh, ++ unsigned int i) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_pix_format *fmt = &pxp->fb.fmt; ++ u32 size; ++ int ret, bpp; ++ ++ if ((i < 0) || (i > 1)) ++ return -EINVAL; ++ ++ /* Output buffer is same format as fbdev */ ++ if (fmt->pixelformat == V4L2_PIX_FMT_RGB24 || ++ fmt->pixelformat == V4L2_PIX_FMT_YUV32) ++ bpp = 4; ++ else ++ bpp = 2; ++ ++ size = fmt->width * fmt->height * bpp; ++ if (size > pxp->outbuf.size) { ++ if (pxp->outbuf.vaddr) ++ free_dma_buf(pxp, &pxp->outbuf); ++ pxp->outbuf.size = size; ++ ret = alloc_dma_buf(pxp, &pxp->outbuf); ++ if (ret < 0) ++ return ret; ++ } ++ memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size); ++ ++ pxp->pxp_conf.out_param.width = fmt->width; ++ pxp->pxp_conf.out_param.height = fmt->height; ++ if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) ++ pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB24; ++ else ++ pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB565; ++ ++ return 0; ++} ++ ++static int pxp_enum_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_fmtdesc *fmt) ++{ ++ enum v4l2_buf_type type = fmt->type; ++ int index = fmt->index; ++ ++ if ((fmt->index < 0) || (fmt->index >= ARRAY_SIZE(pxp_s0_formats))) ++ return -EINVAL; ++ ++ memset(fmt, 0, sizeof(struct v4l2_fmtdesc)); ++ fmt->index = index; ++ fmt->type = type; ++ fmt->pixelformat = pxp_s0_formats[index].fourcc; ++ strcpy(fmt->description, pxp_s0_formats[index].name); ++ ++ return 0; ++} ++ ++static int pxp_g_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct v4l2_pix_format *pf = &f->fmt.pix; ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct pxp_data_format *fmt = pxp->s0_fmt; ++ ++ pf->width = pxp->pxp_conf.s0_param.width; ++ pf->height = pxp->pxp_conf.s0_param.height; ++ pf->pixelformat = fmt->fourcc; ++ pf->field = V4L2_FIELD_NONE; ++ pf->bytesperline = fmt->bpp * pf->width; ++ pf->sizeimage = pf->bytesperline * pf->height; ++ pf->colorspace = fmt->colorspace; ++ pf->priv = 0; ++ ++ return 0; ++} ++ ++static struct pxp_data_format *pxp_get_format(struct v4l2_format *f) ++{ ++ struct pxp_data_format *fmt; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) { ++ fmt = &pxp_s0_formats[i]; ++ if (fmt->fourcc == f->fmt.pix.pixelformat) ++ break; ++ } ++ ++ if (i == ARRAY_SIZE(pxp_s0_formats)) ++ return NULL; ++ ++ return &pxp_s0_formats[i]; ++} ++ ++static int pxp_try_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ int w = f->fmt.pix.width; ++ int h = f->fmt.pix.height; ++ struct pxp_data_format *fmt = pxp_get_format(f); ++ ++ if (!fmt) ++ return -EINVAL; ++ ++ w = min(w, 2040); ++ w = max(w, 8); ++ h = min(h, 2040); ++ h = max(h, 8); ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix.width = w; ++ f->fmt.pix.height = h; ++ f->fmt.pix.pixelformat = fmt->fourcc; ++ ++ return 0; ++} ++ ++static int pxp_s_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_pix_format *pf = &f->fmt.pix; ++ int ret; ++ ++ ret = acquire_dma_channel(pxp); ++ if (ret < 0) ++ return ret; ++ ++ ret = pxp_try_fmt_video_output(file, fh, f); ++ if (ret == 0) { ++ pxp->s0_fmt = pxp_get_format(f); ++ pxp->pxp_conf.s0_param.pixel_fmt = ++ v4l2_fmt_to_pxp_fmt(pxp->s0_fmt->fourcc); ++ pxp->pxp_conf.s0_param.width = pf->width; ++ pxp->pxp_conf.s0_param.height = pf->height; ++ } ++ ++ ++ return ret; ++} ++ ++static int pxp_g_fmt_output_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_window *wf = &f->fmt.win; ++ ++ memset(wf, 0, sizeof(struct v4l2_window)); ++ wf->chromakey = pxp->s1_chromakey; ++ wf->global_alpha = pxp->global_alpha; ++ wf->field = V4L2_FIELD_NONE; ++ wf->clips = NULL; ++ wf->clipcount = 0; ++ wf->bitmap = NULL; ++ wf->w.left = pxp->pxp_conf.proc_data.srect.left; ++ wf->w.top = pxp->pxp_conf.proc_data.srect.top; ++ wf->w.width = pxp->pxp_conf.proc_data.srect.width; ++ wf->w.height = pxp->pxp_conf.proc_data.srect.height; ++ ++ return 0; ++} ++ ++static int pxp_try_fmt_output_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_window *wf = &f->fmt.win; ++ struct v4l2_rect srect; ++ u32 s1_chromakey = wf->chromakey; ++ u8 global_alpha = wf->global_alpha; ++ ++ memcpy(&srect, &(wf->w), sizeof(struct v4l2_rect)); ++ ++ pxp_g_fmt_output_overlay(file, fh, f); ++ ++ wf->chromakey = s1_chromakey; ++ wf->global_alpha = global_alpha; ++ ++ /* Constrain parameters to the input buffer */ ++ wf->w.left = srect.left; ++ wf->w.top = srect.top; ++ wf->w.width = min(srect.width, ++ ((__u32)pxp->pxp_conf.s0_param.width - wf->w.left)); ++ wf->w.height = min(srect.height, ++ ((__u32)pxp->pxp_conf.s0_param.height - wf->w.top)); ++ ++ return 0; ++} ++ ++static int pxp_s_fmt_output_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_window *wf = &f->fmt.win; ++ int ret = pxp_try_fmt_output_overlay(file, fh, f); ++ ++ if (ret == 0) { ++ pxp->global_alpha = wf->global_alpha; ++ pxp->s1_chromakey = wf->chromakey; ++ pxp->pxp_conf.proc_data.srect.left = wf->w.left; ++ pxp->pxp_conf.proc_data.srect.top = wf->w.top; ++ pxp->pxp_conf.proc_data.srect.width = wf->w.width; ++ pxp->pxp_conf.proc_data.srect.height = wf->w.height; ++ pxp->pxp_conf.ol_param[0].global_alpha = pxp->global_alpha; ++ pxp->pxp_conf.ol_param[0].color_key = pxp->s1_chromakey; ++ pxp->pxp_conf.ol_param[0].color_key_enable = ++ pxp->s1_chromakey_state; ++ } ++ ++ return ret; ++} ++ ++static int pxp_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *r) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ return videobuf_reqbufs(&pxp->s0_vbq, r); ++} ++ ++static int pxp_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *b) ++{ ++ int ret; ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ ret = videobuf_querybuf(&pxp->s0_vbq, b); ++ if (!ret) { ++ struct videobuf_buffer *vb = pxp->s0_vbq.bufs[b->index]; ++ if (b->flags & V4L2_BUF_FLAG_MAPPED) ++ b->m.offset = videobuf_to_dma_contig(vb); ++ } ++ ++ return ret; ++} ++ ++static int pxp_qbuf(struct file *file, void *priv, ++ struct v4l2_buffer *b) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ return videobuf_qbuf(&pxp->s0_vbq, b); ++} ++ ++static int pxp_dqbuf(struct file *file, void *priv, ++ struct v4l2_buffer *b) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK); ++} ++ ++static int pxp_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type t) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret = 0; ++ ++ if (t != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ _get_cur_fb_blank(pxp); ++ set_fb_blank(FB_BLANK_UNBLANK); ++ ++ ret = videobuf_streamon(&pxp->s0_vbq); ++ ++ if (!ret && (pxp->output == 0)) ++ pxp_show_buf(pxp, pxp->outbuf.paddr); ++ ++ return ret; ++} ++ ++static int pxp_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type t) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret = 0; ++ ++ if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT)) ++ return -EINVAL; ++ ++ ret = videobuf_streamoff(&pxp->s0_vbq); ++ ++ pxp_show_buf(pxp, (unsigned long)pxp->fb.base); ++ ++ if (pxp->fb_blank) ++ set_fb_blank(FB_BLANK_POWERDOWN); ++ ++ return ret; ++} ++ ++static int pxp_buf_setup(struct videobuf_queue *q, ++ unsigned int *count, unsigned *size) ++{ ++ struct pxps *pxp = q->priv_data; ++ ++ *size = pxp->pxp_conf.s0_param.width * ++ pxp->pxp_conf.s0_param.height * pxp->s0_fmt->bpp; ++ ++ if (0 == *count) ++ *count = PXP_DEF_BUFS; ++ ++ return 0; ++} ++ ++static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf) ++{ ++ struct videobuf_buffer *vb = &buf->vb; ++ ++ BUG_ON(in_interrupt()); ++ ++ pr_debug("%s (vb=0x%p) 0x%08lx %d\n", __func__, ++ vb, vb->baddr, vb->bsize); ++ ++ /* ++ * This waits until this buffer is out of danger, i.e., until it is no ++ * longer in STATE_QUEUED or STATE_ACTIVE ++ */ ++ videobuf_waiton(q, vb, 0, 0); ++ ++ videobuf_dma_contig_free(q, vb); ++ buf->txd = NULL; ++ ++ vb->state = VIDEOBUF_NEEDS_INIT; ++} ++ ++static int pxp_buf_prepare(struct videobuf_queue *q, ++ struct videobuf_buffer *vb, ++ enum v4l2_field field) ++{ ++ struct pxps *pxp = q->priv_data; ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf; ++ struct pxp_proc_data *proc_data = &pxp_conf->proc_data; ++ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb); ++ struct pxp_tx_desc *desc; ++ int ret = 0; ++ int i, length; ++ ++ if (!pxp->outbuf.paddr) { ++ dev_err(&pxp->pdev->dev, "Not allocate memory for " ++ "PxP Out buffer?\n"); ++ return -ENOMEM; ++ } ++ ++ vb->width = pxp->pxp_conf.s0_param.width; ++ vb->height = pxp->pxp_conf.s0_param.height; ++ vb->size = vb->width * vb->height * pxp->s0_fmt->bpp; ++ vb->field = V4L2_FIELD_NONE; ++ if (vb->state != VIDEOBUF_NEEDS_INIT) ++ pxp_buf_free(q, buf); ++ ++ if (vb->state == VIDEOBUF_NEEDS_INIT) { ++ struct pxp_channel *pchan = pxp->pxp_channel[0]; ++ struct scatterlist *sg = &buf->sg[0]; ++ ++ /* This actually (allocates and) maps buffers */ ++ ret = videobuf_iolock(q, vb, NULL); ++ if (ret) { ++ pr_err("fail to call videobuf_iolock, ret = %d\n", ret); ++ goto fail; ++ } ++ ++ /* ++ * sg[0] for input(S0) ++ * Sg[1] for output ++ */ ++ sg_init_table(sg, 3); ++ ++ buf->txd = pchan->dma_chan.device->device_prep_slave_sg( ++ &pchan->dma_chan, sg, 3, DMA_FROM_DEVICE, ++ DMA_PREP_INTERRUPT, NULL); ++ if (!buf->txd) { ++ ret = -EIO; ++ goto fail; ++ } ++ ++ buf->txd->callback_param = buf->txd; ++ buf->txd->callback = video_dma_done; ++ ++ desc = to_tx_desc(buf->txd); ++ length = desc->len; ++ for (i = 0; i < length; i++) { ++ if (i == 0) {/* S0 */ ++ memcpy(&desc->proc_data, proc_data, ++ sizeof(struct pxp_proc_data)); ++ pxp_conf->s0_param.paddr = ++ videobuf_to_dma_contig(vb); ++ memcpy(&desc->layer_param.s0_param, ++ &pxp_conf->s0_param, ++ sizeof(struct pxp_layer_param)); ++ } else if (i == 1) { /* Output */ ++ /* we should always pass the output ++ * width and height which is the value ++ * after been rotated. ++ */ ++ pxp_conf->out_param.width = ++ pxp->fb.fmt.width; ++ pxp_conf->out_param.height = ++ pxp->fb.fmt.height; ++ ++ pxp_conf->out_param.paddr = pxp->outbuf.paddr; ++ memcpy(&desc->layer_param.out_param, ++ &pxp_conf->out_param, ++ sizeof(struct pxp_layer_param)); ++ } else if (pxp_conf->ol_param[0].combine_enable) { ++ /* Overlay */ ++ pxp_conf->ol_param[0].paddr = ++ (dma_addr_t)pxp->fb.base; ++ pxp_conf->ol_param[0].width = pxp->fb.fmt.width; ++ pxp_conf->ol_param[0].height = ++ pxp->fb.fmt.height; ++ pxp_conf->ol_param[0].pixel_fmt = ++ pxp_conf->out_param.pixel_fmt; ++ memcpy(&desc->layer_param.ol_param, ++ &pxp_conf->ol_param[0], ++ sizeof(struct pxp_layer_param)); ++ } ++ ++ desc = desc->next; ++ } ++ ++ vb->state = VIDEOBUF_PREPARED; ++ } ++ ++ return 0; ++ ++fail: ++ pxp_buf_free(q, buf); ++ return ret; ++} ++ ++ ++static void pxp_buf_queue(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct pxps *pxp = q->priv_data; ++ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb); ++ struct dma_async_tx_descriptor *txd = buf->txd; ++ struct pxp_channel *pchan = pxp->pxp_channel[0]; ++ dma_cookie_t cookie; ++ ++ BUG_ON(!irqs_disabled()); ++ ++ list_add_tail(&vb->queue, &pxp->outq); ++ ++ if (!pxp->active) { ++ pxp->active = buf; ++ vb->state = VIDEOBUF_ACTIVE; ++ } else { ++ vb->state = VIDEOBUF_QUEUED; ++ } ++ ++ spin_unlock_irq(&pxp->lock); ++ ++ cookie = txd->tx_submit(txd); ++ dev_dbg(&pxp->pdev->dev, "Submitted cookie %d DMA 0x%08x\n", ++ cookie, sg_dma_address(&buf->sg[0])); ++ mdelay(5); ++ /* trigger ePxP */ ++ dma_async_issue_pending(&pchan->dma_chan); ++ ++ spin_lock_irq(&pxp->lock); ++ ++ if (cookie >= 0) ++ return; ++ ++ /* Submit error */ ++ pr_err("%s: Submit error\n", __func__); ++ vb->state = VIDEOBUF_PREPARED; ++ ++ list_del_init(&vb->queue); ++ ++ if (pxp->active == buf) ++ pxp->active = NULL; ++} ++ ++static void pxp_buf_release(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct pxps *pxp = q->priv_data; ++ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && ++ !list_empty(&vb->queue)) { ++ vb->state = VIDEOBUF_ERROR; ++ ++ list_del_init(&vb->queue); ++ if (pxp->active == buf) ++ pxp->active = NULL; ++ } ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ ++ pxp_buf_free(q, buf); ++} ++ ++static struct videobuf_queue_ops pxp_vbq_ops = { ++ .buf_setup = pxp_buf_setup, ++ .buf_prepare = pxp_buf_prepare, ++ .buf_queue = pxp_buf_queue, ++ .buf_release = pxp_buf_release, ++}; ++ ++static int pxp_querycap(struct file *file, void *fh, ++ struct v4l2_capability *cap) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ memset(cap, 0, sizeof(*cap)); ++ strcpy(cap->driver, "pxp"); ++ strcpy(cap->card, "pxp"); ++ strlcpy(cap->bus_info, dev_name(&pxp->pdev->dev), ++ sizeof(cap->bus_info)); ++ ++ cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR; ++ ++ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_VIDEO_OUTPUT_OVERLAY | ++ V4L2_CAP_STREAMING; ++ ++ return 0; ++} ++ ++static int pxp_g_fbuf(struct file *file, void *priv, ++ struct v4l2_framebuffer *fb) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ memset(fb, 0, sizeof(*fb)); ++ ++ fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | ++ V4L2_FBUF_CAP_CHROMAKEY | ++ V4L2_FBUF_CAP_LOCAL_ALPHA | ++ V4L2_FBUF_CAP_GLOBAL_ALPHA; ++ ++ if (pxp->global_alpha_state) ++ fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; ++ if (pxp->s1_chromakey_state) ++ fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; ++ ++ return 0; ++} ++ ++static int pxp_s_fbuf(struct file *file, void *priv, ++ const struct v4l2_framebuffer *fb) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ pxp->overlay_state = ++ (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; ++ pxp->global_alpha_state = ++ (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; ++ pxp->s1_chromakey_state = ++ (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ++ ++ pxp->pxp_conf.ol_param[0].combine_enable = pxp->overlay_state; ++ pxp->pxp_conf.ol_param[0].global_alpha_enable = pxp->global_alpha_state; ++ ++ return 0; ++} ++ ++static int pxp_g_crop(struct file *file, void *fh, ++ struct v4l2_crop *c) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) ++ return -EINVAL; ++ ++ c->c.left = pxp->pxp_conf.proc_data.drect.left; ++ c->c.top = pxp->pxp_conf.proc_data.drect.top; ++ c->c.width = pxp->pxp_conf.proc_data.drect.width; ++ c->c.height = pxp->pxp_conf.proc_data.drect.height; ++ ++ return 0; ++} ++ ++static int pxp_s_crop(struct file *file, void *fh, ++ const struct v4l2_crop *c) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int l = c->c.left; ++ int t = c->c.top; ++ int w = c->c.width; ++ int h = c->c.height; ++ int fbw = pxp->fb.fmt.width; ++ int fbh = pxp->fb.fmt.height; ++ ++ if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) ++ return -EINVAL; ++ ++ /* Constrain parameters to FB limits */ ++ w = min(w, fbw); ++ w = max(w, PXP_MIN_PIX); ++ h = min(h, fbh); ++ h = max(h, PXP_MIN_PIX); ++ if ((l + w) > fbw) ++ l = 0; ++ if ((t + h) > fbh) ++ t = 0; ++ ++ /* Round up values to PxP pixel block */ ++ l = roundup(l, PXP_MIN_PIX); ++ t = roundup(t, PXP_MIN_PIX); ++ w = roundup(w, PXP_MIN_PIX); ++ h = roundup(h, PXP_MIN_PIX); ++ ++ pxp->pxp_conf.proc_data.drect.left = l; ++ pxp->pxp_conf.proc_data.drect.top = t; ++ pxp->pxp_conf.proc_data.drect.width = w; ++ pxp->pxp_conf.proc_data.drect.height = h; ++ ++ memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size); ++ ++ return 0; ++} ++ ++static int pxp_queryctrl(struct file *file, void *priv, ++ struct v4l2_queryctrl *qc) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (qc->id && qc->id == pxp_controls[i].id) { ++ memcpy(qc, &(pxp_controls[i]), sizeof(*qc)); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int pxp_g_ctrl(struct file *file, void *priv, ++ struct v4l2_control *vc) ++{ ++ int i; ++ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (vc->id == pxp_controls[i].id) ++ return pxp_get_cstate(pxp, vc); ++ ++ return -EINVAL; ++} ++ ++static int pxp_s_ctrl(struct file *file, void *priv, ++ struct v4l2_control *vc) ++{ ++ int i; ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (vc->id == pxp_controls[i].id) { ++ if (vc->value < pxp_controls[i].minimum || ++ vc->value > pxp_controls[i].maximum) ++ return -ERANGE; ++ return pxp_set_cstate(pxp, vc); ++ } ++ ++ memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size); ++ ++ return -EINVAL; ++} ++ ++void pxp_release(struct video_device *vfd) ++{ ++ struct pxps *pxp = video_get_drvdata(vfd); ++ ++ spin_lock(&pxp->lock); ++ video_device_release(vfd); ++ spin_unlock(&pxp->lock); ++} ++ ++static int pxp_open(struct file *file) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret = 0; ++ ++ mutex_lock(&pxp->mutex); ++ pxp->users++; ++ ++ if (pxp->users > 1) { ++ pxp->users--; ++ ret = -EBUSY; ++ goto out; ++ } ++out: ++ mutex_unlock(&pxp->mutex); ++ if (ret) ++ return ret; ++ ++ ret = pxp_set_fbinfo(pxp); ++ if (ret) { ++ dev_err(&pxp->pdev->dev, "failed to call pxp_set_fbinfo\n"); ++ return ret; ++ } ++ ++ videobuf_queue_dma_contig_init(&pxp->s0_vbq, ++ &pxp_vbq_ops, ++ &pxp->pdev->dev, ++ &pxp->lock, ++ V4L2_BUF_TYPE_VIDEO_OUTPUT, ++ V4L2_FIELD_NONE, ++ sizeof(struct pxp_buffer), ++ pxp, ++ NULL); ++ dev_dbg(&pxp->pdev->dev, "call pxp_open\n"); ++ ++ return 0; ++} ++ ++static int pxp_close(struct file *file) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ pxp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_OUTPUT); ++ videobuf_stop(&pxp->s0_vbq); ++ videobuf_mmap_free(&pxp->s0_vbq); ++ pxp->active = NULL; ++ ++ mutex_lock(&pxp->mutex); ++ pxp->users--; ++ mutex_unlock(&pxp->mutex); ++ ++ return 0; ++} ++ ++static int pxp_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret; ++ ++ ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma); ++ ++ return ret; ++} ++ ++static const struct v4l2_file_operations pxp_fops = { ++ .owner = THIS_MODULE, ++ .open = pxp_open, ++ .release = pxp_close, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = pxp_mmap, ++}; ++ ++static const struct v4l2_ioctl_ops pxp_ioctl_ops = { ++ .vidioc_querycap = pxp_querycap, ++ ++ .vidioc_reqbufs = pxp_reqbufs, ++ .vidioc_querybuf = pxp_querybuf, ++ .vidioc_qbuf = pxp_qbuf, ++ .vidioc_dqbuf = pxp_dqbuf, ++ ++ .vidioc_streamon = pxp_streamon, ++ .vidioc_streamoff = pxp_streamoff, ++ ++ .vidioc_enum_output = pxp_enumoutput, ++ .vidioc_g_output = pxp_g_output, ++ .vidioc_s_output = pxp_s_output, ++ ++ .vidioc_enum_fmt_vid_out = pxp_enum_fmt_video_output, ++ .vidioc_try_fmt_vid_out = pxp_try_fmt_video_output, ++ .vidioc_g_fmt_vid_out = pxp_g_fmt_video_output, ++ .vidioc_s_fmt_vid_out = pxp_s_fmt_video_output, ++ ++ .vidioc_try_fmt_vid_out_overlay = pxp_try_fmt_output_overlay, ++ .vidioc_g_fmt_vid_out_overlay = pxp_g_fmt_output_overlay, ++ .vidioc_s_fmt_vid_out_overlay = pxp_s_fmt_output_overlay, ++ ++ .vidioc_g_fbuf = pxp_g_fbuf, ++ .vidioc_s_fbuf = pxp_s_fbuf, ++ ++ .vidioc_g_crop = pxp_g_crop, ++ .vidioc_s_crop = pxp_s_crop, ++ ++ .vidioc_queryctrl = pxp_queryctrl, ++ .vidioc_g_ctrl = pxp_g_ctrl, ++ .vidioc_s_ctrl = pxp_s_ctrl, ++}; ++ ++static const struct video_device pxp_template = { ++ .name = "PxP", ++ .vfl_type = V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_VIDEO_OVERLAY | ++ V4L2_CAP_STREAMING, ++ .vfl_dir = VFL_DIR_TX, ++ .fops = &pxp_fops, ++ .release = pxp_release, ++ .minor = -1, ++ .ioctl_ops = &pxp_ioctl_ops, ++}; ++ ++static const struct of_device_id imx_pxpv4l2_dt_ids[] = { ++ { .compatible = "fsl,imx6sl-pxp-v4l2", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx_pxpv4l2_dt_ids); ++ ++static int pxp_probe(struct platform_device *pdev) ++{ ++ struct pxps *pxp; ++ struct v4l2_device *v4l2_dev; ++ int err = 0; ++ ++ pxp = kzalloc(sizeof(*pxp), GFP_KERNEL); ++ if (!pxp) { ++ dev_err(&pdev->dev, "failed to allocate control object\n"); ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ dev_set_drvdata(&pdev->dev, pxp); ++ ++ v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL); ++ if (!v4l2_dev) { ++ dev_err(&pdev->dev, "failed to allocate v4l2_dev structure\n"); ++ err = -ENOMEM; ++ goto freeirq; ++ } ++ ++ err = v4l2_device_register(&pdev->dev, v4l2_dev); ++ if (err) { ++ dev_err(&pdev->dev, "register v4l2 device failed\n"); ++ goto freev4l2; ++ } ++ ++ INIT_LIST_HEAD(&pxp->outq); ++ spin_lock_init(&pxp->lock); ++ mutex_init(&pxp->mutex); ++ ++ pxp->pdev = pdev; ++ ++ pxp->vdev = video_device_alloc(); ++ if (!pxp->vdev) { ++ dev_err(&pdev->dev, "video_device_alloc() failed\n"); ++ err = -ENOMEM; ++ goto relv4l2; ++ } ++ ++ memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template)); ++ pxp->vdev->v4l2_dev = v4l2_dev; ++ video_set_drvdata(pxp->vdev, pxp); ++ ++ err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, video_nr); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register video device\n"); ++ goto freevdev; ++ } ++ ++ dev_info(&pdev->dev, "initialized\n"); ++ ++exit: ++ return err; ++ ++freevdev: ++ video_device_release(pxp->vdev); ++relv4l2: ++ v4l2_device_unregister(v4l2_dev); ++freev4l2: ++ kfree(v4l2_dev); ++freeirq: ++ kfree(pxp); ++ ++ return err; ++} ++ ++static int pxp_remove(struct platform_device *pdev) ++{ ++ struct pxps *pxp = platform_get_drvdata(pdev); ++ struct v4l2_device *v4l2_dev = pxp->vdev->v4l2_dev; ++ ++ video_unregister_device(pxp->vdev); ++ video_device_release(pxp->vdev); ++ v4l2_device_unregister(v4l2_dev); ++ kfree(v4l2_dev); ++ ++ free_dma_buf(pxp, &pxp->outbuf); ++ ++ kfree(pxp); ++ ++ return 0; ++} ++ ++static struct platform_driver pxp_driver = { ++ .driver = { ++ .name = PXP_DRIVER_NAME, ++ .of_match_table = of_match_ptr(imx_pxpv4l2_dt_ids), ++ }, ++ .probe = pxp_probe, ++ .remove = pxp_remove, ++}; ++ ++module_platform_driver(pxp_driver); ++ ++module_param(video_nr, int, 0444); ++MODULE_DESCRIPTION("MXC PxP V4L2 driver"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h linux-3.14.72/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h +--- linux-3.14.72.orig/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2010-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 ++ * ++ */ ++/* ++ * Based on STMP378X PxP driver ++ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. ++ */ ++ ++#ifndef _MXC_PXP_V4L2_H ++#define _MXC_PXP_V4L2_H ++ ++#include ++#include ++ ++struct pxp_buffer { ++ /* Must be first! */ ++ struct videobuf_buffer vb; ++ ++ /* One descriptor per scatterlist (per frame) */ ++ struct dma_async_tx_descriptor *txd; ++ ++ struct scatterlist sg[3]; ++}; ++ ++struct dma_mem { ++ void *vaddr; ++ dma_addr_t paddr; ++ size_t size; ++}; ++ ++struct pxps { ++ struct platform_device *pdev; ++ ++ spinlock_t lock; ++ struct mutex mutex; ++ int users; ++ ++ struct video_device *vdev; ++ ++ struct videobuf_queue s0_vbq; ++ struct pxp_buffer *active; ++ struct list_head outq; ++ struct pxp_channel *pxp_channel[1]; /* We need 1 channel */ ++ struct pxp_config_data pxp_conf; ++ struct dma_mem outbuf; ++ ++ int output; ++ ++ /* Current S0 configuration */ ++ struct pxp_data_format *s0_fmt; ++ ++ struct fb_info *fbi; ++ struct v4l2_framebuffer fb; ++ ++ /* Output overlay support */ ++ int overlay_state; ++ int global_alpha_state; ++ u8 global_alpha; ++ int s1_chromakey_state; ++ u32 s1_chromakey; ++ ++ int fb_blank; ++}; ++ ++struct pxp_data_format { ++ char *name; ++ unsigned int bpp; ++ u32 fourcc; ++ enum v4l2_colorspace colorspace; ++}; ++ ++#endif +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/output/mxc_vout.c linux-3.14.72/drivers/media/platform/mxc/output/mxc_vout.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/output/mxc_vout.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/output/mxc_vout.c 2016-06-19 22:11:55.185147881 +0200 +@@ -0,0 +1,2277 @@ ++/* ++ * Copyright (C) 2011-2015 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, in_width = 0, in_height = 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; ++ in_width = vout->task.input.width; ++ in_height = vout->task.input.height; ++ vout->task.input.format = vout->vdoa_task.output.format; ++ vout->task.input.width = vout->vdoa_task.output.width; ++ vout->task.input.height = vout->vdoa_task.output.height; ++ 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; ++ vout->task.input.width = in_width; ++ vout->task.input.height = in_height; ++ } ++ 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; ++ int in_width, in_height; ++ 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; ++ in_width = ipu_task->input.width; ++ in_height = ipu_task->input.height; ++ 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; ++ ipu_task->input.width = in_width; ++ ipu_task->input.height = in_height; ++ ++ 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 * fb_num) >> 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.72.orig/drivers/media/platform/mxc/subdev/Kconfig linux-3.14.72/drivers/media/platform/mxc/subdev/Kconfig +--- linux-3.14.72.orig/drivers/media/platform/mxc/subdev/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/subdev/Kconfig 2016-06-19 22:11:55.189147618 +0200 +@@ -0,0 +1,21 @@ ++if VIDEO_MXC_CAPTURE && SOC_IMX6SX ++ ++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_CAPTURE && I2C ++ ---help--- ++ If you plan to use the ov5640 Camera with your MXC system, say Y here. ++ ++config MXC_VADC ++ tristate "mxc VADC support" ++ depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2 ++ ---help--- ++ If you plan to use the VADC with your MXC system, say Y here. ++ ++endif +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/subdev/Makefile linux-3.14.72/drivers/media/platform/mxc/subdev/Makefile +--- linux-3.14.72.orig/drivers/media/platform/mxc/subdev/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/subdev/Makefile 2016-06-19 22:11:55.189147618 +0200 +@@ -0,0 +1,7 @@ ++#Makefile for mxc csi driver ++ ++obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mx6s_capture.o ++obj-$(CONFIG_MXC_VADC) += mxc_vadc.o ++ ++ov5640_camera-objs := ov5640.o ++obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera.o +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/subdev/mx6s_capture.c linux-3.14.72/drivers/media/platform/mxc/subdev/mx6s_capture.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/subdev/mx6s_capture.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/subdev/mx6s_capture.c 2016-06-19 22:11:55.189147618 +0200 +@@ -0,0 +1,1756 @@ ++/* ++ * Copyright (C) 2014-2015 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 mx6s_csi.c ++ * ++ * @brief mx6sx CMOS Sensor interface functions ++ * ++ * @ingroup CSI ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MX6S_CAM_DRV_NAME "mx6s-csi" ++#define MX6S_CAM_VERSION "0.0.1" ++#define MX6S_CAM_DRIVER_DESCRIPTION "i.MX6S_CSI" ++ ++#define MAX_VIDEO_MEM 16 ++ ++/* 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 ++#define SHIFT_RXFIFO_LEVEL 4 ++ ++/* csi status reg */ ++#define BIT_ADDR_CH_ERR_INT (0x1 << 28) ++#define BIT_FIELD0_INT (0x1 << 27) ++#define BIT_FIELD1_INT (0x1 << 26) ++#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) ++ ++/* csi control reg 18 */ ++#define BIT_CSI_ENABLE (0x1 << 31) ++#define BIT_BASEADDR_CHG_ERR_EN (0x1 << 9) ++#define BIT_BASEADDR_SWITCH_SEL (0x1 << 5) ++#define BIT_BASEADDR_SWITCH_EN (0x1 << 4) ++#define BIT_PARALLEL24_EN (0x1 << 3) ++#define BIT_DEINTERLACE_EN (0x1 << 2) ++#define BIT_TVDECODER_IN_EN (0x1 << 1) ++#define BIT_NTSC_EN (0x1 << 0) ++ ++#define CSI_MCLK_VF 1 ++#define CSI_MCLK_ENC 2 ++#define CSI_MCLK_RAW 4 ++#define CSI_MCLK_I2C 8 ++ ++#define CSI_CSICR1 0x0 ++#define CSI_CSICR2 0x4 ++#define CSI_CSICR3 0x8 ++#define CSI_STATFIFO 0xC ++#define CSI_CSIRXFIFO 0x10 ++#define CSI_CSIRXCNT 0x14 ++#define CSI_CSISR 0x18 ++ ++#define CSI_CSIDBG 0x1C ++#define CSI_CSIDMASA_STATFIFO 0x20 ++#define CSI_CSIDMATS_STATFIFO 0x24 ++#define CSI_CSIDMASA_FB1 0x28 ++#define CSI_CSIDMASA_FB2 0x2C ++#define CSI_CSIFBUF_PARA 0x30 ++#define CSI_CSIIMAG_PARA 0x34 ++ ++#define CSI_CSICR18 0x48 ++#define CSI_CSICR19 0x4c ++ ++#define NUM_FORMATS ARRAY_SIZE(formats) ++#define MX6SX_MAX_SENSORS 1 ++ ++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; ++}; ++ ++/* ++ * Basic structures ++ */ ++struct mx6s_fmt { ++ char name[32]; ++ u32 fourcc; /* v4l2 format id */ ++ u32 pixelformat; ++ enum v4l2_mbus_pixelcode mbus_code; ++ int bpp; ++}; ++ ++static struct mx6s_fmt formats[] = { ++ { ++ .name = "UYVY-16", ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .pixelformat = V4L2_PIX_FMT_UYVY, ++ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, ++ .bpp = 2, ++ }, { ++ .name = "YUYV-16", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .pixelformat = V4L2_PIX_FMT_YUYV, ++ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, ++ .bpp = 2, ++ }, { ++ .name = "YUV32 (X-Y-U-V)", ++ .fourcc = V4L2_PIX_FMT_YUV32, ++ .pixelformat = V4L2_PIX_FMT_YUV32, ++ .mbus_code = V4L2_MBUS_FMT_AYUV8_1X32, ++ .bpp = 4, ++ } ++}; ++ ++struct mx6s_buf_internal { ++ struct list_head queue; ++ int bufnum; ++ bool discard; ++}; ++ ++/* buffer for one video frame */ ++struct mx6s_buffer { ++ /* common v4l buffer stuff -- must be first */ ++ struct vb2_buffer vb; ++ struct mx6s_buf_internal internal; ++}; ++ ++struct mx6s_csi_dev { ++ struct device *dev; ++ struct video_device *vdev; ++ struct v4l2_subdev *sd; ++ struct v4l2_device v4l2_dev; ++ ++ struct vb2_queue vb2_vidq; ++ struct vb2_alloc_ctx *alloc_ctx; ++ struct v4l2_ctrl_handler ctrl_handler; ++ ++ struct mutex lock; ++ spinlock_t slock; ++ ++ /* clock */ ++ struct clk *clk_disp_axi; ++ struct clk *clk_disp_dcic; ++ struct clk *clk_csi_mclk; ++ ++ void __iomem *regbase; ++ int irq; ++ ++ u32 type; ++ u32 bytesperline; ++ v4l2_std_id std; ++ struct mx6s_fmt *fmt; ++ struct v4l2_pix_format pix; ++ enum v4l2_mbus_pixelcode mbus_code; ++ ++ unsigned int frame_count; ++ ++ struct list_head capture; ++ struct list_head active_bufs; ++ struct list_head discard; ++ ++ void *discard_buffer; ++ dma_addr_t discard_buffer_dma; ++ size_t discard_size; ++ struct mx6s_buf_internal buf_discard[2]; ++ ++ struct v4l2_async_subdev asd; ++ struct v4l2_async_notifier subdev_notifier; ++ struct v4l2_async_subdev *async_subdevs[2]; ++}; ++ ++static inline int csi_read(struct mx6s_csi_dev *csi, unsigned int offset) ++{ ++ return __raw_readl(csi->regbase + offset); ++} ++static inline void csi_write(struct mx6s_csi_dev *csi, unsigned int value, ++ unsigned int offset) ++{ ++ __raw_writel(value, csi->regbase + offset); ++} ++ ++static inline struct mx6s_csi_dev ++ *notifier_to_mx6s_dev(struct v4l2_async_notifier *n) ++{ ++ return container_of(n, struct mx6s_csi_dev, subdev_notifier); ++} ++ ++struct mx6s_fmt *format_by_fourcc(int fourcc) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_FORMATS; i++) { ++ if (formats[i].pixelformat == fourcc) ++ return formats + i; ++ } ++ ++ pr_err("unknown pixelformat:'%4.4s'\n", (char *)&fourcc); ++ return NULL; ++} ++ ++struct mx6s_fmt *format_by_mbus(enum v4l2_mbus_pixelcode code) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_FORMATS; i++) { ++ if (formats[i].mbus_code == code) ++ return formats + i; ++ } ++ ++ pr_err("unknown pixelformat:'%4.4s'\n", (char *)&code); ++ return NULL; ++} ++ ++static struct mx6s_buffer *mx6s_ibuf_to_buf(struct mx6s_buf_internal *int_buf) ++{ ++ return container_of(int_buf, struct mx6s_buffer, internal); ++} ++ ++void csi_clk_enable(struct mx6s_csi_dev *csi_dev) ++{ ++ clk_prepare_enable(csi_dev->clk_disp_axi); ++ clk_prepare_enable(csi_dev->clk_disp_dcic); ++ clk_prepare_enable(csi_dev->clk_csi_mclk); ++} ++ ++void csi_clk_disable(struct mx6s_csi_dev *csi_dev) ++{ ++ clk_disable_unprepare(csi_dev->clk_csi_mclk); ++ clk_disable_unprepare(csi_dev->clk_disp_dcic); ++ clk_disable_unprepare(csi_dev->clk_disp_axi); ++} ++ ++static void csihw_reset(struct mx6s_csi_dev *csi_dev) ++{ ++ __raw_writel(__raw_readl(csi_dev->regbase + CSI_CSICR3) ++ | BIT_FRMCNT_RST, ++ csi_dev->regbase + CSI_CSICR3); ++ ++ __raw_writel(CSICR1_RESET_VAL, csi_dev->regbase + CSI_CSICR1); ++ __raw_writel(CSICR2_RESET_VAL, csi_dev->regbase + CSI_CSICR2); ++ __raw_writel(CSICR3_RESET_VAL, csi_dev->regbase + CSI_CSICR3); ++} ++ ++static void csisw_reset(struct mx6s_csi_dev *csi_dev) ++{ ++ int cr1, cr3, cr18, isr; ++ ++ /* Disable csi */ ++ cr18 = csi_read(csi_dev, CSI_CSICR18); ++ cr18 &= ~BIT_CSI_ENABLE; ++ csi_write(csi_dev, cr18, CSI_CSICR18); ++ ++ /* Clear RX FIFO */ ++ cr1 = csi_read(csi_dev, CSI_CSICR1); ++ csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1); ++ cr1 = csi_read(csi_dev, CSI_CSICR1); ++ csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1); ++ ++ /* DMA reflash */ ++ cr3 = csi_read(csi_dev, CSI_CSICR3); ++ cr3 |= BIT_DMA_REFLASH_RFF | BIT_FRMCNT_RST; ++ csi_write(csi_dev, cr3, CSI_CSICR3); ++ ++ msleep(2); ++ ++ cr1 = csi_read(csi_dev, CSI_CSICR1); ++ csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1); ++ ++ isr = csi_read(csi_dev, CSI_CSISR); ++ csi_write(csi_dev, isr, CSI_CSISR); ++ ++ /* Ensable csi */ ++ cr18 |= BIT_CSI_ENABLE; ++ csi_write(csi_dev, cr18, CSI_CSICR18); ++} ++ ++/*! ++ * csi_init_interface ++ * Init csi interface ++ */ ++static void csi_init_interface(struct mx6s_csi_dev *csi_dev) ++{ ++ 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_FCC; ++ val |= 1 << SHIFT_MCLKDIV; ++ val |= BIT_MCLKEN; ++ __raw_writel(val, csi_dev->regbase + CSI_CSICR1); ++ ++ imag_para = (640 << 16) | 960; ++ __raw_writel(imag_para, csi_dev->regbase + CSI_CSIIMAG_PARA); ++ ++ val = BIT_DMA_REFLASH_RFF; ++ __raw_writel(val, csi_dev->regbase + CSI_CSICR3); ++} ++ ++static void csi_enable_int(struct mx6s_csi_dev *csi_dev, int arg) ++{ ++ unsigned long cr1 = __raw_readl(csi_dev->regbase + 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_dev->regbase + CSI_CSICR1); ++} ++ ++static void csi_disable_int(struct mx6s_csi_dev *csi_dev) ++{ ++ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1); ++ ++ cr1 &= ~BIT_SOF_INTEN; ++ cr1 &= ~BIT_FB1_DMA_DONE_INTEN; ++ cr1 &= ~BIT_FB2_DMA_DONE_INTEN; ++ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1); ++} ++ ++static void csi_enable(struct mx6s_csi_dev *csi_dev, int arg) ++{ ++ unsigned long cr = __raw_readl(csi_dev->regbase + CSI_CSICR18); ++ ++ if (arg == 1) ++ cr |= BIT_CSI_ENABLE; ++ else ++ cr &= ~BIT_CSI_ENABLE; ++ __raw_writel(cr, csi_dev->regbase + CSI_CSICR18); ++} ++ ++static void csi_buf_stride_set(struct mx6s_csi_dev *csi_dev, u32 stride) ++{ ++ __raw_writel(stride, csi_dev->regbase + CSI_CSIFBUF_PARA); ++} ++ ++static void csi_deinterlace_enable(struct mx6s_csi_dev *csi_dev, bool enable) ++{ ++ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18); ++ ++ if (enable == true) ++ cr18 |= BIT_DEINTERLACE_EN; ++ else ++ cr18 &= ~BIT_DEINTERLACE_EN; ++ ++ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18); ++} ++ ++static void csi_deinterlace_mode(struct mx6s_csi_dev *csi_dev, int mode) ++{ ++ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18); ++ ++ if (mode == V4L2_STD_NTSC) ++ cr18 |= BIT_NTSC_EN; ++ else ++ cr18 &= ~BIT_NTSC_EN; ++ ++ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18); ++} ++ ++static void csi_tvdec_enable(struct mx6s_csi_dev *csi_dev, bool enable) ++{ ++ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18); ++ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1); ++ ++ if (enable == true) { ++ cr18 |= (BIT_TVDECODER_IN_EN | ++ BIT_BASEADDR_SWITCH_EN | ++ BIT_BASEADDR_SWITCH_SEL | ++ BIT_BASEADDR_CHG_ERR_EN); ++ cr1 |= BIT_CCIR_MODE; ++ cr1 &= ~(BIT_SOF_POL | BIT_REDGE); ++ } else { ++ cr18 &= ~(BIT_TVDECODER_IN_EN | ++ BIT_BASEADDR_SWITCH_EN | ++ BIT_BASEADDR_SWITCH_SEL | ++ BIT_BASEADDR_CHG_ERR_EN); ++ cr1 &= ~BIT_CCIR_MODE; ++ cr1 |= BIT_SOF_POL | BIT_REDGE; ++ } ++ ++ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18); ++ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1); ++} ++ ++static void csi_dmareq_rff_enable(struct mx6s_csi_dev *csi_dev) ++{ ++ unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3); ++ unsigned long cr2 = __raw_readl(csi_dev->regbase + CSI_CSICR2); ++ ++ /* Burst Type of DMA Transfer from RxFIFO. INCR16 */ ++ cr2 |= 0xC0000000; ++ ++ cr3 |= BIT_DMA_REQ_EN_RFF; ++ cr3 |= BIT_HRESP_ERR_EN; ++ cr3 &= ~BIT_RXFF_LEVEL; ++ cr3 |= 0x2 << 4; ++ ++ __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3); ++ __raw_writel(cr2, csi_dev->regbase + CSI_CSICR2); ++} ++ ++static void csi_dmareq_rff_disable(struct mx6s_csi_dev *csi_dev) ++{ ++ unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3); ++ ++ cr3 &= ~BIT_DMA_REQ_EN_RFF; ++ cr3 &= ~BIT_HRESP_ERR_EN; ++ __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3); ++} ++ ++static void csi_set_32bit_imagpara(struct mx6s_csi_dev *csi, ++ int width, int height) ++{ ++ int imag_para = 0; ++ unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3); ++ ++ imag_para = (width << 16) | height; ++ __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA); ++ ++ /* reflash the embeded DMA controller */ ++ __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3); ++} ++ ++static void csi_set_16bit_imagpara(struct mx6s_csi_dev *csi, ++ int width, int height) ++{ ++ int imag_para = 0; ++ unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3); ++ ++ imag_para = (width << 16) | (height * 2); ++ __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA); ++ ++ /* reflash the embeded DMA controller */ ++ __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3); ++} ++ ++/* ++ * Videobuf operations ++ */ ++static int mx6s_videobuf_setup(struct vb2_queue *vq, ++ const struct v4l2_format *fmt, ++ unsigned int *count, unsigned int *num_planes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq); ++ ++ dev_dbg(csi_dev->dev, "count=%d, size=%d\n", *count, sizes[0]); ++ ++ /* TODO: support for VIDIOC_CREATE_BUFS not ready */ ++ if (fmt != NULL) ++ return -ENOTTY; ++ ++ alloc_ctxs[0] = csi_dev->alloc_ctx; ++ ++ sizes[0] = csi_dev->pix.sizeimage; ++ ++ pr_debug("size=%d\n", sizes[0]); ++ if (0 == *count) ++ *count = 32; ++ if (!*num_planes && ++ sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) ++ *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; ++ ++ *num_planes = 1; ++ ++ return 0; ++} ++ ++static int mx6s_videobuf_prepare(struct vb2_buffer *vb) ++{ ++ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue); ++ int ret = 0; ++ ++ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); ++ ++#ifdef DEBUG ++ /* ++ * This can be useful if you want to see if we actually fill ++ * the buffer with something ++ */ ++ memset((void *)vb2_plane_vaddr(vb, 0), ++ 0xaa, vb2_get_plane_payload(vb, 0)); ++#endif ++ ++ vb2_set_plane_payload(vb, 0, csi_dev->pix.sizeimage); ++ if (vb2_plane_vaddr(vb, 0) && ++ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ return ret; ++} ++ ++static void mx6s_videobuf_queue(struct vb2_buffer *vb) ++{ ++ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct mx6s_buffer *buf = container_of(vb, struct mx6s_buffer, vb); ++ unsigned long flags; ++ ++ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); ++ ++ spin_lock_irqsave(&csi_dev->slock, flags); ++ ++ list_add_tail(&buf->internal.queue, &csi_dev->capture); ++ ++ spin_unlock_irqrestore(&csi_dev->slock, flags); ++} ++ ++static void mx6s_update_csi_buf(struct mx6s_csi_dev *csi_dev, ++ unsigned long phys, int bufnum) ++{ ++ if (bufnum == 1) ++ csi_write(csi_dev, phys, CSI_CSIDMASA_FB2); ++ else ++ csi_write(csi_dev, phys, CSI_CSIDMASA_FB1); ++} ++ ++static void mx6s_csi_init(struct mx6s_csi_dev *csi_dev) ++{ ++ csi_clk_enable(csi_dev); ++ csihw_reset(csi_dev); ++ csi_init_interface(csi_dev); ++ csi_dmareq_rff_disable(csi_dev); ++} ++ ++static void mx6s_csi_deinit(struct mx6s_csi_dev *csi_dev) ++{ ++ csihw_reset(csi_dev); ++ csi_init_interface(csi_dev); ++ csi_dmareq_rff_disable(csi_dev); ++ csi_clk_disable(csi_dev); ++} ++ ++static void mx6s_csi_enable(struct mx6s_csi_dev *csi_dev) ++{ ++ struct v4l2_pix_format *pix = &csi_dev->pix; ++ ++ csisw_reset(csi_dev); ++ ++ if (pix->field == V4L2_FIELD_INTERLACED) ++ csi_tvdec_enable(csi_dev, true); ++ ++ csi_dmareq_rff_enable(csi_dev); ++ csi_enable_int(csi_dev, 1); ++ csi_enable(csi_dev, 1); ++ ++} ++ ++static void mx6s_csi_disable(struct mx6s_csi_dev *csi_dev) ++{ ++ struct v4l2_pix_format *pix = &csi_dev->pix; ++ ++ csi_dmareq_rff_disable(csi_dev); ++ csi_disable_int(csi_dev); ++ ++ /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */ ++ csi_write(csi_dev, 0, CSI_CSIDMASA_FB1); ++ csi_write(csi_dev, 0, CSI_CSIDMASA_FB2); ++ ++ csi_buf_stride_set(csi_dev, 0); ++ ++ if (pix->field == V4L2_FIELD_INTERLACED) { ++ csi_deinterlace_enable(csi_dev, false); ++ csi_tvdec_enable(csi_dev, false); ++ } ++ ++ csi_enable(csi_dev, 0); ++} ++ ++static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev) ++{ ++ struct v4l2_pix_format *pix = &csi_dev->pix; ++ ++ if (pix->field == V4L2_FIELD_INTERLACED) { ++ csi_deinterlace_enable(csi_dev, true); ++ csi_buf_stride_set(csi_dev, csi_dev->pix.width); ++ csi_deinterlace_mode(csi_dev, csi_dev->std); ++ } else { ++ csi_deinterlace_enable(csi_dev, false); ++ csi_buf_stride_set(csi_dev, 0); ++ } ++ ++ switch (csi_dev->fmt->pixelformat) { ++ case V4L2_PIX_FMT_YUV32: ++ csi_set_32bit_imagpara(csi_dev, pix->width, pix->height); ++ break; ++ case V4L2_PIX_FMT_UYVY: ++ csi_set_16bit_imagpara(csi_dev, pix->width, pix->height); ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ csi_set_16bit_imagpara(csi_dev, pix->width, pix->height); ++ break; ++ default: ++ pr_debug(" case not supported\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int mx6s_start_streaming(struct vb2_queue *vq, unsigned int count) ++{ ++ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq); ++ struct vb2_buffer *vb; ++ struct mx6s_buffer *buf; ++ unsigned long phys; ++ unsigned long flags; ++ ++ if (count < 2) ++ return -ENOBUFS; ++ ++ /* ++ * I didn't manage to properly enable/disable ++ * a per frame basis during running transfers, ++ * thus we allocate a buffer here and use it to ++ * discard frames when no buffer is available. ++ * Feel free to work on this ;) ++ */ ++ csi_dev->discard_size = csi_dev->pix.sizeimage; ++ csi_dev->discard_buffer = dma_alloc_coherent(csi_dev->v4l2_dev.dev, ++ PAGE_ALIGN(csi_dev->discard_size), ++ &csi_dev->discard_buffer_dma, ++ GFP_DMA | GFP_KERNEL); ++ if (!csi_dev->discard_buffer) ++ return -ENOMEM; ++ ++ spin_lock_irqsave(&csi_dev->slock, flags); ++ ++ csi_dev->buf_discard[0].discard = true; ++ list_add_tail(&csi_dev->buf_discard[0].queue, ++ &csi_dev->discard); ++ ++ csi_dev->buf_discard[1].discard = true; ++ list_add_tail(&csi_dev->buf_discard[1].queue, ++ &csi_dev->discard); ++ ++ /* csi buf 0 */ ++ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer, ++ internal.queue); ++ buf->internal.bufnum = 0; ++ vb = &buf->vb; ++ ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); ++ ++ mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum); ++ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs); ++ ++ /* csi buf 1 */ ++ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer, ++ internal.queue); ++ buf->internal.bufnum = 1; ++ vb = &buf->vb; ++ ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); ++ mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum); ++ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs); ++ ++ spin_unlock_irqrestore(&csi_dev->slock, flags); ++ ++ mx6s_csi_enable(csi_dev); ++ ++ return 0; ++} ++ ++static int mx6s_stop_streaming(struct vb2_queue *vq) ++{ ++ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq); ++ unsigned long flags; ++ struct mx6s_buffer *buf, *tmp; ++ void *b; ++ ++ mx6s_csi_disable(csi_dev); ++ ++ spin_lock_irqsave(&csi_dev->slock, flags); ++ ++ ++ list_for_each_entry_safe(buf, tmp, ++ &csi_dev->active_bufs, internal.queue) { ++ list_del_init(&buf->internal.queue); ++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); ++ } ++ ++ INIT_LIST_HEAD(&csi_dev->capture); ++ INIT_LIST_HEAD(&csi_dev->active_bufs); ++ INIT_LIST_HEAD(&csi_dev->discard); ++ ++ b = csi_dev->discard_buffer; ++ csi_dev->discard_buffer = NULL; ++ ++ spin_unlock_irqrestore(&csi_dev->slock, flags); ++ ++ dma_free_coherent(csi_dev->v4l2_dev.dev, ++ csi_dev->discard_size, b, ++ csi_dev->discard_buffer_dma); ++ ++ return 0; ++} ++ ++static struct vb2_ops mx6s_videobuf_ops = { ++ .queue_setup = mx6s_videobuf_setup, ++ .buf_prepare = mx6s_videobuf_prepare, ++ .buf_queue = mx6s_videobuf_queue, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .start_streaming = mx6s_start_streaming, ++ .stop_streaming = mx6s_stop_streaming, ++}; ++ ++static void mx6s_csi_frame_done(struct mx6s_csi_dev *csi_dev, ++ int bufnum, bool err) ++{ ++ struct mx6s_buf_internal *ibuf; ++ struct mx6s_buffer *buf; ++ struct vb2_buffer *vb; ++ unsigned long phys; ++ ++ ibuf = list_first_entry(&csi_dev->active_bufs, struct mx6s_buf_internal, ++ queue); ++ ++ if (ibuf->discard) { ++ /* ++ * Discard buffer must not be returned to user space. ++ * Just return it to the discard queue. ++ */ ++ list_move_tail(csi_dev->active_bufs.next, &csi_dev->discard); ++ } else { ++ buf = mx6s_ibuf_to_buf(ibuf); ++ ++ vb = &buf->vb; ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); ++ if (bufnum == 1) { ++ if (csi_read(csi_dev, CSI_CSIDMASA_FB2) != phys) { ++ dev_err(csi_dev->dev, "%lx != %x\n", phys, ++ csi_read(csi_dev, CSI_CSIDMASA_FB2)); ++ } ++ } else { ++ if (csi_read(csi_dev, CSI_CSIDMASA_FB1) != phys) { ++ dev_err(csi_dev->dev, "%lx != %x\n", phys, ++ csi_read(csi_dev, CSI_CSIDMASA_FB1)); ++ } ++ } ++ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, ++ vb2_plane_vaddr(vb, 0), ++ vb2_get_plane_payload(vb, 0)); ++ ++ list_del_init(&buf->internal.queue); ++ v4l2_get_timestamp(&vb->v4l2_buf.timestamp); ++ vb->v4l2_buf.sequence = csi_dev->frame_count; ++ if (err) ++ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); ++ else ++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); ++ } ++ ++ csi_dev->frame_count++; ++ ++ /* Config discard buffer to active_bufs */ ++ if (list_empty(&csi_dev->capture)) { ++ if (list_empty(&csi_dev->discard)) { ++ dev_warn(csi_dev->dev, ++ "%s: trying to access empty discard list\n", ++ __func__); ++ return; ++ } ++ ++ ibuf = list_first_entry(&csi_dev->discard, ++ struct mx6s_buf_internal, queue); ++ ibuf->bufnum = bufnum; ++ ++ list_move_tail(csi_dev->discard.next, &csi_dev->active_bufs); ++ ++ mx6s_update_csi_buf(csi_dev, ++ csi_dev->discard_buffer_dma, bufnum); ++ return; ++ } ++ ++ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer, ++ internal.queue); ++ ++ buf->internal.bufnum = bufnum; ++ ++ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs); ++ ++ vb = &buf->vb; ++ ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); ++ mx6s_update_csi_buf(csi_dev, phys, bufnum); ++} ++ ++static irqreturn_t mx6s_csi_irq_handler(int irq, void *data) ++{ ++ struct mx6s_csi_dev *csi_dev = data; ++ unsigned long status; ++ u32 cr1, cr3, cr18; ++ ++ spin_lock(&csi_dev->slock); ++ ++ status = csi_read(csi_dev, CSI_CSISR); ++ csi_write(csi_dev, status, CSI_CSISR); ++ ++ if (list_empty(&csi_dev->active_bufs)) { ++ dev_warn(csi_dev->dev, ++ "%s: called while active list is empty\n", ++ __func__); ++ ++ spin_unlock(&csi_dev->slock); ++ return IRQ_HANDLED; ++ } ++ ++ if (status & BIT_HRESP_ERR_INT) { ++ /* software reset */ ++ ++ /* Disable csi */ ++ cr18 = csi_read(csi_dev, CSI_CSICR18); ++ cr18 &= ~BIT_CSI_ENABLE; ++ csi_write(csi_dev, cr18, CSI_CSICR18); ++ ++ /* Clear RX FIFO */ ++ cr1 = csi_read(csi_dev, CSI_CSICR1); ++ csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1); ++ cr1 = csi_read(csi_dev, CSI_CSICR1); ++ csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1); ++ ++ cr1 = csi_read(csi_dev, CSI_CSICR1); ++ csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1); ++ ++ /* DMA reflash */ ++ cr3 = csi_read(csi_dev, CSI_CSICR3); ++ cr3 |= BIT_DMA_REFLASH_RFF; ++ csi_write(csi_dev, cr3, CSI_CSICR3); ++ ++ /* Ensable csi */ ++ cr18 |= BIT_CSI_ENABLE; ++ csi_write(csi_dev, cr18, CSI_CSICR18); ++ ++ pr_warning("Hresponse error is detected.\n"); ++ } ++ ++ if (status & BIT_ADDR_CH_ERR_INT) { ++ /* Disable csi */ ++ cr18 = csi_read(csi_dev, CSI_CSICR18); ++ cr18 &= ~BIT_CSI_ENABLE; ++ csi_write(csi_dev, cr18, CSI_CSICR18); ++ ++ /* DMA reflash */ ++ cr3 = csi_read(csi_dev, CSI_CSICR3); ++ cr3 |= BIT_DMA_REFLASH_RFF; ++ csi_write(csi_dev, cr3, CSI_CSICR3); ++ ++ /* Ensable csi */ ++ cr18 |= BIT_CSI_ENABLE; ++ csi_write(csi_dev, cr18, CSI_CSICR18); ++ ++ pr_debug("base address switching Change Err.\n"); ++ } ++ ++ if ((status & BIT_DMA_TSF_DONE_FB1) && ++ (status & BIT_DMA_TSF_DONE_FB2)) { ++ /* For both FB1 and FB2 interrupter bits set case, ++ * CSI DMA is work in one of FB1 and FB2 buffer, ++ * but software can not know the state. ++ * Skip it to avoid base address updated ++ * when csi work in field0 and field1 will write to ++ * new base address. ++ * PDM TKT230775 */ ++ pr_debug("Skip two frames\n"); ++ } else if (status & BIT_DMA_TSF_DONE_FB1) { ++ mx6s_csi_frame_done(csi_dev, 0, false); ++ } else if (status & BIT_DMA_TSF_DONE_FB2) { ++ mx6s_csi_frame_done(csi_dev, 1, false); ++ } ++ ++ spin_unlock(&csi_dev->slock); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * File operations for the device ++ */ ++static int mx6s_csi_open(struct file *file) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct vb2_queue *q = &csi_dev->vb2_vidq; ++ int ret = 0; ++ ++ file->private_data = csi_dev; ++ ++ if (mutex_lock_interruptible(&csi_dev->lock)) ++ return -ERESTARTSYS; ++ ++ csi_dev->alloc_ctx = vb2_dma_contig_init_ctx(csi_dev->dev); ++ if (IS_ERR(csi_dev->alloc_ctx)) ++ goto unlock; ++ ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP | VB2_USERPTR; ++ q->drv_priv = csi_dev; ++ q->ops = &mx6s_videobuf_ops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->buf_struct_size = sizeof(struct mx6s_buffer); ++ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->lock = &csi_dev->lock; ++ ++ ret = vb2_queue_init(q); ++ if (ret < 0) ++ goto eallocctx; ++ ++ pm_runtime_get_sync(csi_dev->dev); ++ ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ mx6s_csi_init(csi_dev); ++ ++ mutex_unlock(&csi_dev->lock); ++ ++ return ret; ++eallocctx: ++ vb2_dma_contig_cleanup_ctx(csi_dev->alloc_ctx); ++unlock: ++ mutex_unlock(&csi_dev->lock); ++ return ret; ++} ++ ++static int mx6s_csi_close(struct file *file) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ mutex_lock(&csi_dev->lock); ++ ++ vb2_queue_release(&csi_dev->vb2_vidq); ++ ++ mx6s_csi_deinit(csi_dev); ++ ++ vb2_dma_contig_cleanup_ctx(csi_dev->alloc_ctx); ++ mutex_unlock(&csi_dev->lock); ++ ++ file->private_data = NULL; ++ ++ release_bus_freq(BUS_FREQ_HIGH); ++ ++ pm_runtime_put_sync_suspend(csi_dev->dev); ++ return 0; ++} ++ ++static ssize_t mx6s_csi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ int ret; ++ ++ dev_dbg(csi_dev->dev, "read called, buf %p\n", buf); ++ ++ mutex_lock(&csi_dev->lock); ++ ret = vb2_read(&csi_dev->vb2_vidq, buf, count, ppos, ++ file->f_flags & O_NONBLOCK); ++ mutex_unlock(&csi_dev->lock); ++ return ret; ++} ++ ++static int mx6s_csi_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ int ret; ++ ++ if (mutex_lock_interruptible(&csi_dev->lock)) ++ return -ERESTARTSYS; ++ ret = vb2_mmap(&csi_dev->vb2_vidq, vma); ++ mutex_unlock(&csi_dev->lock); ++ ++ pr_debug("vma start=0x%08lx, size=%ld, ret=%d\n", ++ (unsigned long)vma->vm_start, ++ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, ++ ret); ++ ++ return ret; ++} ++ ++static struct v4l2_file_operations mx6s_csi_fops = { ++ .owner = THIS_MODULE, ++ .open = mx6s_csi_open, ++ .release = mx6s_csi_close, ++ .read = mx6s_csi_read, ++ .poll = vb2_fop_poll, ++ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ ++ .mmap = mx6s_csi_mmap, ++}; ++ ++/* ++ * Video node IOCTLs ++ */ ++static int mx6s_vidioc_enum_input(struct file *file, void *priv, ++ struct v4l2_input *inp) ++{ ++ if (inp->index != 0) ++ return -EINVAL; ++ ++ /* default is camera */ ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ strcpy(inp->name, "Camera"); ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_g_input(struct file *file, void *priv, unsigned int *i) ++{ ++ *i = 0; ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_s_input(struct file *file, void *priv, unsigned int i) ++{ ++ if (i > 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ return v4l2_subdev_call(sd, video, querystd, a); ++} ++ ++static int mx6s_vidioc_s_std(struct file *file, void *priv, v4l2_std_id a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ return v4l2_subdev_call(sd, core, s_std, a); ++} ++ ++static int mx6s_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ return v4l2_subdev_call(sd, core, g_std, a); ++} ++ ++static int mx6s_vidioc_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *p) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ WARN_ON(priv != file->private_data); ++ ++ return vb2_reqbufs(&csi_dev->vb2_vidq, p); ++} ++ ++static int mx6s_vidioc_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *p) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ int ret; ++ ++ WARN_ON(priv != file->private_data); ++ ++ ret = vb2_querybuf(&csi_dev->vb2_vidq, p); ++ ++ if (!ret) { ++ /* return physical address */ ++ struct vb2_buffer *vb = csi_dev->vb2_vidq.bufs[p->index]; ++ if (p->flags & V4L2_BUF_FLAG_MAPPED) ++ p->m.offset = vb2_dma_contig_plane_dma_addr(vb, 0); ++ } ++ return ret; ++} ++ ++static int mx6s_vidioc_qbuf(struct file *file, void *priv, ++ struct v4l2_buffer *p) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ WARN_ON(priv != file->private_data); ++ ++ return vb2_qbuf(&csi_dev->vb2_vidq, p); ++} ++ ++static int mx6s_vidioc_dqbuf(struct file *file, void *priv, ++ struct v4l2_buffer *p) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ WARN_ON(priv != file->private_data); ++ ++ return vb2_dqbuf(&csi_dev->vb2_vidq, p, file->f_flags & O_NONBLOCK); ++} ++ ++static int mx6s_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ enum v4l2_mbus_pixelcode code; ++ struct mx6s_fmt *fmt; ++ int ret; ++ ++ int index = f->index; ++ ++ WARN_ON(priv != file->private_data); ++ ++ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, index, &code); ++ if (ret < 0) ++ /* no more formats */ ++ return -EINVAL; ++ ++ ++ fmt = format_by_mbus(code); ++ if (!fmt) { ++ dev_err(csi_dev->dev, "mbus (0x%08x) invalid.", code); ++ return -EINVAL; ++ } ++ ++ strlcpy(f->description, fmt->name, sizeof(f->description)); ++ f->pixelformat = fmt->pixelformat; ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct v4l2_mbus_framefmt mbus_fmt; ++ struct mx6s_fmt *fmt; ++ int ret; ++ ++ fmt = format_by_fourcc(f->fmt.pix.pixelformat); ++ if (!fmt) { ++ dev_err(csi_dev->dev, "Fourcc format (0x%08x) invalid.", ++ f->fmt.pix.pixelformat); ++ return -EINVAL; ++ } ++ ++ v4l2_fill_mbus_format(&mbus_fmt, pix, fmt->mbus_code); ++ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mbus_fmt); ++ v4l2_fill_pix_format(pix, &mbus_fmt); ++ ++ if (pix->field != V4L2_FIELD_INTERLACED) ++ pix->field = V4L2_FIELD_NONE; ++ ++ pix->sizeimage = fmt->bpp * pix->height * pix->width; ++ pix->bytesperline = fmt->bpp * pix->width; ++ ++ return ret; ++} ++ ++/* ++ * The real work of figuring out a workable format. ++ */ ++ ++static int mx6s_vidioc_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ int ret; ++ ++ ret = mx6s_vidioc_try_fmt_vid_cap(file, csi_dev, f); ++ if (ret < 0) ++ return ret; ++ ++ csi_dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); ++ csi_dev->pix.width = f->fmt.pix.width; ++ csi_dev->pix.height = f->fmt.pix.height; ++ csi_dev->pix.sizeimage = f->fmt.pix.sizeimage; ++ csi_dev->pix.field = f->fmt.pix.field; ++ csi_dev->type = f->type; ++ dev_dbg(csi_dev->dev, "set to pixelformat '%4.6s'\n", ++ (char *)&csi_dev->fmt->name); ++ ++ /* Config csi */ ++ mx6s_configure_csi(csi_dev); ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ WARN_ON(priv != file->private_data); ++ ++ f->fmt.pix = csi_dev->pix; ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ WARN_ON(priv != file->private_data); ++ ++ /* cap->name is set by the friendly caller:-> */ ++ strlcpy(cap->driver, MX6S_CAM_DRV_NAME, sizeof(cap->driver)); ++ strlcpy(cap->card, MX6S_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ++ dev_name(csi_dev->dev)); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ return 0; ++} ++ ++static int mx6s_vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type i) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ int ret; ++ ++ WARN_ON(priv != file->private_data); ++ ++ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ ret = vb2_streamon(&csi_dev->vb2_vidq, i); ++ ++ if (!ret) ++ v4l2_subdev_call(sd, video, s_stream, 1); ++ ++ return ret; ++} ++ ++static int mx6s_vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type i) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ WARN_ON(priv != file->private_data); ++ ++ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ /* ++ * This calls buf_release from host driver's videobuf_queue_ops for all ++ * remaining buffers. When the last buffer is freed, stop capture ++ */ ++ vb2_streamoff(&csi_dev->vb2_vidq, i); ++ ++ v4l2_subdev_call(sd, video, s_stream, 0); ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_cropcap(struct file *file, void *fh, ++ struct v4l2_cropcap *a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ dev_dbg(csi_dev->dev, "VIDIOC_CROPCAP not implemented\n"); ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_g_crop(struct file *file, void *priv, ++ struct v4l2_crop *a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ dev_dbg(csi_dev->dev, "VIDIOC_G_CROP not implemented\n"); ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_s_crop(struct file *file, void *priv, ++ const struct v4l2_crop *a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ ++ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ dev_dbg(csi_dev->dev, "VIDIOC_S_CROP not implemented\n"); ++ ++ return 0; ++} ++ ++static int mx6s_vidioc_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ return v4l2_subdev_call(sd, video, g_parm, a); ++} ++ ++static int mx6s_vidioc_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *a) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ return v4l2_subdev_call(sd, video, s_parm, a); ++} ++ ++static int mx6s_vidioc_enum_framesizes(struct file *file, void *priv, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ return v4l2_subdev_call(sd, video, enum_framesizes, fsize); ++} ++ ++static int mx6s_vidioc_enum_frameintervals(struct file *file, void *priv, ++ struct v4l2_frmivalenum *interval) ++{ ++ struct mx6s_csi_dev *csi_dev = video_drvdata(file); ++ struct v4l2_subdev *sd = csi_dev->sd; ++ ++ return v4l2_subdev_call(sd, video, enum_frameintervals, interval); ++} ++ ++static const struct v4l2_ioctl_ops mx6s_csi_ioctl_ops = { ++ .vidioc_querycap = mx6s_vidioc_querycap, ++ .vidioc_enum_fmt_vid_cap = mx6s_vidioc_enum_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = mx6s_vidioc_try_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = mx6s_vidioc_g_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = mx6s_vidioc_s_fmt_vid_cap, ++ .vidioc_cropcap = mx6s_vidioc_cropcap, ++ .vidioc_s_crop = mx6s_vidioc_s_crop, ++ .vidioc_g_crop = mx6s_vidioc_g_crop, ++ .vidioc_reqbufs = mx6s_vidioc_reqbufs, ++ .vidioc_querybuf = mx6s_vidioc_querybuf, ++ .vidioc_qbuf = mx6s_vidioc_qbuf, ++ .vidioc_dqbuf = mx6s_vidioc_dqbuf, ++ .vidioc_g_std = mx6s_vidioc_g_std, ++ .vidioc_s_std = mx6s_vidioc_s_std, ++ .vidioc_querystd = mx6s_vidioc_querystd, ++ .vidioc_enum_input = mx6s_vidioc_enum_input, ++ .vidioc_g_input = mx6s_vidioc_g_input, ++ .vidioc_s_input = mx6s_vidioc_s_input, ++ .vidioc_streamon = mx6s_vidioc_streamon, ++ .vidioc_streamoff = mx6s_vidioc_streamoff, ++ .vidioc_g_parm = mx6s_vidioc_g_parm, ++ .vidioc_s_parm = mx6s_vidioc_s_parm, ++ .vidioc_enum_framesizes = mx6s_vidioc_enum_framesizes, ++ .vidioc_enum_frameintervals = mx6s_vidioc_enum_frameintervals, ++}; ++ ++static int subdev_notifier_bound(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct mx6s_csi_dev *csi_dev = notifier_to_mx6s_dev(notifier); ++ ++ /* Find platform data for this sensor subdev */ ++ if (csi_dev->asd.match.of.node == subdev->dev->of_node) ++ csi_dev->sd = subdev; ++ ++ if (subdev == NULL) ++ return -EINVAL; ++ ++ v4l2_info(&csi_dev->v4l2_dev, "Registered sensor subdevice: %s\n", ++ subdev->name); ++ ++ return 0; ++} ++ ++static int mx6sx_register_subdevs(struct mx6s_csi_dev *csi_dev) ++{ ++ struct device_node *parent = csi_dev->dev->of_node; ++ struct device_node *node, *port, *rem; ++ int ret; ++ ++ /* Attach sensors linked to csi receivers */ ++ for_each_available_child_of_node(parent, node) { ++ if (of_node_cmp(node->name, "port")) ++ continue; ++ ++ /* The csi node can have only port subnode. */ ++ port = of_get_next_child(node, NULL); ++ if (!port) ++ continue; ++ rem = v4l2_of_get_remote_port_parent(port); ++ of_node_put(port); ++ if (rem == NULL) { ++ v4l2_info(&csi_dev->v4l2_dev, ++ "Remote device at %s not found\n", ++ port->full_name); ++ return -1; ++ } ++ ++ csi_dev->asd.match_type = V4L2_ASYNC_MATCH_OF; ++ csi_dev->asd.match.of.node = rem; ++ csi_dev->async_subdevs[0] = &csi_dev->asd; ++ ++ of_node_put(rem); ++ break; ++ } ++ ++ csi_dev->subdev_notifier.subdevs = csi_dev->async_subdevs; ++ csi_dev->subdev_notifier.num_subdevs = 1; ++ csi_dev->subdev_notifier.bound = subdev_notifier_bound; ++ ++ ret = v4l2_async_notifier_register(&csi_dev->v4l2_dev, ++ &csi_dev->subdev_notifier); ++ if (ret) ++ dev_err(csi_dev->dev, ++ "Error register async notifier regoster\n"); ++ ++ return ret; ++} ++ ++static int mx6s_csi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mx6s_csi_dev *csi_dev; ++ struct video_device *vdev; ++ struct resource *res; ++ int ret = 0; ++ ++ dev_dbg(dev, "initialising\n"); ++ ++ /* Prepare our private structure */ ++ csi_dev = devm_kzalloc(dev, sizeof(struct mx6s_csi_dev), GFP_ATOMIC); ++ if (!csi_dev) { ++ dev_err(dev, "Can't allocate private structure\n"); ++ return -ENODEV; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ csi_dev->irq = platform_get_irq(pdev, 0); ++ if (res == NULL || csi_dev->irq < 0) { ++ dev_err(dev, "Missing platform resources data\n"); ++ return -ENODEV; ++ } ++ ++ csi_dev->regbase = devm_ioremap_resource(dev, res); ++ if (IS_ERR(csi_dev->regbase)) { ++ dev_err(dev, "Failed platform resources map\n"); ++ return -ENODEV; ++ } ++ ++ /* init video dma queues */ ++ INIT_LIST_HEAD(&csi_dev->capture); ++ INIT_LIST_HEAD(&csi_dev->active_bufs); ++ INIT_LIST_HEAD(&csi_dev->discard); ++ ++ csi_dev->clk_disp_axi = devm_clk_get(dev, "disp-axi"); ++ if (IS_ERR(csi_dev->clk_disp_axi)) { ++ dev_err(dev, "Could not get csi axi clock\n"); ++ return -ENODEV; ++ } ++ ++ csi_dev->clk_disp_dcic = devm_clk_get(dev, "disp_dcic"); ++ if (IS_ERR(csi_dev->clk_disp_dcic)) { ++ dev_err(dev, "Could not get disp dcic clock\n"); ++ return -ENODEV; ++ } ++ ++ csi_dev->clk_csi_mclk = devm_clk_get(dev, "csi_mclk"); ++ if (IS_ERR(csi_dev->clk_csi_mclk)) { ++ dev_err(dev, "Could not get csi mclk clock\n"); ++ return -ENODEV; ++ } ++ ++ csi_dev->dev = dev; ++ ++ snprintf(csi_dev->v4l2_dev.name, ++ sizeof(csi_dev->v4l2_dev.name), "CSI"); ++ ++ ret = v4l2_device_register(dev, &csi_dev->v4l2_dev); ++ if (ret < 0) { ++ dev_err(dev, "v4l2_device_register() failed: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ /* initialize locks */ ++ mutex_init(&csi_dev->lock); ++ spin_lock_init(&csi_dev->slock); ++ ++ /* Allocate memory for video device */ ++ vdev = video_device_alloc(); ++ if (vdev == NULL) { ++ ret = -ENOMEM; ++ goto err_vdev; ++ } ++ ++ snprintf(vdev->name, sizeof(vdev->name), "mx6s-csi"); ++ ++ vdev->v4l2_dev = &csi_dev->v4l2_dev; ++ vdev->fops = &mx6s_csi_fops; ++ vdev->ioctl_ops = &mx6s_csi_ioctl_ops; ++ vdev->release = video_device_release; ++ vdev->lock = &csi_dev->lock; ++ ++ vdev->queue = &csi_dev->vb2_vidq; ++ ++ csi_dev->vdev = vdev; ++ ++ video_set_drvdata(csi_dev->vdev, csi_dev); ++ mutex_lock(&csi_dev->lock); ++ ++ ret = video_register_device(csi_dev->vdev, VFL_TYPE_GRABBER, -1); ++ if (ret < 0) { ++ video_device_release(csi_dev->vdev); ++ mutex_unlock(&csi_dev->lock); ++ goto err_vdev; ++ } ++ ++ /* install interrupt handler */ ++ if (devm_request_irq(dev, csi_dev->irq, mx6s_csi_irq_handler, ++ 0, "csi", (void *)csi_dev)) { ++ mutex_unlock(&csi_dev->lock); ++ dev_err(dev, "Request CSI IRQ failed.\n"); ++ ret = -ENODEV; ++ goto err_irq; ++ } ++ ++ mutex_unlock(&csi_dev->lock); ++ ++ ret = mx6sx_register_subdevs(csi_dev); ++ if (ret < 0) ++ goto err_irq; ++ ++ pm_runtime_enable(csi_dev->dev); ++ return 0; ++ ++err_irq: ++ video_unregister_device(csi_dev->vdev); ++err_vdev: ++ v4l2_device_unregister(&csi_dev->v4l2_dev); ++ return ret; ++} ++ ++static int mx6s_csi_remove(struct platform_device *pdev) ++{ ++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); ++ struct mx6s_csi_dev *csi_dev = ++ container_of(v4l2_dev, struct mx6s_csi_dev, v4l2_dev); ++ ++ v4l2_async_notifier_unregister(&csi_dev->subdev_notifier); ++ ++ video_unregister_device(csi_dev->vdev); ++ v4l2_device_unregister(&csi_dev->v4l2_dev); ++ ++ pm_runtime_disable(csi_dev->dev); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_RUNTIME ++static int mx6s_csi_runtime_suspend(struct device *dev) ++{ ++ dev_dbg(dev, "csi v4l2 busfreq high release.\n"); ++ return 0; ++} ++ ++static int mx6s_csi_runtime_resume(struct device *dev) ++{ ++ dev_dbg(dev, "csi v4l2 busfreq high request.\n"); ++ return 0; ++} ++#else ++#define mx6s_csi_runtime_suspend NULL ++#define mx6s_csi_runtime_resume NULL ++#endif ++ ++static const struct dev_pm_ops mx6s_csi_pm_ops = { ++ SET_RUNTIME_PM_OPS(mx6s_csi_runtime_suspend, mx6s_csi_runtime_resume, NULL) ++}; ++ ++static const struct of_device_id mx6s_csi_dt_ids[] = { ++ { .compatible = "fsl,imx6s-csi", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, mx6s_csi_dt_ids); ++ ++static struct platform_driver mx6s_csi_driver = { ++ .driver = { ++ .name = MX6S_CAM_DRV_NAME, ++ .of_match_table = of_match_ptr(mx6s_csi_dt_ids), ++ .pm = &mx6s_csi_pm_ops, ++ }, ++ .probe = mx6s_csi_probe, ++ .remove = mx6s_csi_remove, ++}; ++ ++module_platform_driver(mx6s_csi_driver); ++ ++MODULE_DESCRIPTION("i.MX6Sx SoC Camera Host driver"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(MX6S_CAM_VERSION); +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/subdev/mxc_vadc.c linux-3.14.72/drivers/media/platform/mxc/subdev/mxc_vadc.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/subdev/mxc_vadc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/subdev/mxc_vadc.c 2016-06-19 22:11:55.189147618 +0200 +@@ -0,0 +1,813 @@ ++/* ++ * Copyright (C) 2014-2015 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_vadc.h" ++ ++/* Resource names for the VADC driver. */ ++#define VAFE_REGS_ADDR_RES_NAME "vadc-vafe" ++#define VDEC_REGS_ADDR_RES_NAME "vadc-vdec" ++ ++#define reg32_write(addr, val) __raw_writel(val, addr) ++#define reg32_read(addr) __raw_readl(addr) ++#define reg32setbit(addr, bitpos) \ ++ reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos)))) ++ ++#define reg32clrbit(addr, bitpos) \ ++ reg32_write((addr), (reg32_read((addr)) & (0xFFFFFFFF ^ (1<<(bitpos))))) ++ ++#define GPC_CNTR 0x00 ++#define IMX6SX_GPC_CNTR_VADC_ANALOG_OFF_MASK BIT(17) ++#define IMX6SX_GPC_CNTR_VADC_POWER_DOWN_MASK BIT(18) ++ ++void __iomem *vafe_regbase; ++void __iomem *vdec_regbase; ++ ++ ++/* List of input video formats supported. The video formats is corresponding ++ * with v4l2 id in video_fmt ++ */ ++enum video_fmt_idx { ++ VADC_NTSC = 0, /* Locked on (M) NTSC video signal. */ ++ VADC_PAL, /* (B, G, H, I, N)PAL video signal. */ ++}; ++ ++/* Number of video standards supported (including 'not locked' signal). */ ++#define VADC_STD_MAX (VADC_PAL + 1) ++ ++/* Video format structure. */ ++struct video_fmt{ ++ v4l2_std_id v4l2_std; /* 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 framerates; ++}; ++ ++/* ++ * Maintains the information on the current state of the sensor. ++ */ ++struct vadc_state { ++ struct v4l2_device v4l2_dev; ++ struct v4l2_subdev sd; ++ struct video_fmt *fmt; ++ ++ struct clk *vadc_clk; ++ struct clk *csi_clk; ++ struct regmap *gpr; ++ void __iomem *gpc_reg; ++ ++ u32 vadc_in; ++ u32 csi_id; ++}; ++ ++static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std); ++ ++/* Description of video formats supported. ++ * ++ * PAL: raw=720x625, active=720x576. ++ * NTSC: raw=720x525, active=720x480. ++ */ ++static struct video_fmt video_fmts[] = { ++ /* NTSC */ ++ { ++ .v4l2_std = V4L2_STD_NTSC, ++ .name = "NTSC", ++ .raw_width = 720, ++ .raw_height = 525, ++ .active_width = 720, ++ .active_height = 480, ++ .framerates = 30, ++ }, ++ /* (B, G, H, I, N) PAL */ ++ { ++ .v4l2_std = V4L2_STD_PAL, ++ .name = "PAL", ++ .raw_width = 720, ++ .raw_height = 625, ++ .active_width = 720, ++ .active_height = 576, ++ .framerates = 25, ++ }, ++}; ++ ++static void afe_voltage_clampingmode(void) ++{ ++ reg32_write(AFE_CLAMP, 0x07); ++ reg32_write(AFE_CLMPAMP, 0x60); ++ reg32_write(AFE_CLMPDAT, 0xF0); ++} ++ ++static void afe_alwayson_clampingmode(void) ++{ ++ reg32_write(AFE_CLAMP, 0x15); ++ reg32_write(AFE_CLMPDAT, 0x08); ++ reg32_write(AFE_CLMPAMP, 0x00); ++} ++ ++static void afe_init(void) ++{ ++ pr_debug("%s\n", __func__); ++ ++ reg32_write(AFE_PDBUF, 0x1f); ++ reg32_write(AFE_PDADC, 0x0f); ++ reg32_write(AFE_PDSARH, 0x01); ++ reg32_write(AFE_PDSARL, 0xff); ++ reg32_write(AFE_PDADCRFH, 0x01); ++ reg32_write(AFE_PDADCRFL, 0xff); ++ reg32_write(AFE_ICTRL, 0x3a); ++ reg32_write(AFE_ICTLSTG, 0x1e); ++ ++ reg32_write(AFE_RCTRLSTG, 0x1e); ++ reg32_write(AFE_INPBUF, 0x035); ++ reg32_write(AFE_INPFLT, 0x02); ++ reg32_write(AFE_ADCDGN, 0x40); ++ reg32_write(AFE_TSTSEL, 0x10); ++ ++ reg32_write(AFE_ACCTST, 0x07); ++ ++ reg32_write(AFE_BGREG, 0x08); ++ ++ reg32_write(AFE_ADCGN, 0x09); ++ ++ /* set current controlled clamping ++ * always on, low current */ ++ reg32_write(AFE_CLAMP, 0x11); ++ reg32_write(AFE_CLMPAMP, 0x08); ++} ++ ++static void vdec_mode_timing_init(int std) ++{ ++ if (std == V4L2_STD_NTSC) { ++ /* NTSC 720x480 */ ++ reg32_write(VDEC_HACTS, 0x66); ++ reg32_write(VDEC_HACTE, 0x24); ++ ++ reg32_write(VDEC_VACTS, 0x29); ++ reg32_write(VDEC_VACTE, 0x04); ++ ++ /* set V Position */ ++ reg32_write(VDEC_VRTPOS, 0x2); ++ } else if (std == V4L2_STD_PAL) { ++ /* PAL 720x576 */ ++ reg32_write(VDEC_HACTS, 0x66); ++ reg32_write(VDEC_HACTE, 0x24); ++ ++ reg32_write(VDEC_VACTS, 0x29); ++ reg32_write(VDEC_VACTE, 0x04); ++ ++ /* set V Position */ ++ reg32_write(VDEC_VRTPOS, 0x6); ++ } else ++ pr_debug("Error not support video mode\n"); ++ ++ /* set H Position */ ++ reg32_write(VDEC_HZPOS, 0x60); ++ ++ /* set H ignore start */ ++ reg32_write(VDEC_HSIGS, 0xf8); ++ ++ /* set H ignore end */ ++ reg32_write(VDEC_HSIGE, 0x18); ++} ++ ++/* ++* vdec_init() ++* Initialises the VDEC registers ++* Returns: nothing ++*/ ++static void vdec_init(struct vadc_state *vadc) ++{ ++ v4l2_std_id std; ++ ++ pr_debug("%s\n", __func__); ++ ++ /* Get work mode PAL or NTSC */ ++ vadc_querystd(&vadc->sd, &std); ++ ++ vdec_mode_timing_init(std); ++ ++ /* vcr detect threshold high, automatic detections */ ++ reg32_write(VDEC_VSCON2, 0); ++ ++ reg32_write(VDEC_BASE + 0x110, 0x01); ++ ++ /* set the noramp mode on the Hloop PLL. */ ++ reg32_write(VDEC_BASE+(0x14*4), 0x10); ++ ++ /* set the YC relative delay.*/ ++ reg32_write(VDEC_YCDEL, 0x90); ++ ++ /* setup the Hpll */ ++ reg32_write(VDEC_BASE+(0x13*4), 0x13); ++ ++ /* setup the 2d comb */ ++ /* set the gain of the Hdetail output to 3 ++ * set the notch alpha gain to 1 */ ++ reg32_write(VDEC_CFC2, 0x34); ++ ++ /* setup various 2d comb bits.*/ ++ reg32_write(VDEC_BASE+(0x02*4), 0x01); ++ reg32_write(VDEC_BASE+(0x03*4), 0x18); ++ reg32_write(VDEC_BASE+(0x04*4), 0x34); ++ ++ /* set the start of the burst gate */ ++ reg32_write(VDEC_BRSTGT, 0x30); ++ ++ /* set 1f motion gain */ ++ reg32_write(VDEC_BASE+(0x0f*4), 0x20); ++ ++ /* set the 1F chroma motion detector thresh ++ * for colour reverse detection */ ++ reg32_write(VDEC_THSH1, 0x02); ++ reg32_write(VDEC_BASE+(0x4a*4), 0x20); ++ reg32_write(VDEC_BASE+(0x4b*4), 0x08); ++ ++ reg32_write(VDEC_BASE+(0x4c*4), 0x08); ++ ++ /* set the threshold for the narrow/wide adaptive chroma BW */ ++ reg32_write(VDEC_BASE+(0x20*4), 0x20); ++ ++ /* turn up the colour with the new colour gain reg */ ++ /* hue: */ ++ reg32_write(VDEC_HUE, 0x00); ++ ++ /* cbgain: 22 B4 */ ++ reg32_write(VDEC_CBGN, 0xb4); ++ /* cr gain 80 */ ++ reg32_write(VDEC_CRGN, 0x80); ++ /* luma gain (contrast) */ ++ reg32_write(VDEC_CNTR, 0x80); ++ ++ /* setup the signed black level register, brightness */ ++ reg32_write(VDEC_BRT, 0x00); ++ ++ /* filter the standard detection ++ * enable the comb for the ntsc443 */ ++ reg32_write(VDEC_STDDBG, 0x20); ++ ++ /* setup chroma kill thresh for no chroma */ ++ reg32_write(VDEC_CHBTH, 0x0); ++ ++ /* set chroma loop to wider BW ++ * no set it to normal BW. i fixed the bw problem.*/ ++ reg32_write(VDEC_YCDEL, 0x00); ++ ++ /* set the compensation in the chroma loop for the Hloop ++ * set the ratio for the nonarithmetic 3d comb modes.*/ ++ reg32_write(VDEC_BASE + (0x1d*4), 0x90); ++ ++ /* set the threshold for the nonarithmetic mode for the 2d comb ++ * the higher the value the more Fc Fh offset ++ * we will tolerate before turning off the comb. */ ++ reg32_write(VDEC_BASE + (0x33*4), 0xa0); ++ ++ /* setup the bluescreen output colour */ ++ reg32_write(VDEC_BASE + (0x3d*4), 35); ++ reg32_write(VDEC_BLSCRCR, 114); ++ reg32_write(VDEC_BLSCRCB, 212); ++ ++ /* disable the active blanking */ ++ reg32_write(VDEC_BASE + (0x15*4), 0x02); ++ ++ /* setup the luma agc for automatic gain. */ ++ reg32_write(VDEC_LMAGC2, 0x5e); ++ reg32_write(VDEC_LMAGC1, 0x81); ++ ++ /* setup chroma agc */ ++ reg32_write(VDEC_CHAGC2, 0xa0); ++ reg32_write(VDEC_CHAGC1, 0x01); ++ ++ /* setup the MV thresh lower nibble ++ * setup the sync top cap, upper nibble */ ++ reg32_write(VDEC_BASE + (0x3a*4), 0x80); ++ reg32_write(VDEC_SHPIMP, 0x00); ++ ++ /* setup the vsync block */ ++ reg32_write(VDEC_VSCON1, 0x87); ++ ++ /* set the nosignal threshold ++ * set the vsync threshold */ ++ reg32_write(VDEC_VSSGTH, 0x35); ++ ++ /* set length for min hphase filter ++ * (or saturate limit if saturate is chosen) */ ++ reg32_write(VDEC_BASE + (0x45*4), 0x40); ++ ++ /* enable the internal resampler, ++ * select min filter not saturate for ++ * hphase noise filter for vcr detect. ++ * enable vcr pause mode different field lengths */ ++ reg32_write(VDEC_BASE + (0x46*4), 0x90); ++ ++ /* disable VCR detection, lock to the Hsync rather than the Vsync */ ++ reg32_write(VDEC_VSCON2, 0x04); ++ ++ /* set tiplevel goal for dc clamp. */ ++ reg32_write(VDEC_BASE + (0x3c*4), 0xB0); ++ ++ /* override SECAM detection and force SECAM off */ ++ reg32_write(VDEC_BASE + (0x2f*4), 0x20); ++ ++ /* Set r3d_hardblend in 3D control2 reg */ ++ reg32_write(VDEC_BASE + (0x0c*4), 0x04); ++} ++ ++/* set Input selector & input pull-downs */ ++static void vadc_s_routing(int vadc_in) ++{ ++ switch (vadc_in) { ++ case 0: ++ reg32_write(AFE_INPFLT, 0x02); ++ reg32_write(AFE_OFFDRV, 0x00); ++ reg32_write(AFE_INPCONFIG, 0x1e); ++ break; ++ case 1: ++ reg32_write(AFE_INPFLT, 0x02); ++ reg32_write(AFE_OFFDRV, 0x00); ++ reg32_write(AFE_INPCONFIG, 0x2d); ++ break; ++ case 2: ++ reg32_write(AFE_INPFLT, 0x02); ++ reg32_write(AFE_OFFDRV, 0x00); ++ reg32_write(AFE_INPCONFIG, 0x4b); ++ break; ++ case 3: ++ reg32_write(AFE_INPFLT, 0x02); ++ reg32_write(AFE_OFFDRV, 0x00); ++ reg32_write(AFE_INPCONFIG, 0x87); ++ break; ++ default: ++ pr_debug("error video input %d\n", vadc_in); ++ } ++} ++ ++static void vadc_power_up(struct vadc_state *state) ++{ ++ /* Power on vadc analog */ ++ reg32clrbit(state->gpc_reg + GPC_CNTR, 17); ++ ++ /* Power down vadc ext power */ ++ reg32clrbit(state->gpc_reg + GPC_CNTR, 18); ++ ++ /* software reset afe */ ++ regmap_update_bits(state->gpr, IOMUXC_GPR1, ++ IMX6SX_GPR1_VADC_SW_RST_MASK, ++ IMX6SX_GPR1_VADC_SW_RST_RESET); ++ ++ msleep(10); ++ ++ /* clock config for vadc */ ++ reg32_write(VDEC_BASE + 0x320, 0xe3); ++ reg32_write(VDEC_BASE + 0x324, 0x38); ++ reg32_write(VDEC_BASE + 0x328, 0x8e); ++ reg32_write(VDEC_BASE + 0x32c, 0x23); ++ ++ /* Release reset bit */ ++ regmap_update_bits(state->gpr, IOMUXC_GPR1, ++ IMX6SX_GPR1_VADC_SW_RST_MASK, ++ IMX6SX_GPR1_VADC_SW_RST_RELEASE); ++ ++ /* Power on vadc ext power */ ++ reg32setbit(state->gpc_reg + GPC_CNTR, 18); ++} ++ ++static void vadc_power_down(struct vadc_state *state) ++{ ++ /* Power down vadc analog */ ++ reg32setbit(state->gpc_reg + GPC_CNTR, 17); ++ ++ /* Power down vadc ext power */ ++ reg32clrbit(state->gpc_reg + GPC_CNTR, 18); ++ ++} ++static void vadc_init(struct vadc_state *vadc) ++{ ++ pr_debug("%s\n", __func__); ++ ++ vadc_power_up(vadc); ++ ++ afe_init(); ++ ++ /* select Video Input 0-3 */ ++ vadc_s_routing(vadc->vadc_in); ++ ++ afe_voltage_clampingmode(); ++ ++ vdec_init(vadc); ++ ++ /* ++ * current control loop will move sinewave input off below ++ * the bottom of the signal range visible ++ * when the testbus is viewed as magnitude, ++ * so have to break before this point while capturing ENOB data: ++ */ ++ afe_alwayson_clampingmode(); ++} ++ ++static inline struct vadc_state *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct vadc_state, sd); ++} ++ ++static int vadc_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) ++{ ++ struct vadc_state *state = to_state(sd); ++ ++ *std = state->fmt->v4l2_std; ++ return 0; ++} ++ ++/*! ++ * 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 int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) ++{ ++ struct vadc_state *state = to_state(sd); ++ int mod; ++ int idx; ++ int i; ++ ++ /* Read auto mode detected result */ ++ printk(KERN_INFO"wait vadc auto detect video mode....\n"); ++ for (i = 0; i < 10; i++) { ++ msleep(200); ++ mod = reg32_read(VDEC_VIDMOD); ++ /* Check video signal states */ ++ if ((mod & VDEC_VIDMOD_SIGNAL_MASK) ++ == VDEC_VIDMOD_SIGNAL_DETECT) ++ break; ++ } ++ if (i == 10) ++ printk(KERN_INFO"Timeout detect video signal mod=0x%x\n", mod); ++ ++ if ((mod & VDEC_VIDMOD_PAL_MASK) || (mod & VDEC_VIDMOD_M625_MASK)) ++ idx = VADC_PAL; ++ else ++ idx = VADC_NTSC; ++ ++ *std = video_fmts[idx].v4l2_std; ++ state->fmt = &video_fmts[idx]; ++ ++ printk(KERN_INFO"video mode %s\n", video_fmts[idx].name); ++ return 0; ++} ++ ++static int vadc_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, ++ enum v4l2_mbus_pixelcode *code) ++{ ++ /* support only one format */ ++ if (index >= 1) ++ return -EINVAL; ++ ++ *code = V4L2_MBUS_FMT_AYUV8_1X32; ++ return 0; ++} ++ ++static int vadc_mbus_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct vadc_state *state = to_state(sd); ++ ++ fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; ++ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ fmt->field = V4L2_FIELD_INTERLACED; ++ fmt->width = 720; ++ fmt->height = state->fmt->v4l2_std & V4L2_STD_NTSC ? 480 : 576; ++ ++ return 0; ++} ++ ++static int vadc_enum_framesizes(struct v4l2_subdev *sd, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct vadc_state *state = to_state(sd); ++ if (fsize->index >= 1) ++ return -EINVAL; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ fsize->discrete.width = state->fmt->active_width; ++ fsize->discrete.height = state->fmt->active_height; ++ ++ return 0; ++} ++static int vadc_enum_frameintervals(struct v4l2_subdev *sd, ++ struct v4l2_frmivalenum *fival) ++{ ++ struct vadc_state *state = to_state(sd); ++ ++ if (fival->index < 0 || fival->index >= 1) ++ return -EINVAL; ++ ++ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; ++ fival->discrete.numerator = 1; ++ ++ fival->discrete.denominator = state->fmt->framerates; ++ ++ return 0; ++} ++ ++static int vadc_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct vadc_state *state = to_state(sd); ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ if (parms->parm.capture.timeperframe.denominator ++ != state->fmt->framerates) ++ parms->parm.capture.timeperframe.denominator ++ = state->fmt->framerates; ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_video_ops vadc_video_ops = { ++ .querystd = vadc_querystd, ++ .enum_mbus_fmt = vadc_enum_mbus_fmt, ++ .try_mbus_fmt = vadc_mbus_fmt, ++ .g_mbus_fmt = vadc_mbus_fmt, ++ .enum_framesizes = vadc_enum_framesizes, ++ .enum_frameintervals = vadc_enum_frameintervals, ++ .s_parm = vadc_s_parm, ++}; ++ ++static const struct v4l2_subdev_core_ops vadc_core_ops = { ++ .g_std = vadc_g_std, ++}; ++ ++static const struct v4l2_subdev_ops vadc_ops = { ++ .core = &vadc_core_ops, ++ .video = &vadc_video_ops, ++}; ++ ++static const struct of_device_id fsl_vadc_dt_ids[] = { ++ { .compatible = "fsl,imx6sx-vadc", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, fsl_vadc_dt_ids); ++ ++static int vadc_of_init(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *gpc_np; ++ struct vadc_state *state = platform_get_drvdata(pdev); ++ int csi_id; ++ int ret; ++ ++ /* Get csi_id to setting vadc to csi mux in gpr */ ++ ret = of_property_read_u32(np, "csi_id", &csi_id); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to read of property csi_id\n"); ++ return ret; ++ } ++ ++ state->csi_id = csi_id; ++ ++ /* remap GPR register */ ++ state->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, ++ "gpr"); ++ if (IS_ERR(state->gpr)) { ++ dev_dbg(&pdev->dev, "can not get gpr\n"); ++ return -ENOMEM; ++ } ++ ++ /* Configuration vadc-to-csi 0 or 1 */ ++ if (csi_id) { ++ regmap_update_bits(state->gpr, IOMUXC_GPR5, ++ IMX6SX_GPR5_CSI2_MUX_CTRL_MASK, ++ IMX6SX_GPR5_CSI2_MUX_CTRL_CVD); ++ } else { ++ regmap_update_bits(state->gpr, IOMUXC_GPR5, ++ IMX6SX_GPR5_CSI1_MUX_CTRL_MASK, ++ IMX6SX_GPR5_CSI1_MUX_CTRL_CVD); ++ } ++ ++ /* Get default vadc_in number */ ++ ret = of_property_read_u32(np, "vadc_in", &state->vadc_in); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to read of property vadc_in\n"); ++ return ret; ++ } ++ ++ /* map GPC register */ ++ gpc_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); ++ state->gpc_reg = of_iomap(gpc_np, 0); ++ if (!state->gpc_reg) { ++ dev_err(&pdev->dev, "ioremap failed with gpc base\n"); ++ goto error; ++ } ++ ++ return ret; ++ ++error: ++ iounmap(state->gpc_reg); ++ return ret; ++} ++ ++static void vadc_v4l2_subdev_init(struct v4l2_subdev *sd, ++ struct platform_device *pdev, ++ const struct v4l2_subdev_ops *ops) ++{ ++ struct vadc_state *state = platform_get_drvdata(pdev); ++ int ret = 0; ++ ++ v4l2_subdev_init(sd, ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ sd->owner = pdev->dev.driver->owner; ++ sd->dev = &pdev->dev; ++ ++ /* initialize name */ ++ snprintf(sd->name, sizeof(sd->name), "%s", ++ pdev->dev.driver->name); ++ ++ v4l2_set_subdevdata(sd, state); ++ ++ ret = v4l2_async_register_subdev(sd); ++ if (ret < 0) ++ dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret); ++} ++ ++static int vadc_probe(struct platform_device *pdev) ++{ ++ struct vadc_state *state; ++ struct v4l2_subdev *sd; ++ struct resource *res; ++ int ret = 0; ++ ++ state = devm_kzalloc(&pdev->dev, sizeof(struct vadc_state), GFP_KERNEL); ++ if (!state) { ++ dev_err(&pdev->dev, "Cannot allocate device data\n"); ++ return -ENOMEM; ++ } ++ ++ /* Set initial values for the sensor struct. */ ++ state->fmt = &video_fmts[VADC_NTSC]; ++ ++ sd = &state->sd; ++ ++ /* map vafe address */ ++ res = platform_get_resource_byname(pdev, ++ IORESOURCE_MEM, VAFE_REGS_ADDR_RES_NAME); ++ if (!res) { ++ dev_err(&pdev->dev, "No vafe base address found.\n"); ++ return -ENOMEM; ++ } ++ vafe_regbase = devm_ioremap_resource(&pdev->dev, res); ++ if (!vafe_regbase) { ++ dev_err(&pdev->dev, "ioremap failed with vafe base\n"); ++ return -ENOMEM; ++ } ++ ++ /* map vdec address */ ++ res = platform_get_resource_byname(pdev, ++ IORESOURCE_MEM, VDEC_REGS_ADDR_RES_NAME); ++ if (!res) { ++ dev_err(&pdev->dev, "No vdec base address found.\n"); ++ return -ENODEV; ++ } ++ vdec_regbase = devm_ioremap_resource(&pdev->dev, res); ++ if (!vdec_regbase) { ++ dev_err(&pdev->dev, "ioremap failed with vdec base\n"); ++ return -ENOMEM; ++ } ++ ++ /* Get clock */ ++ state->vadc_clk = devm_clk_get(&pdev->dev, "vadc"); ++ if (IS_ERR(state->vadc_clk)) { ++ ret = PTR_ERR(state->vadc_clk); ++ return ret; ++ } ++ ++ state->csi_clk = devm_clk_get(&pdev->dev, "csi"); ++ if (IS_ERR(state->csi_clk)) { ++ ret = PTR_ERR(state->csi_clk); ++ return ret; ++ } ++ ++ /* clock */ ++ clk_prepare_enable(state->csi_clk); ++ clk_prepare_enable(state->vadc_clk); ++ ++ platform_set_drvdata(pdev, state); ++ ++ vadc_v4l2_subdev_init(sd, pdev, &vadc_ops); ++ ++ pm_runtime_enable(&pdev->dev); ++ ++ pm_runtime_get_sync(&pdev->dev); ++ /* Init VADC */ ++ ret = vadc_of_init(pdev); ++ if (ret < 0) ++ goto err; ++ vadc_init(state); ++ ++ pr_info("vadc driver loaded\n"); ++ ++ return 0; ++err: ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ v4l2_async_unregister_subdev(&state->sd); ++ clk_disable_unprepare(state->csi_clk); ++ clk_disable_unprepare(state->vadc_clk); ++ return ret; ++} ++ ++static int vadc_remove(struct platform_device *pdev) ++{ ++ struct vadc_state *state = platform_get_drvdata(pdev); ++ ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ v4l2_async_unregister_subdev(&state->sd); ++ clk_disable_unprepare(state->csi_clk); ++ clk_disable_unprepare(state->vadc_clk); ++ ++ vadc_power_down(state); ++ return true; ++} ++ ++static int vadc_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct vadc_state *state = platform_get_drvdata(pdev); ++ ++ clk_disable(state->csi_clk); ++ clk_disable(state->vadc_clk); ++ ++ vadc_power_down(state); ++ ++ return 0; ++} ++ ++static int vadc_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct vadc_state *state = platform_get_drvdata(pdev); ++ ++ clk_enable(state->csi_clk); ++ clk_enable(state->vadc_clk); ++ ++ vadc_init(state); ++ return 0; ++} ++ ++static const struct dev_pm_ops vadc_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(vadc_suspend, vadc_resume) ++}; ++ ++static struct platform_driver vadc_driver = { ++ .driver = { ++ .name = "fsl_vadc", ++ .of_match_table = of_match_ptr(fsl_vadc_dt_ids), ++ .pm = &vadc_pm_ops, ++ }, ++ .probe = vadc_probe, ++ .remove = vadc_remove, ++}; ++ ++module_platform_driver(vadc_driver); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("fsl VADC/VDEC driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/subdev/mxc_vadc.h linux-3.14.72/drivers/media/platform/mxc/subdev/mxc_vadc.h +--- linux-3.14.72.orig/drivers/media/platform/mxc/subdev/mxc_vadc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/subdev/mxc_vadc.h 2016-06-19 22:11:55.189147618 +0200 +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (C) 2011-2015 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 ++ * ++ */ ++ ++#ifndef MXC_VDEC_H ++#define MXC_VDEC_H ++ ++/*** define base address ***/ ++#define VDEC_BASE vdec_regbase ++#define AFE_BASE vafe_regbase ++ ++/* AFE - Register offsets */ ++#define AFE_BLOCK_ID_OFFSET 0x00000000 ++#define AFE_PDBUF_OFFSET 0x00000004 ++#define AFE_SWRST_OFFSET 0x00000008 ++#define AFE_TSTSEL_OFFSET 0x0000000c ++#define AFE_TSTMSC_OFFSET 0x00000010 ++#define AFE_ENPADIO_OFFSET 0x00000014 ++#define AFE_BGREG_OFFSET 0x00000018 ++#define AFE_ACCESSAR_ID_OFFSET 0x00000400 ++#define AFE_PDADC_OFFSET 0x00000404 ++#define AFE_PDSARH_OFFSET 0x00000408 ++#define AFE_PDSARL_OFFSET 0x0000040C ++#define AFE_PDADCRFH_OFFSET 0x00000410 ++#define AFE_PDADCRFL_OFFSET 0x00000414 ++#define AFE_ACCTST_OFFSET 0x00000418 ++#define AFE_ADCGN_OFFSET 0x0000041C ++#define AFE_ICTRL_OFFSET 0x00000420 ++#define AFE_ICTLSTG_OFFSET 0x00000424 ++#define AFE_RCTRLSTG_OFFSET 0x00000428 ++#define AFE_TCTRLSTG_OFFSET 0x0000042c ++#define AFE_REFMOD_OFFSET 0x00000430 ++#define AFE_REFTRIML_OFFSET 0x00000434 ++#define AFE_REFTRIMH_OFFSET 0x00000438 ++#define AFE_ADCR_OFFSET 0x0000043c ++#define AFE_DUMMY0_OFFSET 0x00000440 ++#define AFE_DUMMY1_OFFSET 0x00000444 ++#define AFE_DUMMY2_OFFSET 0x00000448 ++#define AFE_DACAMP_OFFSET 0x0000044c ++#define AFE_CLMPTST_OFFSET 0x00000450 ++#define AFE_CLMPDAT_OFFSET 0x00000454 ++#define AFE_CLMPAMP_OFFSET 0x00000458 ++#define AFE_CLAMP_OFFSET 0x0000045c ++#define AFE_INPBUF_OFFSET 0x00000460 ++#define AFE_INPFLT_OFFSET 0x00000464 ++#define AFE_ADCDGN_OFFSET 0x00000468 ++#define AFE_OFFDRV_OFFSET 0x0000046c ++#define AFE_INPCONFIG_OFFSET 0x00000470 ++#define AFE_PROGDELAY_OFFSET 0x00000474 ++#define AFE_ADCOMT_OFFSET 0x00000478 ++#define AFE_ALGDELAY_OFFSET 0x0000047c ++#define AFE_ACC_ID_OFFSET 0x00000800 ++#define AFE_ACCSTA_OFFSET 0x00000804 ++#define AFE_ACCNOSLI_OFFSET 0x00000808 ++#define AFE_ACCCALCON_OFFSET 0x0000080c ++#define AFE_BWEWRICTRL_OFFSET 0x00000810 ++#define AFE_SELSLI_OFFSET 0x00000814 ++#define AFE_SELBYT_OFFSET 0x00000818 ++#define AFE_REDVAL_OFFSET 0x00000820 ++#define AFE_WRIBYT_OFFSET 0x00000824 ++ ++/* AFE Register per module */ ++#define AFE_BLOCK_ID (AFE_BASE + AFE_BLOCK_ID_OFFSET) ++#define AFE_PDBUF (AFE_BASE + AFE_PDBUF_OFFSET) ++#define AFE_SWRST (AFE_BASE + AFE_SWRST_OFFSET) ++#define AFE_TSTSEL (AFE_BASE + AFE_TSTSEL_OFFSET) ++#define AFE_TSTMSC (AFE_BASE + AFE_TSTMSC_OFFSET) ++#define AFE_ENPADIO (AFE_BASE + AFE_ENPADIO_OFFSET) ++#define AFE_BGREG (AFE_BASE + AFE_BGREG_OFFSET) ++#define AFE_ACCESSAR_ID (AFE_BASE + AFE_ACCESSAR_ID_OFFSET) ++#define AFE_PDADC (AFE_BASE + AFE_PDADC_OFFSET) ++#define AFE_PDSARH (AFE_BASE + AFE_PDSARH_OFFSET) ++#define AFE_PDSARL (AFE_BASE + AFE_PDSARL_OFFSET) ++#define AFE_PDADCRFH (AFE_BASE + AFE_PDADCRFH_OFFSET) ++#define AFE_PDADCRFL (AFE_BASE + AFE_PDADCRFL_OFFSET) ++#define AFE_ACCTST (AFE_BASE + AFE_ACCTST_OFFSET) ++#define AFE_ADCGN (AFE_BASE + AFE_ADCGN_OFFSET) ++#define AFE_ICTRL (AFE_BASE + AFE_ICTRL_OFFSET) ++#define AFE_ICTLSTG (AFE_BASE + AFE_ICTLSTG_OFFSET) ++#define AFE_RCTRLSTG (AFE_BASE + AFE_RCTRLSTG_OFFSET) ++#define AFE_TCTRLSTG (AFE_BASE + AFE_TCTRLSTG_OFFSET) ++#define AFE_REFMOD (AFE_BASE + AFE_REFMOD_OFFSET) ++#define AFE_REFTRIML (AFE_BASE + AFE_REFTRIML_OFFSET) ++#define AFE_REFTRIMH (AFE_BASE + AFE_REFTRIMH_OFFSET) ++#define AFE_ADCR (AFE_BASE + AFE_ADCR_OFFSET) ++#define AFE_DUMMY0 (AFE_BASE + AFE_DUMMY0_OFFSET) ++#define AFE_DUMMY1 (AFE_BASE + AFE_DUMMY1_OFFSET) ++#define AFE_DUMMY2 (AFE_BASE + AFE_DUMMY2_OFFSET) ++#define AFE_DACAMP (AFE_BASE + AFE_DACAMP_OFFSET) ++#define AFE_CLMPTST (AFE_BASE + AFE_CLMPTST_OFFSET) ++#define AFE_CLMPDAT (AFE_BASE + AFE_CLMPDAT_OFFSET) ++#define AFE_CLMPAMP (AFE_BASE + AFE_CLMPAMP_OFFSET) ++#define AFE_CLAMP (AFE_BASE + AFE_CLAMP_OFFSET) ++#define AFE_INPBUF (AFE_BASE + AFE_INPBUF_OFFSET) ++#define AFE_INPFLT (AFE_BASE + AFE_INPFLT_OFFSET) ++#define AFE_ADCDGN (AFE_BASE + AFE_ADCDGN_OFFSET) ++#define AFE_OFFDRV (AFE_BASE + AFE_OFFDRV_OFFSET) ++#define AFE_INPCONFIG (AFE_BASE + AFE_INPCONFIG_OFFSET) ++#define AFE_PROGDELAY (AFE_BASE + AFE_PROGDELAY_OFFSET) ++#define AFE_ADCOMT (AFE_BASE + AFE_ADCOMT_OFFSET) ++#define AFE_ALGDELAY (AFE_BASE + AFE_ALGDELAY_OFFSET) ++#define AFE_ACC_ID (AFE_BASE + AFE_ACC_ID_OFFSET) ++#define AFE_ACCSTA (AFE_BASE + AFE_ACCSTA_OFFSET) ++#define AFE_ACCNOSLI (AFE_BASE + AFE_ACCNOSLI_OFFSET) ++#define AFE_ACCCALCON (AFE_BASE + AFE_ACCCALCON_OFFSET) ++#define AFE_BWEWRICTRL (AFE_BASE + AFE_BWEWRICTRL_OFFSET) ++#define AFE_SELSLI (AFE_BASE + AFE_SELSLI_OFFSET) ++#define AFE_SELBYT (AFE_BASE + AFE_SELBYT_OFFSET) ++#define AFE_REDVAL (AFE_BASE + AFE_REDVAL_OFFSET) ++#define AFE_WRIBYT (AFE_BASE + AFE_WRIBYT_OFFSET) ++ ++/* VDEC - Register offsets */ ++#define VDEC_CFC1_OFFSET 0x00000000 ++#define VDEC_CFC2_OFFSET 0x00000004 ++#define VDEC_BRSTGT_OFFSET 0x00000024 ++#define VDEC_HZPOS_OFFSET 0x00000040 ++#define VDEC_VRTPOS_OFFSET 0x00000044 ++#define VDEC_HVSHIFT_OFFSET 0x00000054 ++#define VDEC_HSIGS_OFFSET 0x00000058 ++#define VDEC_HSIGE_OFFSET 0x0000005C ++#define VDEC_VSCON1_OFFSET 0x00000060 ++#define VDEC_VSCON2_OFFSET 0x00000064 ++#define VDEC_YCDEL_OFFSET 0x0000006C ++#define VDEC_AFTCLP_OFFSET 0x00000070 ++#define VDEC_DCOFF_OFFSET 0x00000078 ++#define VDEC_CSID_OFFSET 0x00000084 ++#define VDEC_CBGN_OFFSET 0x00000088 ++#define VDEC_CRGN_OFFSET 0x0000008C ++#define VDEC_CNTR_OFFSET 0x00000090 ++#define VDEC_BRT_OFFSET 0x00000094 ++#define VDEC_HUE_OFFSET 0x00000098 ++#define VDEC_CHBTH_OFFSET 0x0000009C ++#define VDEC_SHPIMP_OFFSET 0x000000A4 ++#define VDEC_CHPLLIM_OFFSET 0x000000A8 ++#define VDEC_VIDMOD_OFFSET 0x000000AC ++#define VDEC_VIDSTS_OFFSET 0x000000B0 ++#define VDEC_NOISE_OFFSET 0x000000B4 ++#define VDEC_STDDBG_OFFSET 0x000000B8 ++#define VDEC_MANOVR_OFFSET 0x000000BC ++#define VDEC_VSSGTH_OFFSET 0x000000C8 ++#define VDEC_DBGFBH_OFFSET 0x000000D0 ++#define VDEC_DBGFBL_OFFSET 0x000000D4 ++#define VDEC_HACTS_OFFSET 0x000000D8 ++#define VDEC_HACTE_OFFSET 0x000000DC ++#define VDEC_VACTS_OFFSET 0x000000E0 ++#define VDEC_VACTE_OFFSET 0x000000E4 ++#define VDEC_HSTIP_OFFSET 0x000000EC ++#define VDEC_BLSCRY_OFFSET 0x000000F4 ++#define VDEC_BLSCRCR_OFFSET 0x000000F8 ++#define VDEC_BLSCRCB_OFFSET 0x000000FC ++#define VDEC_LMAGC1_OFFSET 0x00000100 ++#define VDEC_LMAGC2_OFFSET 0x00000104 ++#define VDEC_CHAGC1_OFFSET 0x00000108 ++#define VDEC_CHAGC2_OFFSET 0x0000010C ++#define VDEC_MINTH_OFFSET 0x00000114 ++#define VDEC_VFRQOH_OFFSET 0x0000011C ++#define VDEC_VFRQOL_OFFSET 0x00000120 ++#define VDEC_THSH1_OFFSET 0x00000124 ++#define VDEC_THSH2_OFFSET 0x00000128 ++#define VDEC_NCHTH_OFFSET 0x0000012C ++#define VDEC_TH1F_OFFSET 0x00000130 ++ ++/* VDEC Register per module */ ++#define VDEC_CFC1 (VDEC_BASE + VDEC_CFC1_OFFSET) ++#define VDEC_CFC2 (VDEC_BASE + VDEC_CFC2_OFFSET) ++#define VDEC_BRSTGT (VDEC_BASE + VDEC_BRSTGT_OFFSET) ++#define VDEC_HZPOS (VDEC_BASE + VDEC_HZPOS_OFFSET) ++#define VDEC_VRTPOS (VDEC_BASE + VDEC_VRTPOS_OFFSET) ++#define VDEC_HVSHIFT (VDEC_BASE + VDEC_HVSHIFT_OFFSET) ++#define VDEC_HSIGS (VDEC_BASE + VDEC_HSIGS_OFFSET) ++#define VDEC_HSIGE (VDEC_BASE + VDEC_HSIGE_OFFSET) ++#define VDEC_VSCON1 (VDEC_BASE + VDEC_VSCON1_OFFSET) ++#define VDEC_VSCON2 (VDEC_BASE + VDEC_VSCON2_OFFSET) ++#define VDEC_YCDEL (VDEC_BASE + VDEC_YCDEL_OFFSET) ++#define VDEC_AFTCLP (VDEC_BASE + VDEC_AFTCLP_OFFSET) ++#define VDEC_DCOFF (VDEC_BASE + VDEC_DCOFF_OFFSET) ++#define VDEC_CSID (VDEC_BASE + VDEC_CSID_OFFSET) ++#define VDEC_CBGN (VDEC_BASE + VDEC_CBGN_OFFSET) ++#define VDEC_CRGN (VDEC_BASE + VDEC_CRGN_OFFSET) ++#define VDEC_CNTR (VDEC_BASE + VDEC_CNTR_OFFSET) ++#define VDEC_BRT (VDEC_BASE + VDEC_BRT_OFFSET) ++#define VDEC_HUE (VDEC_BASE + VDEC_HUE_OFFSET) ++#define VDEC_CHBTH (VDEC_BASE + VDEC_CHBTH_OFFSET) ++#define VDEC_SHPIMP (VDEC_BASE + VDEC_SHPIMP_OFFSET) ++#define VDEC_CHPLLIM (VDEC_BASE + VDEC_CHPLLIM_OFFSET) ++#define VDEC_VIDMOD (VDEC_BASE + VDEC_VIDMOD_OFFSET) ++#define VDEC_VIDSTS (VDEC_BASE + VDEC_VIDSTS_OFFSET) ++#define VDEC_NOISE (VDEC_BASE + VDEC_NOISE_OFFSET) ++#define VDEC_STDDBG (VDEC_BASE + VDEC_STDDBG_OFFSET) ++#define VDEC_MANOVR (VDEC_BASE + VDEC_MANOVR_OFFSET) ++#define VDEC_VSSGTH (VDEC_BASE + VDEC_VSSGTH_OFFSET) ++#define VDEC_DBGFBH (VDEC_BASE + VDEC_DBGFBH_OFFSET) ++#define VDEC_DBGFBL (VDEC_BASE + VDEC_DBGFBL_OFFSET) ++#define VDEC_HACTS (VDEC_BASE + VDEC_HACTS_OFFSET) ++#define VDEC_HACTE (VDEC_BASE + VDEC_HACTE_OFFSET) ++#define VDEC_VACTS (VDEC_BASE + VDEC_VACTS_OFFSET) ++#define VDEC_VACTE (VDEC_BASE + VDEC_VACTE_OFFSET) ++#define VDEC_HSTIP (VDEC_BASE + VDEC_HSTIP_OFFSET) ++#define VDEC_BLSCRY (VDEC_BASE + VDEC_BLSCRY_OFFSET) ++#define VDEC_BLSCRCR (VDEC_BASE + VDEC_BLSCRCR_OFFSET) ++#define VDEC_BLSCRCB (VDEC_BASE + VDEC_BLSCRCB_OFFSET) ++#define VDEC_LMAGC1 (VDEC_BASE + VDEC_LMAGC1_OFFSET) ++#define VDEC_LMAGC2 (VDEC_BASE + VDEC_LMAGC2_OFFSET) ++#define VDEC_CHAGC1 (VDEC_BASE + VDEC_CHAGC1_OFFSET) ++#define VDEC_CHAGC2 (VDEC_BASE + VDEC_CHAGC2_OFFSET) ++#define VDEC_MINTH (VDEC_BASE + VDEC_MINTH_OFFSET) ++#define VDEC_VFRQOH (VDEC_BASE + VDEC_VFRQOH_OFFSET) ++#define VDEC_VFRQOL (VDEC_BASE + VDEC_VFRQOL_OFFSET) ++#define VDEC_THSH1 (VDEC_BASE + VDEC_THSH1_OFFSET) ++#define VDEC_THSH2 (VDEC_BASE + VDEC_THSH2_OFFSET) ++#define VDEC_NCHTH (VDEC_BASE + VDEC_NCHTH_OFFSET) ++#define VDEC_TH1F (VDEC_BASE + VDEC_TH1F_OFFSET) ++ ++#define VDEC_VIDMOD_SIGNAL_MASK 0x0F ++#define VDEC_VIDMOD_SIGNAL_DETECT 0x0F ++ ++#define VDEC_VIDMOD_M625_SHIFT 4 ++#define VDEC_VIDMOD_M625_MASK (1 << VDEC_VIDMOD_M625_SHIFT) ++ ++#define VDEC_VIDMOD_PAL_SHIFT 7 ++#define VDEC_VIDMOD_PAL_MASK (1 << VDEC_VIDMOD_PAL_SHIFT) ++/*** define base address ***/ ++ ++#endif +diff -Nur linux-3.14.72.orig/drivers/media/platform/mxc/subdev/ov5640.c linux-3.14.72/drivers/media/platform/mxc/subdev/ov5640.c +--- linux-3.14.72.orig/drivers/media/platform/mxc/subdev/ov5640.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/media/platform/mxc/subdev/ov5640.c 2016-06-19 22:11:55.189147618 +0200 +@@ -0,0 +1,1918 @@ ++/* ++ * Copyright (C) 2012-2015 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 ++ ++#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 ov5640_datafmt { ++ enum v4l2_mbus_pixelcode code; ++ enum v4l2_colorspace colorspace; ++}; ++ ++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; ++}; ++ ++struct ov5640 { ++ struct v4l2_subdev subdev; ++ struct i2c_client *i2c_client; ++ struct v4l2_pix_format pix; ++ const struct ov5640_datafmt *fmt; ++ 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); ++}; ++ ++/*! ++ * Maintains the information on the current state of the sesor. ++ */ ++static struct ov5640 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}, ++ {}, ++}; ++ ++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 const struct ov5640_datafmt ov5640_colour_fmts[] = { ++ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, ++}; ++ ++static struct ov5640 *to_ov5640(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov5640, subdev); ++} ++ ++/* Find a data format by a pixel code in an array */ ++static const struct ov5640_datafmt ++ *ov5640_find_datafmt(enum v4l2_mbus_pixelcode code) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++) ++ if (ov5640_colour_fmts[i].code == code) ++ return ov5640_colour_fmts + i; ++ ++ return NULL; ++} ++ ++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; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov5640_get_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ u8 val; ++ ++ if (reg->reg & ~0xffff) ++ return -EINVAL; ++ ++ reg->size = 1; ++ ++ ret = ov5640_read_reg(reg->reg, &val); ++ if (!ret) ++ reg->val = (__u64)val; ++ ++ return ret; ++} ++ ++static int ov5640_set_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg & ~0xffff || reg->val & ~0xff) ++ return -EINVAL; ++ ++ return ov5640_write_reg(reg->reg, reg->val); ++} ++#endif ++ ++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 */ ++static 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; ++} ++ ++/*! ++ * ov5640_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 ov5640_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640 *sensor = to_ov5640(client); ++ ++ if (on) ++ clk_enable(ov5640_data.sensor_clk); ++ else ++ clk_disable(ov5640_data.sensor_clk); ++ ++ 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; ++} ++ ++static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ if (enable) { ++ clk_enable(ov5640_data.sensor_clk); ++ ov5640_power_down(0); ++ } else { ++ ov5640_power_down(1); ++ clk_disable(ov5640_data.sensor_clk); ++ } ++ return 0; ++} ++ ++/*! ++ * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl ++ * @s: pointer to standard V4L2 sub device structure ++ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure ++ * ++ * Returns the sensor's video CAPTURE parameters. ++ */ ++static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640 *sensor = to_ov5640(client); ++ 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; ++} ++ ++/*! ++ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl ++ * @s: pointer to standard V4L2 sub 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 ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640 *sensor = to_ov5640(client); ++ 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 */ ++ clk_enable(ov5640_data.sensor_clk); ++ 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"); ++ goto error; ++ } ++ ++ ret = ov5640_change_mode(frame_rate, ++ a->parm.capture.capturemode); ++ if (ret < 0) ++ goto error; ++ ++ 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; ++ } ++ ++error: ++ ov5640_power_down(1); ++ clk_disable(ov5640_data.sensor_clk); ++ return ret; ++} ++ ++static int ov5640_try_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *mf) ++{ ++ const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code); ++ ++ if (!fmt) { ++ mf->code = ov5640_colour_fmts[0].code; ++ mf->colorspace = ov5640_colour_fmts[0].colorspace; ++ } ++ ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov5640_s_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *mf) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640 *sensor = to_ov5640(client); ++ ++ /* MIPI CSI could have changed the format, double-check */ ++ if (!ov5640_find_datafmt(mf->code)) ++ return -EINVAL; ++ ++ ov5640_try_fmt(sd, mf); ++ sensor->fmt = ov5640_find_datafmt(mf->code); ++ ++ return 0; ++} ++ ++static int ov5640_g_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *mf) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640 *sensor = to_ov5640(client); ++ ++ const struct ov5640_datafmt *fmt = sensor->fmt; ++ ++ mf->code = fmt->code; ++ mf->colorspace = fmt->colorspace; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov5640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, ++ enum v4l2_mbus_pixelcode *code) ++{ ++ if (index >= ARRAY_SIZE(ov5640_colour_fmts)) ++ return -EINVAL; ++ ++ *code = ov5640_colour_fmts[index].code; ++ return 0; ++} ++ ++/*! ++ * ov5640_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 ov5640_enum_framesizes(struct v4l2_subdev *sd, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ if (fsize->index > ov5640_mode_MAX) ++ return -EINVAL; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ 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; ++} ++ ++/*! ++ * ov5640_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 ov5640_enum_frameintervals(struct v4l2_subdev *sd, ++ 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; ++} ++ ++/*! ++ * dev_init - V4L2 sensor init ++ * @s: pointer to standard V4L2 device structure ++ * ++ */ ++static int init_device(void) ++{ ++ 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 = ov5640_data.streamcap.timeperframe.denominator / ++ ov5640_data.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; ++} ++ ++static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = { ++ .s_stream = ov5640_s_stream, ++ .g_parm = ov5640_g_parm, ++ .s_parm = ov5640_s_parm, ++ ++ .s_mbus_fmt = ov5640_s_fmt, ++ .g_mbus_fmt = ov5640_g_fmt, ++ .try_mbus_fmt = ov5640_try_fmt, ++ .enum_mbus_fmt = ov5640_enum_fmt, ++ .enum_framesizes = ov5640_enum_framesizes, ++ .enum_frameintervals = ov5640_enum_frameintervals, ++}; ++ ++static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = { ++ .s_power = ov5640_s_power, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov5640_get_register, ++ .s_register = ov5640_set_register, ++#endif ++}; ++ ++static struct v4l2_subdev_ops ov5640_subdev_ops = { ++ .core = &ov5640_subdev_core_ops, ++ .video = &ov5640_subdev_video_ops, ++}; ++ ++/*! ++ * 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; ++ } ++ ++ retval = init_device(); ++ if (retval < 0) { ++ clk_disable_unprepare(ov5640_data.sensor_clk); ++ pr_warning("camera ov5640 init failed\n"); ++ ov5640_power_down(1); ++ return retval; ++ } ++ ++ ov5640_power_down(1); ++ ++ clk_disable(ov5640_data.sensor_clk); ++ ++ v4l2_i2c_subdev_init(&ov5640_data.subdev, client, &ov5640_subdev_ops); ++ ++ retval = v4l2_async_register_subdev(&ov5640_data.subdev); ++ if (retval < 0) ++ dev_err(&client->dev, ++ "%s--Async register failed, ret=%d\n", __func__, retval); ++ ++ 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) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ ++ v4l2_async_unregister_subdev(sd); ++ ++ clk_unprepare(ov5640_data.sensor_clk); ++ ++ 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.72.orig/drivers/media/v4l2-core/v4l2-compat-ioctl32.c linux-3.14.72/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +--- linux-3.14.72.orig/drivers/media/v4l2-core/v4l2-compat-ioctl32.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/v4l2-core/v4l2-compat-ioctl32.c 2016-06-19 22:11:55.189147618 +0200 +@@ -1072,6 +1072,7 @@ + case VIDIOC_TRY_DECODER_CMD: + case VIDIOC_DBG_S_REGISTER: + case VIDIOC_DBG_G_REGISTER: ++ case VIDIOC_DBG_G_CHIP_IDENT: + case VIDIOC_S_HW_FREQ_SEEK: + case VIDIOC_S_DV_TIMINGS: + case VIDIOC_G_DV_TIMINGS: +diff -Nur linux-3.14.72.orig/drivers/media/v4l2-core/v4l2-dev.c linux-3.14.72/drivers/media/v4l2-core/v4l2-dev.c +--- linux-3.14.72.orig/drivers/media/v4l2-core/v4l2-dev.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/v4l2-core/v4l2-dev.c 2016-06-19 22:11:55.189147618 +0200 +@@ -499,8 +499,8 @@ + }; + + /** +- * get_index - assign stream index number based on v4l2_dev +- * @vdev: video_device to assign index number to, vdev->v4l2_dev should be assigned ++ * get_index - assign stream index number based on parent device ++ * @vdev: video_device to assign index number to, vdev->parent should be assigned + * + * Note that when this is called the new device has not yet been registered + * in the video_device array, but it was able to obtain a minor number. +@@ -518,11 +518,15 @@ + static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES); + int i; + ++ /* Some drivers do not set the parent. In that case always return 0. */ ++ if (vdev->parent == NULL) ++ return 0; ++ + bitmap_zero(used, VIDEO_NUM_DEVICES); + + for (i = 0; i < VIDEO_NUM_DEVICES; i++) { + if (video_device[i] != NULL && +- video_device[i]->v4l2_dev == vdev->v4l2_dev) { ++ video_device[i]->parent == vdev->parent) { + set_bit(video_device[i]->index, used); + } + } +@@ -596,6 +600,7 @@ + set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); + #endif ++ SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident); + /* yes, really vidioc_subscribe_event */ + SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event); + SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event); +@@ -775,9 +780,6 @@ + /* the release callback MUST be present */ + if (WARN_ON(!vdev->release)) + return -EINVAL; +- /* the v4l2_dev pointer MUST be present */ +- if (WARN_ON(!vdev->v4l2_dev)) +- return -EINVAL; + + /* v4l2_fh support */ + spin_lock_init(&vdev->fh_lock); +@@ -805,14 +807,16 @@ + + vdev->vfl_type = type; + vdev->cdev = NULL; +- if (vdev->dev_parent == NULL) +- vdev->dev_parent = vdev->v4l2_dev->dev; +- if (vdev->ctrl_handler == NULL) +- vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; +- /* If the prio state pointer is NULL, then use the v4l2_device +- prio state. */ +- if (vdev->prio == NULL) +- vdev->prio = &vdev->v4l2_dev->prio; ++ if (vdev->v4l2_dev) { ++ if (vdev->v4l2_dev->dev) ++ vdev->parent = vdev->v4l2_dev->dev; ++ if (vdev->ctrl_handler == NULL) ++ vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; ++ /* If the prio state pointer is NULL, then use the v4l2_device ++ prio state. */ ++ if (vdev->prio == NULL) ++ vdev->prio = &vdev->v4l2_dev->prio; ++ } + + /* Part 2: find a free minor, device node number and device index. */ + #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES +@@ -898,7 +902,8 @@ + /* Part 4: register the device with sysfs */ + vdev->dev.class = &video_class; + vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); +- vdev->dev.parent = vdev->dev_parent; ++ if (vdev->parent) ++ vdev->dev.parent = vdev->parent; + dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); + ret = device_register(&vdev->dev); + if (ret < 0) { +diff -Nur linux-3.14.72.orig/drivers/media/v4l2-core/v4l2-ioctl.c linux-3.14.72/drivers/media/v4l2-core/v4l2-ioctl.c +--- linux-3.14.72.orig/drivers/media/v4l2-core/v4l2-ioctl.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/v4l2-core/v4l2-ioctl.c 2016-06-19 22:11:55.189147618 +0200 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + + #define CREATE_TRACE_POINTS +@@ -621,6 +622,20 @@ + pr_info("pts=%llu\n", p->stop.pts); + } + ++static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) ++{ ++ const struct v4l2_dbg_chip_ident *p = arg; ++ ++ pr_cont("type=%u, ", p->match.type); ++ if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) ++ pr_cont("name=%.*s, ", ++ (int)sizeof(p->match.name), p->match.name); ++ else ++ pr_cont("addr=%u, ", p->match.addr); ++ pr_cont("chip_ident=%u, revision=0x%x\n", ++ p->ident, p->revision); ++} ++ + static void v4l_print_dbg_chip_info(const void *arg, bool write_only) + { + const struct v4l2_dbg_chip_info *p = arg; +@@ -1801,6 +1816,18 @@ + #endif + } + ++static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, ++ struct file *file, void *fh, void *arg) ++{ ++ struct v4l2_dbg_chip_ident *p = arg; ++ ++ p->ident = V4L2_IDENT_NONE; ++ p->revision = 0; ++ if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) ++ return -EINVAL; ++ return ops->vidioc_g_chip_ident(file, fh, p); ++} ++ + static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) + { +@@ -1816,7 +1843,12 @@ + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (ops->vidioc_g_register) + p->flags |= V4L2_CHIP_FL_READABLE; +- strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); ++ if (vfd->v4l2_dev) ++ strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); ++ else if (vfd->parent) ++ strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name)); ++ else ++ strlcpy(p->name, "bridge", sizeof(p->name)); + if (ops->vidioc_g_chip_info) + return ops->vidioc_g_chip_info(file, fh, arg); + if (p->match.addr) +@@ -2045,6 +2077,7 @@ + IOCTL_INFO_STD(VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd, v4l_print_decoder_cmd, 0), + IOCTL_INFO_FNC(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0), + IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0), ++ IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0), + IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0), +diff -Nur linux-3.14.72.orig/drivers/media/v4l2-core/videobuf-dma-contig.c linux-3.14.72/drivers/media/v4l2-core/videobuf-dma-contig.c +--- linux-3.14.72.orig/drivers/media/v4l2-core/videobuf-dma-contig.c 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/media/v4l2-core/videobuf-dma-contig.c 2016-06-19 22:11:55.189147618 +0200 +@@ -305,7 +305,16 @@ + /* Try to remap memory */ + size = vma->vm_end - vma->vm_start; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +- retval = vm_iomap_memory(vma, vma->vm_start, size); ++ ++ /* the "vm_pgoff" is just used in v4l2 to find the ++ * corresponding buffer data structure which is allocated ++ * earlier and it does not mean the offset from the physical ++ * buffer start address as usual. So set it to 0 to pass ++ * the sanity check in vm_iomap_memory(). ++ */ ++ vma->vm_pgoff = 0; ++ ++ retval = vm_iomap_memory(vma, mem->dma_handle, size); + if (retval) { + dev_err(q->dev, "mmap: remap failed with error %d. ", + retval); +diff -Nur linux-3.14.72.orig/drivers/mfd/Kconfig linux-3.14.72/drivers/mfd/Kconfig +--- linux-3.14.72.orig/drivers/mfd/Kconfig 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/mfd/Kconfig 2016-06-19 22:11:55.189147618 +0200 +@@ -163,6 +163,21 @@ + 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_MXC_HDMI_ANDROID ++ tristate "Freescale HDMI Core for Android" ++ select MFD_CORE ++ depends on MFD_MXC_HDMI=y ++ 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) +@@ -317,6 +332,13 @@ + select individual components like voltage regulators, RTC and + battery-charger under the corresponding menus. + ++config MFD_MAX17135 ++ tristate "Maxim MAX17135 EPD PMIC core" ++ depends on I2C ++ help ++ This is the MAX17135 PMIC support. It includes ++ core support for communication with the MAX17135 chip. ++ + config MFD_MAX14577 + bool "Maxim Semiconductor MAX14577 MUIC + Charger Support" + depends on I2C=y +@@ -1193,6 +1215,14 @@ + in various ST Microelectronics and ST-Ericsson embedded + Nomadik series. + ++config MFD_TDA1997X ++ tristate "TDA1997X HDMI Receiver Core" ++ select MFD_CORE ++ depends on I2C=y ++ help ++ This is the core driver for the TDA1997X HDMI Reciver. This MFD ++ driver connects with video and audio drivers for HDMI Input. ++ + endmenu + endif + +diff -Nur linux-3.14.72.orig/drivers/mfd/Makefile linux-3.14.72/drivers/mfd/Makefile +--- linux-3.14.72.orig/drivers/mfd/Makefile 2016-06-08 02:22:20.000000000 +0200 ++++ linux-3.14.72/drivers/mfd/Makefile 2016-06-19 22:11:55.193147356 +0200 +@@ -112,6 +112,7 @@ + obj-$(CONFIG_MFD_DA9063) += da9063.o + + obj-$(CONFIG_MFD_MAX14577) += max14577.o ++obj-$(CONFIG_MFD_MAX17135) += max17135-core.o + obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o + obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o + obj-$(CONFIG_MFD_MAX8907) += max8907.o +@@ -166,3 +167,5 @@ + 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 ++obj-$(CONFIG_MFD_TDA1997X) += tda1997x-core.o +diff -Nur linux-3.14.72.orig/drivers/mfd/max17135-core.c linux-3.14.72/drivers/mfd/max17135-core.c +--- linux-3.14.72.orig/drivers/mfd/max17135-core.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/mfd/max17135-core.c 2016-06-19 22:11:55.193147356 +0200 +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (C) 2010-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 ++ * ++ */ ++ ++/*! ++ * @file pmic/core/max17135.c ++ * @brief This file contains MAX17135 specific PMIC code. This implementaion ++ * may differ for each PMIC chip. ++ * ++ * @ingroup PMIC_CORE ++ */ ++ ++/* ++ * Includes ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int max17135_detect(struct i2c_client *client, ++ struct i2c_board_info *info); ++struct i2c_client *max17135_client; ++static struct regulator *gpio_regulator; ++ ++static struct mfd_cell max17135_devs[] = { ++ { .name = "max17135-pmic", }, ++ { .name = "max17135-sns", }, ++}; ++ ++static const unsigned short normal_i2c[] = {0x48, I2C_CLIENT_END}; ++ ++int max17135_reg_read(int reg_num, unsigned int *reg_val) ++{ ++ int result; ++ ++ if (max17135_client == NULL) ++ return PMIC_ERROR; ++ ++ if ((reg_num == REG_MAX17135_EXT_TEMP) || ++ (reg_num == REG_MAX17135_INT_TEMP)) { ++ result = i2c_smbus_read_word_data(max17135_client, reg_num); ++ if (result < 0) { ++ dev_err(&max17135_client->dev, ++ "Unable to read MAX17135 register via I2C\n"); ++ return PMIC_ERROR; ++ } ++ /* Swap bytes for dword read */ ++ result = (result >> 8) | ((result & 0xFF) << 8); ++ } else { ++ result = i2c_smbus_read_byte_data(max17135_client, reg_num); ++ if (result < 0) { ++ dev_err(&max17135_client->dev, ++ "Unable to read MAX17135 register via I2C\n"); ++ return PMIC_ERROR; ++ } ++ } ++ ++ *reg_val = result; ++ return PMIC_SUCCESS; ++} ++ ++int max17135_reg_write(int reg_num, const unsigned int reg_val) ++{ ++ int result; ++ ++ if (max17135_client == NULL) ++ return PMIC_ERROR; ++ ++ result = i2c_smbus_write_byte_data(max17135_client, reg_num, reg_val); ++ if (result < 0) { ++ dev_err(&max17135_client->dev, ++ "Unable to write MAX17135 register via I2C\n"); ++ return PMIC_ERROR; ++ } ++ ++ return PMIC_SUCCESS; ++} ++ ++#ifdef CONFIG_OF ++static struct max17135_platform_data *max17135_i2c_parse_dt_pdata( ++ struct device *dev) ++{ ++ struct max17135_platform_data *pdata; ++ ++ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) { ++ dev_err(dev, "could not allocate memory for pdata\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ return pdata; ++} ++#else ++static struct max17135_platform_data *max17135_i2c_parse_dt_pdata( ++ struct device *dev) ++{ ++ return NULL; ++} ++#endif /* !CONFIG_OF */ ++ ++static int max17135_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct max17135 *max17135; ++ struct max17135_platform_data *pdata = client->dev.platform_data; ++ struct device_node *np = client->dev.of_node; ++ int ret = 0; ++ ++ if (!np) ++ return -ENODEV; ++ ++ gpio_regulator = devm_regulator_get(&client->dev, "SENSOR"); ++ if (!IS_ERR(gpio_regulator)) { ++ ret = regulator_enable(gpio_regulator); ++ if (ret) { ++ dev_err(&client->dev, "gpio set voltage error\n"); ++ return ret; ++ } ++ } ++ ++ /* Create the PMIC data structure */ ++ max17135 = kzalloc(sizeof(struct max17135), GFP_KERNEL); ++ if (max17135 == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } ++ ++ /* Initialize the PMIC data structure */ ++ i2c_set_clientdata(client, max17135); ++ max17135->dev = &client->dev; ++ max17135->i2c_client = client; ++ ++ max17135_client = client; ++ ret = max17135_detect(client, NULL); ++ if (ret) ++ goto err1; ++ ++ mfd_add_devices(max17135->dev, -1, max17135_devs, ++ ARRAY_SIZE(max17135_devs), ++ NULL, 0, NULL); ++ ++ if (max17135->dev->of_node) { ++ pdata = max17135_i2c_parse_dt_pdata(max17135->dev); ++ if (IS_ERR(pdata)) { ++ ret = PTR_ERR(pdata); ++ goto err2; ++ } ++ ++ } ++ max17135->pdata = pdata; ++ ++ dev_info(&client->dev, "PMIC MAX17135 for eInk display\n"); ++ ++ return ret; ++err2: ++ mfd_remove_devices(max17135->dev); ++err1: ++ kfree(max17135); ++ ++ return ret; ++} ++ ++ ++static int max17135_remove(struct i2c_client *i2c) ++{ ++ struct max17135 *max17135 = i2c_get_clientdata(i2c); ++ ++ mfd_remove_devices(max17135->dev); ++ return 0; ++} ++ ++static int max17135_suspend(struct i2c_client *client, pm_message_t state) ++{ ++ return 0; ++} ++ ++static int max17135_resume(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++/* Return 0 if detection is successful, -ENODEV otherwise */ ++static int max17135_detect(struct i2c_client *client, ++ struct i2c_board_info *info) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ u8 chip_rev, chip_id; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return -ENODEV; ++ ++ /* detection */ ++ if (i2c_smbus_read_byte_data(client, ++ REG_MAX17135_PRODUCT_REV) != 0) { ++ dev_err(&adapter->dev, ++ "Max17135 PMIC not found!\n"); ++ return -ENODEV; ++ } ++ ++ /* identification */ ++ chip_rev = i2c_smbus_read_byte_data(client, ++ REG_MAX17135_PRODUCT_REV); ++ chip_id = i2c_smbus_read_byte_data(client, ++ REG_MAX17135_PRODUCT_ID); ++ ++ if (chip_rev != 0x00 || chip_id != 0x4D) { /* identification failed */ ++ dev_info(&adapter->dev, ++ "Unsupported chip (man_id=0x%02X, " ++ "chip_id=0x%02X).\n", chip_rev, chip_id); ++ return -ENODEV; ++ } ++ ++ if (info) ++ strlcpy(info->type, "max17135_sensor", I2C_NAME_SIZE); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id max17135_id[] = { ++ { "max17135", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max17135_id); ++ ++static const struct of_device_id max17135_dt_ids[] = { ++ { ++ .compatible = "maxim,max17135", ++ .data = (void *) &max17135_id[0], ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, max17135_dt_ids); ++ ++ ++static struct i2c_driver max17135_driver = { ++ .driver = { ++ .name = "max17135", ++ .owner = THIS_MODULE, ++ .of_match_table = max17135_dt_ids, ++ }, ++ .probe = max17135_probe, ++ .remove = max17135_remove, ++ .suspend = max17135_suspend, ++ .resume = max17135_resume, ++ .id_table = max17135_id, ++ .detect = max17135_detect, ++ .address_list = &normal_i2c[0], ++}; ++ ++static int __init max17135_init(void) ++{ ++ return i2c_add_driver(&max17135_driver); ++} ++ ++static void __exit max17135_exit(void) ++{ ++ i2c_del_driver(&max17135_driver); ++} ++ ++/* ++ * Module entry points ++ */ ++subsys_initcall(max17135_init); ++module_exit(max17135_exit); +diff -Nur linux-3.14.72.orig/drivers/mfd/mxc-hdmi-core.c linux-3.14.72/drivers/mfd/mxc-hdmi-core.c +--- linux-3.14.72.orig/drivers/mfd/mxc-hdmi-core.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.14.72/drivers/mfd/mxc-hdmi-core.c 2016-06-19 22:11:55.193147356 +0200 +@@ -0,0 +1,792 @@ ++/* ++ * 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 ++ ++#include