diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6dl-cm-fx6.dts linux-4.1.13/arch/arm/boot/dts/imx6dl-cm-fx6.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6dl-cm-fx6.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6dl-cm-fx6.dts 2015-11-30 17:56:13.480144383 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6dl.dtsi linux-4.1.13/arch/arm/boot/dts/imx6dl.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6dl.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6dl.dtsi 2015-11-30 17:56:13.480144383 +0100 @@ -30,7 +30,7 @@ /* kHz uV */ 996000 1250000 792000 1175000 - 396000 1075000 + 396000 1175000 >; fsl,soc-operating-points = < /* ARM kHz SOC-PU uV */ @@ -43,9 +43,12 @@ <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, <&clks IMX6QDL_CLK_STEP>, <&clks IMX6QDL_CLK_PLL1_SW>, - <&clks IMX6QDL_CLK_PLL1_SYS>; + <&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>; @@ -60,17 +63,82 @@ }; soc { - ocram: sram@00900000 { + busfreq { /* 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_GPU2D_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>; + }; + + hdmi_cec: hdmi_cec@00120000 { + compatible = "fsl,imx6q-hdmi-cec"; + interrupts = <0 115 0x04>; + status = "disabled"; + }; + + 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>; + reg = <0x00905000 0x1B000>; clocks = <&clks IMX6QDL_CLK_OCRAM>; }; aips1: aips-bus@02000000 { + vpu@02040000 { + iramsize = <0>; + status = "okay"; + }; + 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 { reg = <0x020f0000 0x4000>; interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; @@ -88,6 +156,16 @@ }; aips2: aips-bus@02100000 { + mipi_dsi: mipi@021e0000 { + compatible = "fsl,imx6dl-mipi-dsi"; + reg = <0x021e0000 0x4000>; + interrupts = <0 102 0x04>; + gpr = <&gpr>; + clocks = <&clks 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>; @@ -99,26 +177,13 @@ }; }; }; - - display-subsystem { - compatible = "fsl,imx-display-subsystem"; - ports = <&ipu1_di0>, <&ipu1_di1>; - }; -}; - -&hdmi { - compatible = "fsl,imx6dl-hdmi"; }; &ldb { - clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_SEL>, - <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, - <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>; + 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"; }; - -&vpu { - compatible = "fsl,imx6dl-vpu", "cnm,coda960"; -}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6dl-hummingboard2.dts linux-4.1.13/arch/arm/boot/dts/imx6dl-hummingboard2.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6dl-hummingboard2.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6dl-hummingboard2.dts 2015-11-30 17:56:13.480144383 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6dl-sbc-fx6.dts linux-4.1.13/arch/arm/boot/dts/imx6dl-sbc-fx6.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6dl-sbc-fx6.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6dl-sbc-fx6.dts 2015-11-30 17:56:13.480144383 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts linux-4.1.13/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6dl-sbc-fx6m.dts 2015-11-30 17:56:13.480144383 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6dl-vero.dts linux-4.1.13/arch/arm/boot/dts/imx6dl-vero.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6dl-vero.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6dl-vero.dts 2015-11-30 17:56:13.480144383 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 Russell King + * Copyright (C) 2015 Sam Nazarko + * + * 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-vero.dtsi" + +/ { + model = "OSMC Vero Rev 1.0"; + compatible = "osmc,vero1", "fsl,imx6dl"; +}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6q-cm-fx6.dts linux-4.1.13/arch/arm/boot/dts/imx6q-cm-fx6.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6q-cm-fx6.dts 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6q-cm-fx6.dts 2015-11-30 17:56:13.480144383 +0100 @@ -1,5 +1,5 @@ /* - * Copyright 2013 CompuLab Ltd. + * Copyright 2014 CompuLab Ltd. * * Author: Valentin Raevsky * @@ -13,95 +13,9 @@ /dts-v1/; #include "imx6q.dtsi" +#include "imx6q-cm-fx6.dtsi" / { model = "CompuLab CM-FX6"; compatible = "compulab,cm-fx6", "fsl,imx6q"; - - memory { - reg = <0x10000000 0x80000000>; - }; - - leds { - compatible = "gpio-leds"; - - heartbeat-led { - label = "Heartbeat"; - gpios = <&gpio2 31 0>; - linux,default-trigger = "heartbeat"; - }; - }; -}; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet>; - phy-mode = "rgmii"; - status = "okay"; -}; - -&gpmi { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gpmi_nand>; - status = "okay"; -}; - -&iomuxc { - imx6q-cm-fx6 { - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; - - pinctrl_gpmi_nand: gpminandgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 - MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 - MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 - MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 - MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 - MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 - MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 - MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 - MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 - MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 - MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 - MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 - MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 - MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 - MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 - MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 - MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 - >; - }; - - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; - }; -}; - -&uart4 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart4>; - status = "okay"; }; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6q-cm-fx6.dtsi linux-4.1.13/arch/arm/boot/dts/imx6q-cm-fx6.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6q-cm-fx6.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6q-cm-fx6.dtsi 2015-11-30 17:56:13.480144383 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-cm-fx6.dtsi 2015-11-30 17:56:13.484144118 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2015-11-30 17:56:13.484144118 +0100 @@ -45,11 +45,22 @@ #include / { + chosen { + bootargs = "quiet console=ttymxc0,115200 root=/dev/mmcblk0p2 rw"; + }; + + aliases { + mmc0 = &usdhc2; + mmc1 = &usdhc1; + mxcfb0 = &mxcfb1; + }; + ir_recv: ir-receiver { compatible = "gpio-ir-receiver"; gpios = <&gpio3 9 1>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cubox_i_ir>; + linux,rc-map-name = "rc-rc6-mce"; }; pwmleds { @@ -78,6 +89,8 @@ reg_usbh1_vbus: usb-h1-vbus { compatible = "regulator-fixed"; + regulator-boot-on; + regulator-always-on; enable-active-high; gpio = <&gpio1 0 0>; pinctrl-names = "default"; @@ -89,6 +102,8 @@ reg_usbotg_vbus: usb-otg-vbus { compatible = "regulator-fixed"; + regulator-boot-on; + regulator-always-on; enable-active-high; gpio = <&gpio3 22 0>; pinctrl-names = "default"; @@ -101,8 +116,7 @@ sound-spdif { compatible = "fsl,imx-audio-spdif"; - model = "Integrated SPDIF"; - /* IMX6 doesn't implement this yet */ + model = "imx-spdif"; spdif-controller = <&spdif>; spdif-out; }; @@ -118,12 +132,45 @@ linux,code = ; }; }; + + sound-hdmi { + compatible = "fsl,imx6q-audio-hdmi", + "fsl,imx-audio-hdmi"; + model = "imx-audio-hdmi"; + hdmi-controller = <&hdmi_audio>; + }; + + mxcfb1: fb@0 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "hdmi"; + interface_pix_fmt = "RGB24"; + mode_str ="1920x1080M@60"; + default_bpp = <32>; + int_clk = <0>; + late_init = <0>; + status = "okay"; + }; +}; + +&hdmi_core { + ipu_id = <0>; + disp_id = <0>; + status = "okay"; +}; + +&hdmi_video { + fsl,phy_reg_vlev = <0x0294>; + fsl,phy_reg_cksymtx = <0x800d>; + status = "okay"; +}; + +&hdmi_audio { + status = "okay"; }; -&hdmi { +&hdmi_cec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cubox_i_hdmi>; - ddc-i2c-bus = <&i2c2>; status = "okay"; }; @@ -131,7 +178,13 @@ 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 { @@ -207,7 +260,7 @@ 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 >; }; @@ -228,6 +281,28 @@ MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x17059 >; }; + + pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 + >; + }; + + pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 + >; + }; }; }; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl.dtsi 2015-11-30 17:56:13.488143852 +0100 @@ -14,6 +14,7 @@ #include #include "skeleton.dtsi" +#include / { aliases { @@ -30,6 +31,7 @@ i2c0 = &i2c1; i2c1 = &i2c2; i2c2 = &i2c3; + ipu0 = &ipu1; mmc0 = &usdhc1; mmc1 = &usdhc2; mmc2 = &usdhc3; @@ -79,6 +81,10 @@ }; }; + pu_dummy: pudummy_reg { + compatible = "fsl,imx6-dummy-pureg"; /* only used in ldo-bypass */ + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -86,6 +92,11 @@ interrupt-parent = <&gpc>; 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>; @@ -99,6 +110,12 @@ 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 { compatible = "fsl,imx6q-gpmi-nand"; #address-cells = <1>; @@ -169,6 +186,39 @@ 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 0x04>; + 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 23 0>; + dma-names = "tx"; + status = "disabled"; + }; + aips-bus@02000000 { /* AIPS1 */ compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; @@ -274,7 +324,12 @@ esai: esai@02024000 { reg = <0x02024000 0x4000>; interrupts = <0 51 IRQ_TYPE_LEVEL_HIGH>; - }; + compatible = "fsl,imx6q-esai"; + clocks = <&clks 118>; + fsl,esai-dma-events = <24 23>; + fsl,flags = <1>; + status = "disabled"; + }; ssi1: ssi@02028000 { #sound-dai-cells = <0>; @@ -325,8 +380,30 @@ }; asrc: asrc@02034000 { + compatible = "fsl,imx53-asrc"; reg = <0x02034000 0x4000>; interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_ASRC_MEM>, + <&clks IMX6QDL_CLK_ASRC_IPG>, + <&clks IMX6QDL_CLK_SPDIF>, + <&clks IMX6QDL_CLK_SPBA>; + clock-names = "mem", "ipg", "asrck_0", "dma"; + dmas = <&sdma 17 20 1>, <&sdma 18 20 1>, <&sdma 19 20 1>, + <&sdma 20 20 1>, <&sdma 21 20 1>, <&sdma 22 20 1>; + dma-names = "rxa", "rxb", "rxc", + "txa", "txb", "txc"; + fsl,asrc-rate = <48000>; + fsl,asrc-width = <16>; + status = "okay"; + }; + + asrc_p2p: asrc_p2p { + compatible = "fsl,imx6q-asrc-p2p"; + fsl,output-rate = <48000>; + fsl,output-width = <16>; + fsl,asrc-dma-rx-events = <17 18 19>; + fsl,asrc-dma-tx-events = <20 21 22>; + status = "okay"; }; spba@0203c000 { @@ -335,16 +412,20 @@ }; vpu: vpu@02040000 { - compatible = "cnm,coda960"; + compatible = "cnm,coda960", "fsl,imx6-vpu"; reg = <0x02040000 0x3c000>; + reg-names = "vpu_regs"; interrupts = <0 12 IRQ_TYPE_LEVEL_HIGH>, <0 3 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "bit", "jpeg"; clocks = <&clks IMX6QDL_CLK_VPU_AXI>, - <&clks IMX6QDL_CLK_MMDC_CH0_AXI>; - clock-names = "per", "ahb"; - resets = <&src 1>; + <&clks IMX6QDL_CLK_MMDC_CH0_AXI>, + <&clks IMX6QDL_CLK_OCRAM>; + clock-names = "per", "ahb", "ocram"; + iramsize = <0x21000>; iram = <&ocram>; + resets = <&src 1>; + power-domains = <&gpc 1>; }; aipstz@0207c000 { /* AIPSTZ1 */ @@ -552,20 +633,21 @@ anatop-min-bit-val = <4>; anatop-min-voltage = <800000>; anatop-max-voltage = <1375000>; + anatop-enable-bit = <0>; }; - regulator-3p0@120 { + reg_3p0: regulator-3p0@120 { compatible = "fsl,anatop-regulator"; regulator-name = "vdd3p0"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <3150000>; - regulator-always-on; + regulator-min-microvolt = <2625000>; + regulator-max-microvolt = <3400000>; 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>; + anatop-enable-bit = <0>; }; regulator-2p5@130 { @@ -580,6 +662,7 @@ anatop-min-bit-val = <0>; anatop-min-voltage = <2000000>; anatop-max-voltage = <2750000>; + anatop-enable-bit = <0>; }; reg_arm: regulator-vddcore@140 { @@ -597,6 +680,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 { @@ -631,6 +716,8 @@ anatop-min-bit-val = <1>; anatop-min-voltage = <725000>; anatop-max-voltage = <1450000>; + regulator-allow-bypass; + linux,phandle = <®_soc>; }; }; @@ -647,6 +734,7 @@ reg = <0x020c9000 0x1000>; interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_USBPHY1>; + phy-3p0-supply = <®_3p0>; fsl,anatop = <&anatop>; }; @@ -655,9 +743,15 @@ reg = <0x020ca000 0x1000>; interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_USBPHY2>; + phy-3p0-supply = <®_3p0>; fsl,anatop = <&anatop>; }; + caam_snvs: caam-snvs@020cc000 { + compatible = "fsl,imx6q-caam-snvs"; + reg = <0x020cc000 0x4000>; + }; + snvs@020cc000 { compatible = "fsl,sec-v4.0-mon", "simple-bus"; #address-cells = <1>; @@ -704,14 +798,12 @@ interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>, <0 90 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&intc>; - 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>; + clocks = <&clks 122>, <&clks 74>, <&clks 121>, + <&clks 26>, <&clks 143>, <&clks 168>; + clock-names = "gpu3d_core", "gpu3d_shader", "gpu2d_core", + "gpu2d_axi", "openvg_axi", "vpu_axi"; + pu-supply = <®_pu>; }; gpr: iomuxc-gpr@020e0000 { @@ -736,22 +828,6 @@ #size-cells = <0>; reg = <0>; status = "disabled"; - - port@0 { - reg = <0>; - - lvds0_mux_0: endpoint { - remote-endpoint = <&ipu1_di0_lvds0>; - }; - }; - - port@1 { - reg = <1>; - - lvds0_mux_1: endpoint { - remote-endpoint = <&ipu1_di1_lvds0>; - }; - }; }; lvds-channel@1 { @@ -759,22 +835,6 @@ #size-cells = <0>; reg = <1>; status = "disabled"; - - port@0 { - reg = <0>; - - lvds1_mux_0: endpoint { - remote-endpoint = <&ipu1_di0_lvds1>; - }; - }; - - port@1 { - reg = <1>; - - lvds1_mux_1: endpoint { - remote-endpoint = <&ipu1_di1_lvds1>; - }; - }; }; }; @@ -788,32 +848,26 @@ <&clks IMX6QDL_CLK_HDMI_ISFR>; clock-names = "iahb", "isfr"; status = "disabled"; - - port@0 { - reg = <0>; - - hdmi_mux_0: endpoint { - remote-endpoint = <&ipu1_di0_hdmi>; - }; - }; - - port@1 { - reg = <1>; - - hdmi_mux_1: endpoint { - remote-endpoint = <&ipu1_di1_hdmi>; - }; - }; }; dcic1: dcic@020e4000 { + compatible = "fsl,imx6q-dcic"; reg = <0x020e4000 0x4000>; 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 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 { @@ -824,6 +878,7 @@ <&clks IMX6QDL_CLK_SDMA>; clock-names = "ipg", "ahb"; #dma-cells = <3>; + iram = <&ocram>; fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; }; }; @@ -835,10 +890,30 @@ reg = <0x02100000 0x100000>; ranges; - caam@02100000 { - reg = <0x02100000 0x40000>; - interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>, - <0 106 IRQ_TYPE_LEVEL_HIGH>; + 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>; */ + interrupts = <0 92 0x4>; + clocks = <&clks 213>, <&clks 214>, <&clks 215> ,<&clks 196>; + clock-names = "caam_mem", "caam_aclk", "caam_ipg", "caam_emi_slow"; + + sec_jr0: jr0@1000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>; + }; + + sec_jr1: jr1@2000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>; + }; }; aipstz@0217c000 { /* AIPSTZ2 */ @@ -852,6 +927,7 @@ clocks = <&clks IMX6QDL_CLK_USBOH3>; fsl,usbphy = <&usbphy1>; fsl,usbmisc = <&usbmisc 0>; + fsl,anatop = <&anatop>; status = "disabled"; }; @@ -903,14 +979,22 @@ <&clks IMX6QDL_CLK_ENET>, <&clks IMX6QDL_CLK_ENET_REF>; clock-names = "ipg", "ahb", "ptp"; - status = "disabled"; + phy-mode = "rgmii"; + fsl,magic-packet; + status = "okay"; + local-mac-address = [FF FF FF FF FF FF]; }; - mlb@0218c000 { + mlb: mlb@0218c000 { reg = <0x0218c000 0x4000>; interrupts = <0 53 IRQ_TYPE_LEVEL_HIGH>, <0 117 IRQ_TYPE_LEVEL_HIGH>, <0 126 IRQ_TYPE_LEVEL_HIGH>; + compatible = "fsl,imx6q-mlb150"; + clocks = <&clks 139>, <&clks 175>; + clock-names = "mlb", "pll8_mlb"; + iram = <&ocram>; + status = "disabled"; }; usdhc1: usdhc@02190000 { @@ -995,6 +1079,11 @@ reg = <0x021ac000 0x4000>; }; + mmdc0-1@021b0000 { + compatible = "fsl,imx6q-mmdc-combine"; + reg = <0x021b0000 0x8000>; + }; + mmdc0: mmdc@021b0000 { /* MMDC0 */ compatible = "fsl,imx6q-mmdc"; reg = <0x021b0000 0x4000>; @@ -1011,9 +1100,15 @@ clocks = <&clks IMX6QDL_CLK_EIM_SLOW>; }; - ocotp: ocotp@021bc000 { - compatible = "fsl,imx6q-ocotp", "syscon"; + ocotp: ocotp-ctrl@021bc000 { + compatible = "syscon"; + reg = <0x021bc000 0x4000>; + }; + + ocotp-fuse@021bc000 { + compatible = "fsl,imx6q-ocotp"; reg = <0x021bc000 0x4000>; + clocks = <&clks 128>; }; tzasc@021d0000 { /* TZASC1 */ @@ -1034,39 +1129,38 @@ mipi_csi: mipi@021dc000 { reg = <0x021dc000 0x4000>; + compatible = "fsl,imx6q-mipi-csi2"; + interrupts = <0 100 0x04>, <0 101 0x04>; + clocks = <&clks IMX6QDL_CLK_HSI_TX>, + <&clks IMX6QDL_CLK_EIM_SEL>, + <&clks IMX6QDL_CLK_LVDS2_IN>; + /* 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_dsi: mipi@021e0000 { + compatible = "fsl,imx6q-mipi-dsi"; #address-cells = <1>; #size-cells = <0>; reg = <0x021e0000 0x4000>; status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - mipi_mux_0: endpoint { - remote-endpoint = <&ipu1_di0_mipi>; - }; - }; - - port@1 { - reg = <1>; - - mipi_mux_1: endpoint { - remote-endpoint = <&ipu1_di1_mipi>; - }; - }; - }; + 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"; }; vdoa@021e4000 { + compatible = "fsl,imx6q-vdoa"; reg = <0x021e4000 0x4000>; interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 202>; + iram = <&ocram>; }; uart2: serial@021e8000 { @@ -1127,67 +1221,14 @@ <0 5 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_IPU1>, <&clks IMX6QDL_CLK_IPU1_DI0>, - <&clks IMX6QDL_CLK_IPU1_DI1>; - clock-names = "bus", "di0", "di1"; + <&clks IMX6QDL_CLK_IPU1_DI1>, + <&clks 39>, <&clks 40>, + <&clks 135>, <&clks 136>; + clock-names = "bus", "di0", "di1", + "di0_sel", "di1_sel", + "ldb_di0", "ldb_di1"; resets = <&src 2>; - - ipu1_csi0: port@0 { - reg = <0>; - }; - - ipu1_csi1: port@1 { - reg = <1>; - }; - - ipu1_di0: port@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - - ipu1_di0_disp0: endpoint@0 { - }; - - ipu1_di0_hdmi: endpoint@1 { - remote-endpoint = <&hdmi_mux_0>; - }; - - ipu1_di0_mipi: endpoint@2 { - remote-endpoint = <&mipi_mux_0>; - }; - - ipu1_di0_lvds0: endpoint@3 { - remote-endpoint = <&lvds0_mux_0>; - }; - - ipu1_di0_lvds1: endpoint@4 { - remote-endpoint = <&lvds1_mux_0>; - }; - }; - - ipu1_di1: port@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - - ipu1_di0_disp1: endpoint@0 { - }; - - ipu1_di1_hdmi: endpoint@1 { - remote-endpoint = <&hdmi_mux_1>; - }; - - ipu1_di1_mipi: endpoint@2 { - remote-endpoint = <&mipi_mux_1>; - }; - - ipu1_di1_lvds0: endpoint@3 { - remote-endpoint = <&lvds0_mux_1>; - }; - - ipu1_di1_lvds1: endpoint@4 { - remote-endpoint = <&lvds1_mux_1>; - }; - }; + bypass_reset = <0>; }; }; }; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi 2015-11-30 17:56:13.488143852 +0100 @@ -0,0 +1,686 @@ +/* + * 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"; +}; + +&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 + >; + + vmmc-supply = <®_usdhc2_vbus>; + cd-gpios = <&gpio1 4 0>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = < + &pinctrl_hummingboard2_usdhc3 + >; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_uart3>; + status = "okay"; +}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2015-11-30 17:56:13.492143584 +0100 @@ -44,8 +44,11 @@ #include / { - chosen { - stdout-path = &uart1; + aliases { + mmc0 = &usdhc2; + mmc1 = &usdhc1; + mxcfb0 = &mxcfb1; + mxcfb2 = &mxcfb2; }; ir_recv: ir-receiver { @@ -53,6 +56,17 @@ gpios = <&gpio3 5 1>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_gpio3_5>; + linux,rc-map-name = "rc-rc6-mce"; + }; + + 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 { @@ -87,6 +101,16 @@ 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 { @@ -99,16 +123,50 @@ model = "On-board Codec"; mux-ext-port = <5>; mux-int-port = <1>; + cpu-dai = <&ssi1>; ssi-controller = <&ssi1>; + status = "disabled"; }; sound-spdif { compatible = "fsl,imx-audio-spdif"; - model = "On-board SPDIF"; + model = "imx-spdif"; /* IMX6 doesn't implement this yet */ spdif-controller = <&spdif>; spdif-out; }; + + sound-hdmi { + compatible = "fsl,imx6q-audio-hdmi", + "fsl,imx-audio-hdmi"; + model = "imx-audio-hdmi"; + hdmi-controller = <&hdmi_audio>; + }; + + mxcfb1: fb@0 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "hdmi"; + interface_pix_fmt = "RGB24"; + mode_str ="1920x1080M@60"; + default_bpp = <32>; + int_clk = <0>; + late_init = <0>; + }; + + 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 { @@ -118,13 +176,32 @@ &can1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_flexcan1>; + status = "disabled"; +}; + +&hdmi_core { + ipu_id = <0>; + disp_id = <0>; status = "okay"; }; -&hdmi { +&hdmi_video { + fsl,phy_reg_vlev = <0x0294>; + fsl,phy_reg_cksymtx = <0x800d>; + status = "okay"; +}; + +&hdmi_audio { + status = "okay"; +}; + +&ocram { + status = "okay"; +}; + +&hdmi_cec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_hdmi>; - ddc-i2c-bus = <&i2c2>; status = "okay"; }; @@ -133,21 +210,45 @@ 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; + status = "disabled"; }; /* Pro baseboard model */ sgtl5000: sgtl5000@0a { - clocks = <&clks IMX6QDL_CLK_CKO>; compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks IMX6QDL_CLK_CKO>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_sgtl5000>; - reg = <0x0a>; VDDA-supply = <®_3p3v>; VDDIO-supply = <®_3p3v>; + status = "disabled"; }; }; @@ -156,10 +257,47 @@ 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_flexcan1: hummingboard-flexcan1 { fsl,pins = < MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x80000000 @@ -193,6 +331,19 @@ >; }; + 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 = ; }; @@ -220,16 +371,21 @@ * Similar to pinctrl_usbotg_2, but we want it * pulled down for a fixed host connection. */ - fsl,pins = ; + 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 0x1f071 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x13071 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 >; }; @@ -243,9 +399,73 @@ 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>; @@ -257,10 +477,28 @@ status = "okay"; }; +&pwm3 { + status = "disabled"; +}; + +&pwm4 { + status = "disabled"; +}; + &spdif { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_spdif>; status = "okay"; + clocks = <&clks 197>, <&clks 0>, + <&clks 197>, <&clks 0>, + <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, + <&clks 0>; + clock-names = "core", "rxtx0", + "rxtx1", "rxtx2", + "rxtx3", "rxtx4", + "rxtx5", "rxtx6", + "rxtx7"; }; &ssi1 { diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-microsom.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2015-11-30 17:56:13.512142253 +0100 @@ -39,15 +39,98 @@ * 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: 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 MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 >; }; + + 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 + >; + }; }; }; @@ -56,3 +139,23 @@ pinctrl-0 = <&pinctrl_microsom_uart1>; status = "okay"; }; + +/* UART4 - Connected to optional BRCM Wifi/BT/FM */ +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */ +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>; + bus-width = <4>; + mmc-pwrseq = <&usdhc1_pwrseq>; + keep-power-in-suspend; + non-removable; + vmmc-supply = <®_brcm>; + status = "okay"; +}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sabresd.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-sabresd.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2015-11-30 17:56:13.512142253 +0100 @@ -57,6 +57,13 @@ 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_pcie: regulator@3 { compatible = "regulator-fixed"; reg = <3>; @@ -133,6 +140,13 @@ default-state = "on"; }; }; + + mipi_dsi_reset: mipi-dsi-reset { + compatible = "gpio-reset"; + reset-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>; + reset-delay-us = <50>; + #reset-cells = <0>; + }; }; &audmux { @@ -332,10 +346,24 @@ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 - MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x1b0b0 - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0 - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 - MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 + MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 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 >; }; @@ -525,6 +553,15 @@ status = "okay"; }; +&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"; +}; + &pwm1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm1>; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-sb-fx6.dtsi 2015-11-30 17:56:13.512142253 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-sb-fx6m.dtsi 2015-11-30 17:56:13.512142253 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-sb-fx6x.dtsi 2015-11-30 17:56:13.512142253 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6qdl-vero.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-vero.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-vero.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-vero.dtsi 2015-11-30 17:56:13.516141986 +0100 @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2014 Russell King + * Copyright (C) 2015 Sam Nazarko + * + * 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-verosom.dtsi" +#include "imx6qdl-verosom-ar8035.dtsi" +#include +#include + +/ { + chosen { + bootargs = "quiet console=ttymxc0,115200 rw root=/dev/mmcblk0p2"; + }; + + aliases { + mmc0 = &usdhc2; + mmc1 = &usdhc1; + mxcfb0 = &mxcfb1; + }; + + ir_recv: ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio3 9 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_ir>; + linux,rc-map-name = "rc-rc6-mce"; + }; + + pwmleds { + compatible = "pwm-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_pwm1>; + + front { + active-low; + label = "imx6:red:front"; + max-brightness = <248>; + pwms = <&pwm1 0 50000>; + }; + }; + + regulators { + compatible = "simple-bus"; + + reg_3p3v: 3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usbh1_vbus: usb-h1-vbus { + compatible = "regulator-fixed"; + regulator-boot-on; + regulator-always-on; + enable-active-high; + gpio = <&gpio1 0 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_usbh1_vbus>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_usbotg_vbus: usb-otg-vbus { + compatible = "regulator-fixed"; + regulator-boot-on; + regulator-always-on; + enable-active-high; + gpio = <&gpio3 22 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_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"; + spdif-controller = <&spdif>; + spdif-out; + }; + + 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 = ; + }; + }; + + sound-hdmi { + compatible = "fsl,imx6q-audio-hdmi", + "fsl,imx-audio-hdmi"; + model = "imx-audio-hdmi"; + hdmi-controller = <&hdmi_audio>; + }; + + mxcfb1: fb@0 { + compatible = "fsl,mxc_sdc_fb"; + disp_dev = "hdmi"; + interface_pix_fmt = "RGB24"; + mode_str ="1920x1080M@60"; + default_bpp = <32>; + int_clk = <0>; + late_init = <0>; + status = "okay"; + }; +}; + +&hdmi_core { + ipu_id = <0>; + disp_id = <0>; + status = "okay"; +}; + +&hdmi_video { + fsl,phy_reg_vlev = <0x0294>; + fsl,phy_reg_cksymtx = <0x800d>; + status = "okay"; +}; + +&hdmi_audio { + status = "okay"; +}; + +&hdmi_cec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_hdmi>; + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_i2c2>; + + status = "okay"; + + ddc: imx6_hdmi_i2c@50 { + compatible = "fsl,imx6-hdmi-i2c"; + reg = <0x50>; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_i2c3>; + + status = "okay"; + + rtc: pcf8523@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + }; +}; + +&iomuxc { + vero { + pinctrl_vero_hdmi: vero-hdmi { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; + + pinctrl_vero_i2c2: vero-i2c2 { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_vero_i2c3: vero-i2c3 { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_vero_ir: vero-ir { + fsl,pins = < + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 + >; + }; + + pinctrl_vero_pwm1: vero-pwm1-front-led { + fsl,pins = ; + }; + + pinctrl_vero_spdif: vero-spdif { + fsl,pins = ; + }; + + pinctrl_vero_usbh1: vero-usbh1 { + fsl,pins = ; + }; + + pinctrl_vero_usbh1_vbus: vero-usbh1-vbus { + fsl,pins = ; + }; + + pinctrl_vero_usbotg: vero-usbotg { + /* + * The vero 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_vero_usbotg_vbus: vero-usbotg-vbus { + fsl,pins = ; + }; + + pinctrl_vero_usdhc2_aux: vero-usdhc2-aux { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 + >; + }; + + pinctrl_vero_usdhc2: vero-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_gpio_key: gpio-key { + fsl,pins = < + MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x17059 + >; + }; + + pinctrl_vero_usdhc2_100mhz: vero-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_vero_usdhc2_200mhz: vero-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 + >; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&spdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_spdif>; + status = "okay"; +}; + +&usbh1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_usbh1>; + vbus-supply = <®_usbh1_vbus>; + status = "okay"; +}; + +&usbotg { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vero_usbotg>; + vbus-supply = <®_usbotg_vbus>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_vero_usdhc2_aux &pinctrl_vero_usdhc2>; + pinctrl-1 = <&pinctrl_vero_usdhc2_aux &pinctrl_vero_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_vero_usdhc2_aux &pinctrl_vero_usdhc2_200mhz>; + vmmc-supply = <®_3p3v>; + cd-gpios = <&gpio1 4 0>; + status = "okay"; + no-1-8-v; +}; + +&dcic1 { + dcic_id = <0>; + dcic_mux = "dcic-hdmi"; + status = "okay"; +}; + +&dcic2 { + dcic_id = <1>; + dcic_mux = "dcic-lvds1"; + status = "disabled"; +}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-verosom-ar8035.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-verosom-ar8035.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-verosom-ar8035.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-verosom-ar8035.dtsi 2015-11-30 17:56:13.516141986 +0100 @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2013,2014 Russell King + * Copyright (C) 2015 Sam Nazarko + * + * This describes the hookup for an AR8035 to the iMX6 on the Vero + * SOM. + * + * 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"; + pinctrl-0 = <&pinctrl_verosom_enet_ar8035>; + phy-mode = "rgmii"; + phy-reset-duration = <2>; + phy-reset-gpios = <&gpio4 15 0>; + status = "okay"; +}; + +&iomuxc { + enet { + pinctrl_verosom_enet_ar8035: verosom-enet-ar8035 { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b8b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + /* AR8035 reset */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x130b0 + /* AR8035 interrupt */ + MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x80000000 + /* GPIO16 -> AR8035 25MHz */ + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0xc0000000 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x80000000 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 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 0x1b030 + /* AR8035 pin strapping: PHYADDR#0: pull down */ + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030 + /* AR8035 pin strapping: PHYADDR#1: pull down */ + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030 + /* AR8035 pin strapping: MODE#1: pull up */ + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + /* AR8035 pin strapping: MODE#3: pull up */ + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + /* AR8035 pin strapping: MODE#0: pull down */ + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x13030 + + /* + * As the RMII pins are also connected to RGMII + * so that an AR8030 can be placed, set these + * to high-z with the same pulls as above. + * Use the GPIO settings to avoid changing the + * input select registers. + */ + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x03000 + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x03000 + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x03000 + >; + }; + }; +}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-verosom.dtsi linux-4.1.13/arch/arm/boot/dts/imx6qdl-verosom.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6qdl-verosom.dtsi 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6qdl-verosom.dtsi 2015-11-30 17:56:13.516141986 +0100 @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2013,2014 Russell King + * Copyright (C) 2015 Sam Nazarko + * + * 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_verosom_brcm_osc>; + enable-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>; + }; + + regulators { + compatible = "simple-bus"; + + reg_brcm: brcm-reg { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 19 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_verosom_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 { + verosom { + pinctrl_verosom_brcm_bt: verosom-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_verosom_brcm_osc: verosom-brcm-osc { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 + >; + }; + + pinctrl_verosom_brcm_reg: verosom-brcm-reg { + fsl,pins = < + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070 + >; + }; + + pinctrl_verosom_brcm_wifi: verosom-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_verosom_uart1: verosom-uart1 { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_verosom_uart4: verosom-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_verosom_usdhc1: verosom-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 + >; + }; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_verosom_uart1>; + status = "okay"; +}; + +/* UART4 - Connected to optional BRCM Wifi/BT/FM */ +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_verosom_brcm_bt &pinctrl_verosom_uart4>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */ +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_verosom_brcm_wifi &pinctrl_verosom_usdhc1>; + bus-width = <4>; + mmc-pwrseq = <&usdhc1_pwrseq>; + keep-power-in-suspend; + non-removable; + vmmc-supply = <®_brcm>; + status = "okay"; +}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6q.dtsi linux-4.1.13/arch/arm/boot/dts/imx6q.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6q.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6q.dtsi 2015-11-30 17:56:13.516141986 +0100 @@ -14,6 +14,7 @@ / { aliases { + ipu1 = &ipu2; spi4 = &ecspi5; }; @@ -32,7 +33,7 @@ 996000 1250000 852000 1250000 792000 1175000 - 396000 975000 + 396000 1175000 >; fsl,soc-operating-points = < /* ARM kHz SOC-PU uV */ @@ -47,9 +48,12 @@ <&clks IMX6QDL_CLK_PLL2_PFD2_396M>, <&clks IMX6QDL_CLK_STEP>, <&clks IMX6QDL_CLK_PLL1_SW>, - <&clks IMX6QDL_CLK_PLL1_SYS>; + <&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>; @@ -78,9 +82,58 @@ }; soc { - ocram: sram@00900000 { + + busfreq { /* BUSFREQ */ + compatible = "fsl,imx6_busfreq"; + clocks = <&clks 171>, <&clks 6>, <&clks 11>, <&clks 104>, <&clks 172>, <&clks 58>, + <&clks 18>, <&clks 60>, <&clks 20>, <&clks 3>; + clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", + "periph_pre", "periph_clk2", "periph_clk2_sel", "osc"; + interrupts = <0 107 0x04>, <0 112 0x4>, <0 113 0x4>, <0 114 0x4>; + interrupt-names = "irq_busfreq_0", "irq_busfreq_1", "irq_busfreq_2", "irq_busfreq_3"; + fsl,max_ddr_freq = <528000000>; + }; + + gpu@00130000 { + compatible = "fsl,imx6q-gpu"; + reg = <0x00130000 0x4000>, <0x00134000 0x4000>, + <0x02204000 0x4000>, <0x0 0x0>; + reg-names = "iobase_3d", "iobase_2d", + "iobase_vg", "phys_baseaddr"; + interrupts = <0 9 0x04>, <0 10 0x04>,<0 11 0x04>; + interrupt-names = "irq_3d", "irq_2d", "irq_vg"; + clocks = <&clks 26>, <&clks 143>, + <&clks 27>, <&clks 121>, + <&clks 122>, <&clks 74>; + clock-names = "gpu2d_axi_clk", "openvg_axi_clk", + "gpu3d_axi_clk", "gpu2d_clk", + "gpu3d_clk", "gpu3d_shader_clk"; + resets = <&src 0>, <&src 3>, <&src 3>; + reset-names = "gpu3d", "gpu2d", "gpuvg"; + power-domains = <&gpc 1>; + }; + + hdmi_cec: hdmi_cec@00120000 { + compatible = "fsl,imx6q-hdmi-cec"; + interrupts = <0 115 0x04>; + status = "disabled"; + }; + + 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>; + reg = <0x00905000 0x3B000>; clocks = <&clks IMX6QDL_CLK_OCRAM>; }; @@ -101,6 +154,10 @@ }; }; + vpu@02040000 { + status = "okay"; + }; + iomuxc: iomuxc@020e0000 { compatible = "fsl,imx6q-iomuxc"; @@ -142,6 +199,18 @@ }; }; + 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>; @@ -154,165 +223,33 @@ }; ipu2: ipu@02800000 { - #address-cells = <1>; - #size-cells = <0>; compatible = "fsl,imx6q-ipu"; reg = <0x02800000 0x400000>; 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>; - clock-names = "bus", "di0", "di1"; + clocks = <&clks 133>, <&clks 134>, <&clks 137>, + <&clks 41>, <&clks 42>, + <&clks 135>, <&clks 136>; + clock-names = "bus", "di0", "di1", + "di0_sel", "di1_sel", + "ldb_di0", "ldb_di1"; resets = <&src 4>; - - ipu2_csi0: port@0 { - reg = <0>; - }; - - ipu2_csi1: port@1 { - reg = <1>; - }; - - ipu2_di0: port@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - - ipu2_di0_disp0: endpoint@0 { - }; - - ipu2_di0_hdmi: endpoint@1 { - remote-endpoint = <&hdmi_mux_2>; - }; - - ipu2_di0_mipi: endpoint@2 { - }; - - ipu2_di0_lvds0: endpoint@3 { - remote-endpoint = <&lvds0_mux_2>; - }; - - ipu2_di0_lvds1: endpoint@4 { - remote-endpoint = <&lvds1_mux_2>; - }; - }; - - ipu2_di1: port@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - - ipu2_di1_hdmi: endpoint@1 { - remote-endpoint = <&hdmi_mux_3>; - }; - - ipu2_di1_mipi: endpoint@2 { - }; - - ipu2_di1_lvds0: endpoint@3 { - remote-endpoint = <&lvds0_mux_3>; - }; - - ipu2_di1_lvds1: endpoint@4 { - remote-endpoint = <&lvds1_mux_3>; - }; - }; - }; - }; - - display-subsystem { - compatible = "fsl,imx-display-subsystem"; - ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>; - }; -}; - -&hdmi { - compatible = "fsl,imx6q-hdmi"; - - port@2 { - reg = <2>; - - hdmi_mux_2: endpoint { - remote-endpoint = <&ipu2_di0_hdmi>; - }; - }; - - port@3 { - reg = <3>; - - hdmi_mux_3: endpoint { - remote-endpoint = <&ipu2_di1_hdmi>; + bypass_reset = <0>; }; }; }; &ldb { - clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_SEL>, + 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>, <&clks IMX6QDL_CLK_LDB_DI1>; - clock-names = "di0_pll", "di1_pll", - "di0_sel", "di1_sel", "di2_sel", "di3_sel", - "di0", "di1"; - - lvds-channel@0 { - port@2 { - reg = <2>; - - lvds0_mux_2: endpoint { - remote-endpoint = <&ipu2_di0_lvds0>; - }; - }; - - port@3 { - reg = <3>; - - lvds0_mux_3: endpoint { - remote-endpoint = <&ipu2_di1_lvds0>; - }; - }; - }; - - lvds-channel@1 { - port@2 { - reg = <2>; - - lvds1_mux_2: endpoint { - remote-endpoint = <&ipu2_di0_lvds1>; - }; - }; - - port@3 { - reg = <3>; - - lvds1_mux_3: endpoint { - remote-endpoint = <&ipu2_di1_lvds1>; - }; - }; - }; -}; - -&mipi_dsi { - ports { - port@2 { - reg = <2>; - - mipi_mux_2: endpoint { - remote-endpoint = <&ipu2_di0_mipi>; - }; - }; - - port@3 { - reg = <3>; - - mipi_mux_3: endpoint { - remote-endpoint = <&ipu2_di1_mipi>; - }; - }; - }; -}; - -&vpu { - compatible = "fsl,imx6q-vpu", "cnm,coda960"; + <&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-4.1.13.orig/arch/arm/boot/dts/imx6q-hummingboard2.dts linux-4.1.13/arch/arm/boot/dts/imx6q-hummingboard2.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6q-hummingboard2.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6q-hummingboard2.dts 2015-11-30 17:56:13.516141986 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6q-hummingboard.dts linux-4.1.13/arch/arm/boot/dts/imx6q-hummingboard.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6q-hummingboard.dts 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6q-hummingboard.dts 2015-11-30 17:56:13.516141986 +0100 @@ -48,6 +48,10 @@ / { model = "SolidRun HummingBoard Dual/Quad"; compatible = "solidrun,hummingboard/q", "fsl,imx6q"; + + sound-sgtl5000 { + status = "okay"; + }; }; &sata { @@ -57,3 +61,11 @@ fsl,transmit-atten-16ths = <9>; fsl,receive-eq-mdB = <3000>; }; + +&sgtl5000 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6q-sbc-fx6.dts linux-4.1.13/arch/arm/boot/dts/imx6q-sbc-fx6.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6q-sbc-fx6.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6q-sbc-fx6.dts 2015-11-30 17:56:13.516141986 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6q-sbc-fx6m.dts linux-4.1.13/arch/arm/boot/dts/imx6q-sbc-fx6m.dts --- linux-4.1.13.orig/arch/arm/boot/dts/imx6q-sbc-fx6m.dts 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6q-sbc-fx6m.dts 2015-11-30 17:56:13.516141986 +0100 @@ -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-4.1.13.orig/arch/arm/boot/dts/imx6sl.dtsi linux-4.1.13/arch/arm/boot/dts/imx6sl.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6sl.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6sl.dtsi 2015-11-30 17:56:13.520141720 +0100 @@ -457,20 +457,21 @@ anatop-min-bit-val = <4>; anatop-min-voltage = <800000>; anatop-max-voltage = <1375000>; + anatop-enable-bit = <0>; }; - regulator-3p0@120 { + reg_3p0: regulator-3p0@120 { compatible = "fsl,anatop-regulator"; regulator-name = "vdd3p0"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <3150000>; - regulator-always-on; + regulator-min-microvolt = <2625000>; + regulator-max-microvolt = <3400000>; 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>; + anatop-enable-bit = <0>; }; regulator-2p5@130 { @@ -485,6 +486,7 @@ anatop-min-bit-val = <0>; anatop-min-voltage = <2100000>; anatop-max-voltage = <2850000>; + anatop-enable-bit = <0>; }; reg_arm: regulator-vddcore@140 { @@ -552,6 +554,7 @@ reg = <0x020c9000 0x1000>; interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBPHY1>; + phy-3p0-supply = <®_3p0>; fsl,anatop = <&anatop>; }; @@ -560,6 +563,7 @@ reg = <0x020ca000 0x1000>; interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBPHY2>; + phy-3p0-supply = <®_3p0>; fsl,anatop = <&anatop>; }; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/imx6sx.dtsi linux-4.1.13/arch/arm/boot/dts/imx6sx.dtsi --- linux-4.1.13.orig/arch/arm/boot/dts/imx6sx.dtsi 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/imx6sx.dtsi 2015-11-30 17:56:13.520141720 +0100 @@ -556,20 +556,21 @@ anatop-min-bit-val = <4>; anatop-min-voltage = <800000>; anatop-max-voltage = <1375000>; + anatop-enable-bit = <0>; }; - regulator-3p0@120 { + reg_3p0: regulator-3p0@120 { compatible = "fsl,anatop-regulator"; regulator-name = "vdd3p0"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <3150000>; - regulator-always-on; + regulator-min-microvolt = <2625000>; + regulator-max-microvolt = <3400000>; 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>; + anatop-enable-bit = <0>; }; regulator-2p5@130 { @@ -584,6 +585,7 @@ anatop-min-bit-val = <0>; anatop-min-voltage = <2100000>; anatop-max-voltage = <2875000>; + anatop-enable-bit = <0>; }; reg_arm: regulator-vddcore@140 { @@ -650,6 +652,7 @@ reg = <0x020c9000 0x1000>; interrupts = ; clocks = <&clks IMX6SX_CLK_USBPHY1>; + phy-3p0-supply = <®_3p0>; fsl,anatop = <&anatop>; }; @@ -658,6 +661,7 @@ reg = <0x020ca000 0x1000>; interrupts = ; clocks = <&clks IMX6SX_CLK_USBPHY2>; + phy-3p0-supply = <®_3p0>; fsl,anatop = <&anatop>; }; diff -Nur linux-4.1.13.orig/arch/arm/boot/dts/Makefile linux-4.1.13/arch/arm/boot/dts/Makefile --- linux-4.1.13.orig/arch/arm/boot/dts/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/boot/dts/Makefile 2015-11-30 17:56:13.520141720 +0100 @@ -256,6 +256,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6dl-aristainetos_4.dtb \ imx6dl-aristainetos_7.dtb \ + imx6dl-cm-fx6.dtb \ imx6dl-cubox-i.dtb \ imx6dl-dfi-fs700-m60.dtb \ imx6dl-gw51xx.dtb \ @@ -264,6 +265,7 @@ imx6dl-gw54xx.dtb \ imx6dl-gw552x.dtb \ imx6dl-hummingboard.dtb \ + imx6dl-hummingboard2.dtb \ imx6dl-nitrogen6x.dtb \ imx6dl-phytec-pbab01.dtb \ imx6dl-rex-basic.dtb \ @@ -275,6 +277,8 @@ imx6dl-tx6u-801x.dtb \ imx6dl-tx6u-811x.dtb \ imx6dl-udoo.dtb \ + imx6dl-sbc-fx6.dtb \ + imx6dl-sbc-fx6m.dtb \ imx6dl-wandboard.dtb \ imx6dl-wandboard-revb1.dtb \ imx6q-arm2.dtb \ @@ -290,12 +294,20 @@ imx6q-gw54xx.dtb \ imx6q-gw552x.dtb \ imx6q-hummingboard.dtb \ + imx6q-hummingboard2.dtb \ imx6q-nitrogen6x.dtb \ imx6q-phytec-pbab01.dtb \ imx6q-rex-pro.dtb \ imx6q-sabreauto.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-tbs2910.dtb \ imx6q-tx6q-1010.dtb \ @@ -305,7 +317,8 @@ imx6q-tx6q-1110.dtb \ imx6q-udoo.dtb \ imx6q-wandboard.dtb \ - imx6q-wandboard-revb1.dtb + imx6q-wandboard-revb1.dtb \ + imx6dl-vero.dtb dtb-$(CONFIG_SOC_IMX6SL) += \ imx6sl-evk.dtb \ imx6sl-warp.dtb diff -Nur linux-4.1.13.orig/arch/arm/configs/cm_fx6_defconfig linux-4.1.13/arch/arm/configs/cm_fx6_defconfig --- linux-4.1.13.orig/arch/arm/configs/cm_fx6_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/configs/cm_fx6_defconfig 2015-11-30 17:56:13.520141720 +0100 @@ -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-4.1.13.orig/arch/arm/configs/imx_v7_cbi_hb_base_defconfig linux-4.1.13/arch/arm/configs/imx_v7_cbi_hb_base_defconfig --- linux-4.1.13.orig/arch/arm/configs/imx_v7_cbi_hb_base_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/configs/imx_v7_cbi_hb_base_defconfig 2015-11-30 17:56:13.524141455 +0100 @@ -0,0 +1,367 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZO=y +CONFIG_SYSVIPC=y +CONFIG_FHANDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_PERF_EVENTS=y +CONFIG_CLEANCACHE=y +# CONFIG_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=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_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_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_UTF8=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FTRACE is not set +CONFIG_SECURITYFS=y +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LRW=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_CRYPTO_RMD128=y +CONFIG_CRYPTO_RMD160=y +CONFIG_CRYPTO_RMD256=y +CONFIG_CRYPTO_RMD320=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_TGR192=y +CONFIG_CRYPTO_WP512=y +CONFIG_CRYPTO_BLOWFISH=y +CONFIG_CRYPTO_CAMELLIA=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y +# CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST is not set +CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC_T10DIF=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +# CONFIG_MXC_MMA8451 is not set +CONFIG_RC_CORE=m +CONFIG_RC_DECODERS=y +CONFIG_LIRC=m +CONFIG_RC_LOOPBACK=m +CONFIG_RC_MAP=m +CONFIG_RC_DEVICES=y +CONFIG_RC_ATI_REMOTE=m +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_RC5_SZ_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_LIRC_CODEC=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_ITE_CIR=m +CONFIG_IR_NUVOTON=m +CONFIG_IR_FINTEK=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_ENE=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_WINBOND_CIR=m +CONFIG_IR_IGUANA=m +CONFIG_IR_TTUSBIR=m +CONFIG_IR_GPIO_CIR=m diff -Nur linux-4.1.13.orig/arch/arm/configs/imx_v7_cbi_hb_defconfig linux-4.1.13/arch/arm/configs/imx_v7_cbi_hb_defconfig --- linux-4.1.13.orig/arch/arm/configs/imx_v7_cbi_hb_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/configs/imx_v7_cbi_hb_defconfig 2015-11-30 17:56:13.524141455 +0100 @@ -0,0 +1,5139 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MMU=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +CONFIG_LOCALVERSION="" +CONFIG_CROSS_COMPILE="" +CONFIG_DEFAULT_HOSTNAME="(none)" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_HOTPLUG=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_PREVENT_FIRMWARE_BUILD=y + +CONFIG_BUILD_DOCSRC=y + +# +# General setup +# +CONFIG_KERNEL_LZO=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_SWAP=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_COMPILE_TEST is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_SYSCTL=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_IOSCHED_BFQ=y +CONFIG_CGROUP_BFQIO=y +CONFIG_DEFAULT_BFQ=y +CONFIG_DEFAULT_IOSCHED="bfq" +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_PID_NS=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_NET_NS=y +CONFIG_USER_NS=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +CONFIG_SYSVIPC=y +CONFIG_FHANDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y + +CONFIG_POSIX_MQUEUE=y +CONFIG_PREEMPT_VOLUNTARY=y + +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SLUB_STATS is not set +# CONFIG_SLUB_DEBUG_ON is not set + +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_IWMC3200TOP is not set +# CONFIG_BLK_DEV_BSG is not set + +# MX6 specific kernel configuration +CONFIG_GPIO_PCA953X=y +CONFIG_ARCH_MXC=y +CONFIG_MXC_DEBUG_BOARD=y +CONFIG_SOC_IMX6Q=y +# CONFIG_SOC_IMX6SL 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_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_IMX_THERMAL=y +CONFIG_DEVICE_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_IMX2_WDT=y +CONFIG_MFD_DA9052_I2C=y +CONFIG_MFD_MC13XXX_SPI=y +CONFIG_MFD_MC13XXX_I2C=y +CONFIG_MFD_SI476X_CORE=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_ANATOP=y +CONFIG_REGULATOR_PFUZE100=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_RADIO_SUPPORT is not set +CONFIG_VIDEO_V4L2_INT_DEVICE=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +# CONFIG_RADIO_ADAPTERS is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_MXC_OUTPUT=y +CONFIG_VIDEO_MXC_CAPTURE=m +CONFIG_VIDEO_MXC_CSI_CAMERA=m +CONFIG_MXC_CAMERA_OV5640=m +CONFIG_MXC_CAMERA_OV5642=m +CONFIG_MXC_CAMERA_OV5640_MIPI=m +CONFIG_MXC_TVIN_ADV7180=m +CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m +CONFIG_VIDEO_MXC_IPU_OUTPUT=y +CONFIG_VIDEO_MXC_PXP_V4L2=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2640=y +CONFIG_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_USER=y +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LRW=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_CRYPTO_RMD128=y +CONFIG_CRYPTO_RMD160=y +CONFIG_CRYPTO_RMD256=y +CONFIG_CRYPTO_RMD320=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_TGR192=y +CONFIG_CRYPTO_WP512=y +CONFIG_CRYPTO_BLOWFISH=y +CONFIG_CRYPTO_CAMELLIA=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y +# CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST is not set +CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC_T10DIF=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +# CONFIG_MXC_MMA8451 is not set + +# +# Loadable module support +# +# CONFIG_MODULE_FORCE_LOAD is not set +# -- MODULE_FORCE_UNLOAD is controlled by config-debug/nodebug + +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_STUB=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_HT_IRQ=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEBUG is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEAER_INJECT=m +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_HOTPLUG_PCI_FAKE=m + +# CONFIG_SGI_IOC4 is not set + +# CONFIG_ISA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# FIXME: Deprecate Cardbus ? +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_PD6729=m + +CONFIG_PCCARD=y +CONFIG_SDIO_UART=m +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_DEBUG is not set +# https://lists.fedoraproject.org/pipermail/kernel/2014-February/004889.html +# CONFIG_MMC_CLKGATE is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_SDHCI_PCI=m +CONFIG_MMC_SDHCI_ACPI=m +CONFIG_MMC_SDRICOH_CS=m +CONFIG_MMC_TIFM_SD=m +CONFIG_MMC_WBSD=m +CONFIG_MMC_VIA_SDMMC=m +CONFIG_MMC_CB710=m +CONFIG_MMC_RICOH_MMC=y +CONFIG_MMC_USHC=m +CONFIG_MMC_REALTEK_PCI=m +CONFIG_MMC_VUB300=m +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set + + +CONFIG_CB710_CORE=m +# CONFIG_CB710_DEBUG is not set + +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_MTHCA=m +# CONFIG_INFINIBAND_MTHCA_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_DEBUG=y +CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_SRPT=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +# CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING is not set #staging +CONFIG_INFINIBAND_IPATH=m +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_ISERT=m +CONFIG_INFINIBAND_AMSO1100=m +# CONFIG_INFINIBAND_AMSO1100_DEBUG is not set +CONFIG_INFINIBAND_CXGB3=m +CONFIG_INFINIBAND_CXGB4=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_MLX4_INFINIBAND=m +CONFIG_MLX5_INFINIBAND=m +CONFIG_INFINIBAND_NES=m +# CONFIG_INFINIBAND_NES_DEBUG is not set +CONFIG_INFINIBAND_QIB=m +CONFIG_INFINIBAND_QIB_DCA=y +# CONFIG_INFINIBAND_OCRDMA is not set +# CONFIG_INFINIBAND_USNIC is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_SCRIPT=y + +# +# Device Drivers +# + +# CONFIG_COMMON_CLK_SI5351 is not set + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" + +# Give this a try in rawhide for now +# CONFIG_FW_LOADER_USER_HELPER is not set + + + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +# CONFIG_MTD_BLKDEVS is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_TS5500 is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# Self-contained MTD device drivers +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_LPDDR is not set +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_LIMIT=20 +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +CONFIG_PARPORT_1284=y +# CONFIG_PARPORT_AX88796 is not set + +CONFIG_ACPI_PCI_SLOT=y +CONFIG_HOTPLUG_PCI_ACPI=y +CONFIG_HOTPLUG_PCI_ACPI_IBM=m + +# +# Block devices +# +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_NULL_BLK=m +CONFIG_BLK_DEV_FD=m +# CONFIG_PARIDE is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_DEBUG is not set +CONFIG_ENHANCEIO=m + +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 +# Fedora 18 util-linux is the last release that supports cryptoloop devices +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_NVME=m +CONFIG_BLK_DEV_SKD=m # 64-bit only but easier to put here +CONFIG_BLK_DEV_OSD=m +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_IO_TRACE=y + +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_THROTTLING=y +# CONFIG_BLK_CMDLINE_PARSER is not set + + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_RSXX is not set + +CONFIG_SCSI_VIRTIO=m +CONFIG_VIRTIO_BLK=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_MMIO=m +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set +CONFIG_VIRTIO_NET=m +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_VIRTIO_CONSOLE=m +CONFIG_VHOST_NET=m +CONFIG_TCM_VHOST=m +CONFIG_VHOST_SCSI=m + +# +# SCSI device support +# +CONFIG_SCSI=y + +CONFIG_SCSI_ENCLOSURE=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_TGT=m +CONFIG_SCSI_ISCI=m +CONFIG_SCSI_CHELSIO_FCOE=m + +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +CONFIG_RAID_ATTRS=m + +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +# http://lists.fedoraproject.org/pipermail/kernel/2013-February/004102.html +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +# CONFIG_SCSI_ADVANSYS is not set +CONFIG_SCSI_BFA_FC=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_ESAS2R=m +CONFIG_SCSI_MVSAS=m +# CONFIG_SCSI_MVSAS_DEBUG is not set +CONFIG_SCSI_MVSAS_TASKLET=y +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_MPT2SAS_MAX_SGE=128 +CONFIG_SCSI_MPT2SAS_LOGGING=y +CONFIG_SCSI_MPT3SAS=m +CONFIG_SCSI_MPT3SAS_MAX_SGE=128 +CONFIG_SCSI_MPT3SAS_LOGGING=y + +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m +# CONFIG_SCSI_UFSHCD_PLATFORM is not set + +CONFIG_SCSI_MVUMI=m + +CONFIG_SCSI_OSD_INITIATOR=m +CONFIG_SCSI_OSD_ULD=m +CONFIG_SCSI_OSD_DPRINT_SENSE=1 +# CONFIG_SCSI_OSD_DEBUG is not set + +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2X_FCOE=m +CONFIG_BE2ISCSI=m +CONFIG_SCSI_PMCRAID=m + +CONFIG_SCSI_HPSA=m +CONFIG_SCSI_3W_SAS=m +CONFIG_SCSI_PM8001=m +CONFIG_VMWARE_PVSCSI=m +CONFIG_VMWARE_BALLOON=m + +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_FLASHPOINT=y +CONFIG_SCSI_DMX3191D=m +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_DC395x=m +# CONFIG_SCSI_NSP32 is not set +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_QLA_FC=m +CONFIG_TCM_QLA2XXX=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_IPR=m +CONFIG_SCSI_IPR_TRACE=y +CONFIG_SCSI_IPR_DUMP=y +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_LPFC=m +# CONFIG_SCSI_LPFC_DEBUG_FS is not set + +# PCMCIA SCSI adapter support +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set + +CONFIG_ATA_BMDMA=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_SFF=y +CONFIG_ATA_PIIX=y +# CONFIG_SATA_HIGHBANK is not set +CONFIG_ATA_ACPI=y +CONFIG_BLK_DEV_SX8=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_AHCI=y +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PMP=y +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_RCAR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_ACARD_AHCI=m + +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_ACPI=m +CONFIG_PATA_ALI=m +CONFIG_PATA_AMD=m +CONFIG_PATA_ARASAN_CF=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +CONFIG_PATA_CMD640_PCI=m +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +CONFIG_PATA_CS5530=m +CONFIG_PATA_CS5535=m +CONFIG_PATA_CS5536=m +CONFIG_PATA_CYPRESS=m +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_HPT366=m +CONFIG_PATA_HPT37X=m +CONFIG_PATA_HPT3X2N=m +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +CONFIG_PATA_IT821X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_NINJA32=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_NS87410=m +CONFIG_PATA_NS87415=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_OPTI=m +CONFIG_PATA_OPTIDMA=m +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC_OLD=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RDC=m +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SCH=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TOSHIBA=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PATA_ATP867X=m + + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m + +CONFIG_BCACHE=m +# CONFIG_BCACHE_DEBUG is not set +# CONFIG_BCACHE_EDEBUG is not set +# CONFIG_BCACHE_CLOSURES_DEBUG is not set + +# CONFIG_MULTICORE_RAID456 is not set +CONFIG_ASYNC_RAID6_TEST=m +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=m +CONFIG_DM_DEBUG=y +CONFIG_DM_DELAY=m +CONFIG_DM_MIRROR=y +CONFIG_DM_MULTIPATH=m +CONFIG_DM_SNAPSHOT=y +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_CACHE_MQ=m +CONFIG_DM_CACHE_CLEANER=m +# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set +# CONFIG_DM_DEBUG_SPACE_MAPS is not set +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=y +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_RAID=m +CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m +CONFIG_DM_SWITCH=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_MAX_SGE=40 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support (JUJU alternative stack) +# +CONFIG_FIREWIRE=m +CONFIG_FIREWIRE_OHCI=m +CONFIG_FIREWIRE_SBP2=m +CONFIG_FIREWIRE_NET=m +CONFIG_FIREWIRE_OHCI_DEBUG=y +CONFIG_FIREWIRE_NOSY=m +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIREWIRE_OHCI_REMOTE_DMA is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_LCT_NOTIFY_ON_CHANGES is not set + +# +# Virtualization support drivers +# +# CONFIG_VIRT_DRIVERS is not set + +# Networking support +# + +CONFIG_NET_DMA=y + +CONFIG_NETLINK_MMAP=y +CONFIG_NETLINK_DIAG=m + +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m + +CONFIG_TCP_MD5SIG=y + +# +# Networking options +# +CONFIG_PACKET_DIAG=m +CONFIG_UNIX_DIAG=m +CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=m +CONFIG_INET_UDP_DIAG=m +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_FIB_TRIE_STATS=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_NF_SECURITY=m +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=m +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL_TRAP=y +CONFIG_NET_POLL_CONTROLLER=y + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_PE_SIP=m + +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y + +CONFIG_RDS=m +# CONFIG_RDS_DEBUG is not set +CONFIG_RDS_RDMA=m +CONFIG_RDS_TCP=m + +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_RDMA=m + +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_BRIDGE_VLAN_FILTERING=y + +# PHY timestamping adds overhead +CONFIG_NETWORK_PHY_TIMESTAMPING=y + +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NF_CONNTRACK=m +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_QUEUE_CT=y +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_TPROXY=m +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_MARK=m +CONFIG_NETFILTER_XT_CONNMARK=m + +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_RATEEST=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m + +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ECN=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_HL=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m + +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# + +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y # check if contrack(8) in f17 supports netlink +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_CT_PROTO_DCCP=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_NETLINK=m +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NF_CT_PROTO_UDPLITE=m + +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m + +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +# CONFIG_IP6_NF_TARGET_NPT is not set + +# nf_tables support +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=m +CONFIG_NFT_EXTHDR=m +CONFIG_NFT_META=m +CONFIG_NFT_CT=m +CONFIG_NFT_RBTREE=m +CONFIG_NFT_HASH=m +CONFIG_NFT_COUNTER=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_NAT=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m + +CONFIG_NF_TABLES_IPV4=m +CONFIG_NFT_REJECT_IPV4=m +CONFIG_NFT_CHAIN_ROUTE_IPV4=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NF_TABLES_ARP=m + +CONFIG_NF_TABLES_IPV6=m +CONFIG_NFT_CHAIN_ROUTE_IPV6=m +CONFIG_NFT_CHAIN_NAT_IPV6=m + +CONFIG_NF_TABLES_BRIDGE=m +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_XFRM=y +CONFIG_XFRM_MIGRATE=y +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_BEET=m + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_NETPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETNET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +CONFIG_NET_SCTPPROBE=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y +# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set +# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set +CONFIG_SCTP_COOKIE_HMAC_MD5=y +CONFIG_SCTP_COOKIE_HMAC_SHA1=y +CONFIG_ATM=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=y +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +# CONFIG_IP_DCCP_DEBUG is not set +# CONFIG_NET_DCCPPROBE is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +CONFIG_TIPC=m +CONFIG_TIPC_PORTS=8192 +# CONFIG_TIPC_MEDIA_IB is not set +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set + +CONFIG_NETLABEL=y + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=m +CONFIG_NET_SCH_FQ=m +CONFIG_NET_SCH_HHF=m +CONFIG_NET_SCH_PIE=m +CONFIG_NET_SCH_PLUG=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_CGROUP=y +CONFIG_NET_CLS_BPF=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_IND=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_MARK=y +CONFIG_CLS_U32_PERF=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_EMATCH_U32=m + +CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m + +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=m +CONFIG_BATMAN_ADV=m +CONFIG_BATMAN_ADV_BLA=y +CONFIG_BATMAN_ADV_DAT=y +CONFIG_BATMAN_ADV_NC=y + +# CONFIG_BATMAN_ADV_DEBUG is not set +CONFIG_OPENVSWITCH=m +CONFIG_OPENVSWITCH_GRE=y +CONFIG_OPENVSWITCH_VXLAN=y +CONFIG_VSOCKETS=m + + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +# CONFIG_NET_TCPPROBE is not set +CONFIG_NET_DROP_MONITOR=y + +# disable later --kyle + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_IFB=m +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_NET_TEAM_MODE_BROADCAST=m +CONFIG_NET_TEAM_MODE_RANDOM=m +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_VXLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NLMON=m + +# +# ATM +# +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_BR2684=m +CONFIG_NET_SCH_ATM=m +CONFIG_ATM_TCP=m +# CONFIG_ATM_LANAI is not set +CONFIG_ATM_ENI=m +CONFIG_ATM_FIRESTREAM=m +# CONFIG_ATM_ZATM is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 + +CONFIG_ATM_HE=m +CONFIG_PPTP=m +CONFIG_PPPOATM=m +CONFIG_PPPOL2TP=m +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_IA is not set +# CONFIG_ATM_CLIP_NO_ICMP is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_BR2684_IPFILTER is not set +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +# CONFIG_ATM_ZATM_DEBUG is not set +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +# CONFIG_ATM_HORIZON_DEBUG is not set +# CONFIG_ATM_HE_USE_SUNI is not set +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_SOLOS=m + +CONFIG_L2TP=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m + +# CONFIG_CAIF is not set + +CONFIG_RFKILL=m +CONFIG_RFKILL_GPIO=m +CONFIG_RFKILL_INPUT=y + + +# +# Ethernet (10 or 100Mbit) +# + +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_ADAPTEC_STARFIRE=m + +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set + +CONFIG_NET_VENDOR_AMD=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_PCMCIA_NMCLAN=m + +CONFIG_NET_VENDOR_ARC=y +CONFIG_ARC_EMAC=m + +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_ALX=m +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1C=m +CONFIG_ATL1E=m +CONFIG_NET_CADENCE=y +CONFIG_ARM_AT91_ETHER=m +CONFIG_MACB=m + +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_BNA=m +CONFIG_NET_CALXEDA_XGMAC=m + +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHELSIO_T4=m +CONFIG_CHELSIO_T4VF=m + +CONFIG_NET_VENDOR_CISCO=y +CONFIG_ENIC=m + +CONFIG_NET_VENDOR_DEC=y +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_DE2104X_DSL=0 +CONFIG_TULIP=m +# CONFIG_TULIP_NAPI is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_NI5010 is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_ULI526X=m + +CONFIG_NET_VENDOR_DLINK=y +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_DL2K=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set + +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m + +CONFIG_NET_VENDOR_EXAR=y +CONFIG_S2IO=m +CONFIG_VXGE=m +# CONFIG_VXGE_DEBUG_TRACE_ALL is not set + +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_FUJITSU is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IGB_HWMON=y +CONFIG_IGB_DCA=y +CONFIG_IGB_PTP=y +CONFIG_IGBVF=m +CONFIG_IXGB=m +CONFIG_IXGBEVF=m +CONFIG_IXGBE=m +CONFIG_IXGBE_DCA=y +CONFIG_IXGBE_DCB=y +CONFIG_IXGBE_HWMON=y +CONFIG_IXGBE_PTP=y +CONFIG_I40E=m +# CONFIG_I40E_VXLAN is not set +# CONFIG_I40E_DCB is not set +# CONFIG_I40EVF is not set + + +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_MVMDIO=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKGE_GENESIS=y +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set + +CONFIG_NET_VENDOR_MICREL=y +CONFIG_KSZ884X_PCI=m +# CONFIG_KS8842 is not set +# CONFIG_KS8851_MLL is not set + +CONFIG_NET_VENDOR_MYRI=y +CONFIG_MYRI10GE=m +CONFIG_MYRI10GE_DCA=y + +CONFIG_NATSEMI=m +CONFIG_NS83820=m + +CONFIG_PCMCIA_AXNET=m +CONFIG_NE2K_PCI=m +CONFIG_NE3210=m +CONFIG_PCMCIA_PCNET=m + +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_FORCEDETH=m + +CONFIG_NET_VENDOR_OKI=y +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PTP is not set + +CONFIG_NET_PACKET_ENGINE=y +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m + +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_QLA3XXX=m +CONFIG_QLCNIC=m +CONFIG_QLCNIC_SRIOV=y +CONFIG_QLCNIC_DCB=y +CONFIG_QLGE=m +CONFIG_NETXEN_NIC=m + +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_ATP=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_R8169=m + + +CONFIG_NET_VENDOR_RDC=y +CONFIG_R6040=m + + +CONFIG_NET_VENDOR_SILAN=y +CONFIG_SC92031=m + +CONFIG_NET_VENDOR_SIS=y +CONFIG_SIS900=m +CONFIG_SIS190=m + +CONFIG_PCMCIA_SMC91C92=m +CONFIG_EPIC100=m +CONFIG_SMSC9420=m + +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_DA is not set +# CONFIG_STMMAC_DUAL_MAC is not set +# CONFIG_STMMAC_TIMER is not set +# CONFIG_STMMAC_DEBUG_FS is not set + +CONFIG_NET_VENDOR_SUN=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NIU=m + +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_TEHUTI=m + +CONFIG_NET_VENDOR_TI=y +CONFIG_TLAN=m + +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y + +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5300=m +CONFIG_NET_VENDOR_XIRCOM=y +CONFIG_PCMCIA_XIRC2PS=m + +CONFIG_AMD_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_BCM87XX_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_DP83640_PHY=m +CONFIG_FIXED_PHY=y +CONFIG_MDIO_BITBANG=m +CONFIG_NATIONAL_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_BCM63XX_PHY=m +CONFIG_LSI_ET1011C_PHY=m +CONFIG_LXT_PHY=m +CONFIG_MARVELL_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_REALTEK_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_STE10XP=m +CONFIG_VITESSE_PHY=m +CONFIG_MICREL_PHY=m + +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_DNET=m + + +CONFIG_LNE390=m +CONFIG_ES3210=m +CONFIG_NET_PCI=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_BNX2=m +CONFIG_BNX2X=m +CONFIG_BNX2X_SRIOV=y +CONFIG_CNIC=m +CONFIG_FEALNX=m +CONFIG_NET_POCKET=y + +# +# Ethernet (1000 Mbit) +# +CONFIG_TIGON3=m +CONFIG_JME=m + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IP1000 is not set +# CONFIG_MLX4_EN is not set +# CONFIG_SFC is not set + +# CONFIG_FDDI is not set +# CONFIG_DEFXX is not set +# CONFIG_SKFP is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_IPPP_FILTER=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPPOE=m +CONFIG_PPP_MPPE=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +# CONFIG_SLIP_MODE_SLIP6 is not set + +# +# Wireless LAN +# +# +# CONFIG_STRIP is not set +# CONFIG_PCMCIA_RAYCS is not set + +CONFIG_CFG80211_WEXT=y +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_NL80211=y +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_WIRELESS_EXT_SYSFS is not set +CONFIG_LIB80211=m +CONFIG_LIB80211_CRYPT_WEP=m +CONFIG_LIB80211_CRYPT_CCMP=m +CONFIG_LIB80211_CRYPT_TKIP=m +# CONFIG_LIB80211_DEBUG is not set + +CONFIG_MAC80211=m +CONFIG_MAC80211_RC_MINSTREL=y +# CONFIG_MAC80211_RC_DEFAULT_PID is not set +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel" +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_LEDS=y +# CONFIG_MAC80211_DEBUG_MENU is not set + +# CONFIG_WIMAX is not set + +# CONFIG_ADM8211 is not set +CONFIG_ATH_COMMON=m +CONFIG_ATH_CARDS=m +CONFIG_ATH5K=m +CONFIG_ATH5K_DEBUG=y +# CONFIG_ATH5K_TRACER is not set +CONFIG_ATH6KL=m +CONFIG_ATH6KL_DEBUG=y +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m +# CONFIG_ATH6KL_TRACING is not set +CONFIG_AR5523=m +CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +CONFIG_ATH9K_AHB=y +# CONFIG_ATH9K_DEBUG is not set +# CONFIG_ATH9K_MAC_DEBUG is not set +CONFIG_ATH9K_HTC=m +CONFIG_ATH9K_BTCOEX_SUPPORT=y +# CONFIG_ATH9K_LEGACY_RATE_CONTROL is not set +# CONFIG_ATH9K_WOW is not set +# +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +# CONFIG_ATH10K_DEBUG is not set +# CONFIG_ATH10K_TRACING is not set +CONFIG_ATH10K_DEBUGFS=y +CONFIG_WCN36XX=m +# CONFIG_WCN36XX_DEBUGFS is not set +CONFIG_WIL6210=m +CONFIG_WIL6210_ISR_COR=y +# CONFIG_WIL6210_TRACING is not set +CONFIG_CARL9170=m +CONFIG_CARL9170_LEDS=y +# CONFIG_CARL9170_HWRNG is not set +CONFIG_AT76C50X_USB=m +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_ATMEL is not set +CONFIG_B43=m +CONFIG_B43_PCMCIA=y +CONFIG_B43_SDIO=y +CONFIG_B43_BCMA=y +# CONFIG_B43_BCMA_EXTRA is not set +CONFIG_B43_BCMA_PIO=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43_PHY_LP=y +CONFIG_B43_PHY_N=y +CONFIG_B43_PHY_HT=y +# CONFIG_B43_FORCE_PIO is not set +CONFIG_B43LEGACY=m +# CONFIG_B43LEGACY_DEBUG is not set +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_PIO=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_BRCMSMAC=m +# CONFIG_BRCMFMAC_SDIO_OOB is not set +CONFIG_BRCMFMAC_USB=y +# CONFIG_BRCM_TRACING is not set +# CONFIG_BRCMISCAN is not set +# CONFIG_BRCMDBG is not set +CONFIG_HERMES=m +CONFIG_HERMES_CACHE_FW_ON_INIT=y +# CONFIG_HERMES_PRISM is not set +CONFIG_NORTEL_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_PCMCIA_HERMES=m +CONFIG_ORINOCO_USB=m +# CONFIG_TMD_HERMES is not set +# CONFIG_PCMCIA_SPECTRUM is not set +CONFIG_CW1200=m +CONFIG_CW1200_WLAN_SDIO=m +CONFIG_CW1200_WLAN_SPI=m +# CONFIG_HOSTAP is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_IPW2100_DEBUG is not set +# CONFIG_IPW2200_DEBUG is not set +# CONFIG_LIBIPW_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_CS=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +# CONFIG_LIBERTAS_THINFIRM is not set +CONFIG_LIBERTAS_MESH=y +CONFIG_IWLWIFI=m +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_IWLWIFI_DEBUG=y +CONFIG_IWLWIFI_DEVICE_SVTOOL=y +# CONFIG_IWLWIFI_EXPERIMENTAL_MFP is not set +CONFIG_IWLWIFI_UCODE16=y +# CONFIG_IWLWIFI_P2P is not set +CONFIG_IWLEGACY=m +CONFIG_IWLEGACY_DEBUG=y +# CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING is not set +CONFIG_IWL4965=y +CONFIG_IWL3945=m +# CONFIG_IWM is not set +# CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE is not set +CONFIG_MAC80211_HWSIM=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +CONFIG_MWL8K=m +# CONFIG_PRISM54 is not set +# CONFIG_PCMCIA_WL3501 is not set +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2400PCI=m +CONFIG_RT2500PCI=m +CONFIG_RT61PCI=m +CONFIG_RT2500USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT33XX=y +CONFIG_RT2800USB_RT35XX=y +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RT2800PCI=m +CONFIG_RT2800PCI_RT3290=y +CONFIG_RT2800PCI_RT33XX=y +CONFIG_RT2800PCI_RT35XX=y +CONFIG_RT2800PCI_RT53XX=y +CONFIG_RT73USB=m +CONFIG_RTL8180=m +CONFIG_RTL8187=m +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_SR9800 is not set +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_NET_SMSC75XX=m +# CONFIG_WL_TI is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set + +CONFIG_WL12XX=m +CONFIG_WL12XX_SPI=m +CONFIG_WL12XX_SDIO=m + +CONFIG_WL1251=m +CONFIG_WL1251_SPI=m +CONFIG_WL1251_SDIO=m + +CONFIG_RTL_CARDS=m +CONFIG_RTLWIFI=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192CU=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8188EE=m + +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_PCIE=m +CONFIG_MWIFIEX_USB=m + +# +# Token Ring devices +# +# CONFIG_TR is not set + +CONFIG_NET_FC=y + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m + +# +# Amateur Radio support +# +CONFIG_HAMRADIO=y +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y + +# CONFIG_CAN is not set + +CONFIG_NETROM=m +CONFIG_ROSE=m +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_YAM=m + +CONFIG_NFC=m +CONFIG_NFC_DIGITAL=m +CONFIG_NFC_NCI=m +CONFIG_NFC_HCI=m +CONFIG_NFC_SHDLC=y +CONFIG_NFC_LLCP=y +CONFIG_NFC_SIM=m +CONFIG_NFC_MRVL=m +CONFIG_NFC_MRVL_USB=m + +# +# Near Field Communication (NFC) devices +# +CONFIG_NFC_PORT100=m +CONFIG_NFC_PN544=m +CONFIG_NFC_PN544_I2C=m +CONFIG_NFC_PN533=m +CONFIG_NFC_MICROREAD=m +CONFIG_NFC_MICROREAD_I2C=m + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m +# CONFIG_IRDA_DEBUG is not set +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRTTY_SIR=m +CONFIG_DONGLE=y +CONFIG_ACTISYS_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_ESI_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TOIM3232_DONGLE=m + +CONFIG_ALI_FIR=m +CONFIG_MCS_FIR=m +CONFIG_NSC_FIR=m +CONFIG_SIGMATEL_FIR=m +CONFIG_SMC_IRCC_FIR=m +# CONFIG_TOSHIBA_FIR is not set +CONFIG_USB_IRDA=m +CONFIG_VLSI_FIR=m +CONFIG_VIA_FIR=m +CONFIG_WINBOND_FIR=m + +# +# Bluetooth support +# +CONFIG_BT=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_CMTP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIBTUSB=m +# Disable the BT_HCIUSB driver. +# It sucks more power than BT_HCIBTUSB which has the same functionality. +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_3WIRE=y +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_MRVL=m +CONFIG_BT_MRVL_SDIO=m +CONFIG_BT_ATH3K=m +CONFIG_BT_WILINK=m + +# +# ISDN subsystem +# +CONFIG_ISDN=y +CONFIG_MISDN=m +CONFIG_MISDN_DSP=m +CONFIG_MISDN_L1OIP=m +CONFIG_MISDN_AVMFRITZ=m +CONFIG_MISDN_SPEEDFAX=m +CONFIG_MISDN_INFINEON=m +CONFIG_MISDN_W6692=m +CONFIG_MISDN_NETJET=m + +# +# mISDN hardware drivers +# +CONFIG_MISDN_HFCPCI=m +CONFIG_MISDN_HFCMULTI=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m + +CONFIG_MISDN_HFCUSB=m + +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_TTY_FAX=y +CONFIG_DE_AOC=y + +CONFIG_ISDN_AUDIO=y + +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m + +CONFIG_ISDN_CAPI_CAPIDRV=m +CONFIG_ISDN_DIVERSION=m + +CONFIG_HISAX_EURO=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_ST5481=m +# CONFIG_HISAX_HFCUSB is not set +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_TELES_CS=m +CONFIG_HISAX_HFC4S8S=m + +CONFIG_ISDN_DRV_LOOP=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y + + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +# CONFIG_CAPI_TRACE is not set +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y + +# +# Active Eicon DIVA Server cards +# +# CONFIG_CAPI_EICON is not set +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_CAPI=y +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M101=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_DEBUG is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_MATRIXKMAP is not set + +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_HANWANG=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m + +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_CM109=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_SPARSEKMAP=m +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_IMS_PCU is not set +CONFIG_INPUT_CMA3000=m +CONFIG_INPUT_CMA3000_I2C=m +CONFIG_INPUT_IDEAPAD_SLIDEBAR=m + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_RAW=m +CONFIG_SERIO_ALTERA_PS2=m +# CONFIG_SERIO_PS2MULT is not set +CONFIG_SERIO_ARC_PS2=m +# CONFIG_SERIO_APBPS2 is not set + +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_OLPC_APSP is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_OMAP4 is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_SENTELIC=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_BCM5974=m +CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m +CONFIG_MOUSE_CYAPA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WALKERA0701=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_ZHENHUA=m +# CONFIG_JOYSTICK_AS5011 is not set + +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_AD7879_I2C=m +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +CONFIG_TOUCHSCREEN_DYNAPRO=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_EETI=m +CONFIG_TOUCHSCREEN_EGALAX=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_ILI210X=m +CONFIG_TOUCHSCREEN_MMS114=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MCS5000=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_TOUCHSCREEN_TSC_SERIO=m +CONFIG_TOUCHSCREEN_TSC2007=m +CONFIG_TOUCHSCREEN_TOUCHIT213=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_PIXCIR=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_WACOM_W8001=m +CONFIG_TOUCHSCREEN_WACOM_I2C=m +CONFIG_TOUCHSCREEN_USB_E2I=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +# CONFIG_TOUCHSCREEN_WM97XX is not set +CONFIG_TOUCHSCREEN_W90X900=m +# CONFIG_TOUCHSCREEN_BU21013 is not set +CONFIG_TOUCHSCREEN_ST1232=m +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +# CONFIG_TOUCHSCREEN_MAX11801 is not set +CONFIG_TOUCHSCREEN_AUO_PIXCIR=m +CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m +CONFIG_TOUCHSCREEN_ZFORCE=m + +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_RETU_PWRBUTTON=m +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_ATLAS_BTNS=m + +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m + +CONFIG_MAC_EMUMOUSEBTN=y + +CONFIG_INPUT_WM831X_ON=m + + +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_PCF8574 is not set +CONFIG_INPUT_MMA8450=m +CONFIG_INPUT_MPU3050=m +CONFIG_INPUT_KXTJ9=m +# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +CONFIG_N_GSM=m +# CONFIG_TRACE_SINK is not set +# CONFIG_STALDRV is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_TCG_TIS_I2C_ATMEL is not set +# CONFIG_TCG_TIS_I2C_NUVOTON is not set +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +# CONFIG_TCG_INFINEON is not set +# CONFIG_TCG_ST33_I2C is not set +# CONFIG_TCG_XEN is not set +CONFIG_TELCLOCK=m + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y +# CONFIG_SERIAL_8250_DW is not set +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_RIO is not set +CONFIG_SERIAL_JSM=m +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_MFD_HSU is not set + +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_TIMBERDALE is not set +CONFIG_SERIAL_ARC=m +CONFIG_SERIAL_ARC_NR_PORTS=1 +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_PCH_UART is not set + +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# + +# +# I2C Algorithms +# +# CONFIG_I2C_DEBUG_ALGO is not set +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD756_S4882 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_NFORCE2_S4985 is not set +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_VIPERBOARD=m + +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_LEGACY=m +CONFIG_EEPROM_93CX6=m +CONFIG_EEPROM_MAX6875=m + +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +CONFIG_I2C_PASEMI=m +CONFIG_I2C_PCA_PLATFORM=m +# CONFIG_I2C_PIIX4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_XILINX is not set + +CONFIG_I2C_DIOLAN_U2C=m + +# +# I2C Hardware Sensors Chip support +# +CONFIG_SENSORS_ATK0110=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7414=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7310=m +CONFIG_SENSORS_ADT7410=m +CONFIG_SENSORS_ADS7828=m +CONFIG_SENSORS_ADT7462=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ADT7475=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1621=m +# CONFIG_DS1682 is not set +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_G760A=m +CONFIG_SENSORS_G762=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_HDAPS=m +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# FIXME: IBMAEM x86 only? +CONFIG_SENSORS_IBMAEM=m +CONFIG_SENSORS_IBMPEX=m +# CONFIG_SENSORS_IIO_HWMON is not set +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_K10TEMP=m +CONFIG_SENSORS_LIS3LV02D=m +CONFIG_SENSORS_LIS3_SPI=m +CONFIG_SENSORS_LIS3_I2C=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_LM95234=m +CONFIG_SENSORS_LTC4245=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6697=m +CONFIG_SENSORS_MCP3021=m +CONFIG_SENSORS_NCT6775=m +CONFIG_SENSORS_NTC_THERMISTOR=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SHT15=m +CONFIG_SENSORS_SIS5595=m +CONFIG_CHARGER_SMB347=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TMP401=m +CONFIG_APDS9802ALS=m +CONFIG_ISL29020=m +CONFIG_ISL29003=m +CONFIG_SENSORS_BH1770=m +CONFIG_SENSORS_APDS990X=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VIA_CPUTEMP=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83L786NG=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_LTC4215=m +CONFIG_SENSORS_LM95241=m +CONFIG_SENSORS_LM95245=m +CONFIG_SENSORS_TMP421=m +CONFIG_SENSORS_WM8350=m +CONFIG_SENSORS_WM831X=m +CONFIG_SENSORS_LM73=m +CONFIG_SENSORS_AMC6821=m +CONFIG_SENSORS_INA2XX=m +CONFIG_SENSORS_INA209=m +CONFIG_SENSORS_ADT7411=m +CONFIG_SENSORS_ASC7621=m +CONFIG_SENSORS_EMC1403=m +CONFIG_SENSORS_TMP102=m +CONFIG_SENSORS_LTC4261=m +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +CONFIG_SENSORS_W83795=m +# CONFIG_SENSORS_W83795_FANCTRL is not set +CONFIG_SENSORS_DS620=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_LINEAGE=m +CONFIG_SENSORS_LTC4151=m +CONFIG_SENSORS_MAX6639=m +CONFIG_SENSORS_SCH5627=m +CONFIG_SENSORS_SCH5636=m +CONFIG_SENSORS_ADS1015=m +CONFIG_SENSORS_MAX16065=m +CONFIG_SENSORS_MAX6642=m +CONFIG_SENSORS_ADM1275=m +CONFIG_SENSORS_UCD9000=m +CONFIG_SENSORS_UCD9200=m +CONFIG_SENSORS_ZL6100=m +CONFIG_SENSORS_EMC6W201=m + +CONFIG_PMBUS=m +CONFIG_SENSORS_PMBUS=m +CONFIG_SENSORS_MAX16064=m +CONFIG_SENSORS_LM25066=m +CONFIG_SENSORS_LTC2978=m +CONFIG_SENSORS_MAX34440=m +CONFIG_SENSORS_MAX8688=m +CONFIG_SENSORS_MAX1668=m +CONFIG_SENSORS_MAX197=m + +# Industrial I/O subsystem configuration +CONFIG_IIO=m +CONFIG_IIO_BUFFER=y +CONFIG_IIO_BUFFER_CB=y +# CONFIG_IIO_KFIFO_BUF is not set +CONFIG_IIO_TRIGGERED_BUFFER=m +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +CONFIG_IIO_INTERRUPT_TRIGGER=m +CONFIG_HID_SENSOR_IIO_COMMON=m +CONFIG_HID_SENSOR_IIO_TRIGGER=m +CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS=y +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5064 is not set +# CONFIG_BMA180 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX517 is not set +# CONFIG_MCP4725 is not set +# CONFIG_ITG3200 is not set +# CONFIG_APDS9300 is not set +# CONFIG_CM32181 is not set +# CONFIG_CM36651 is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TCS3472 is not set +# CONFIG_TSL4531 is not set +# CONFIG_NAU7802 is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_EXYNOS_ADC is not set +# CONFIG_VIPERBOARD_ADC is not set +# CONFIG_INV_MPU6050_IIO is not set +CONFIG_IIO_ST_GYRO_3AXIS=m +CONFIG_IIO_ST_MAGN_3AXIS=m +CONFIG_IIO_ST_ACCEL_3AXIS=m +CONFIG_HID_SENSOR_INCLINOMETER_3D=m +# CONFIG_ADJD_S311 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_VCNL4000 is not set +# CONFIG_AK8975 is not set +# CONFIG_MAG3110 is not set +# CONFIG_TMP006 is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_KXSD9 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_AD8366 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD9523 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADXRS450 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_DHT11 is not set +# CONFIG_MPL3115 is not set + +# staging IIO drivers +# CONFIG_AD7291 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD799X is not set +# CONFIG_ADT7316 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7746 is not set +# CONFIG_AD5933 is not set +# CONFIG_ADE7854 is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_SCA3000 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD5930 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_AD9850 is not set +# CONFIG_AD9852 is not set +# CONFIG_AD9910 is not set +# CONFIG_AD9951 is not set +# CONFIG_ADIS16060 is not set +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set + + + +# CONFIG_HMC6352 is not set +# CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set + +CONFIG_W1=m +CONFIG_W1_CON=y +# CONFIG_W1_MASTER_MATROX is not set +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS1WM=m +CONFIG_W1_MASTER_GPIO=m +# CONFIG_HDQ_MASTER_OMAP is not set +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2408=m +# CONFIG_W1_SLAVE_DS2408_READBACK is not set +CONFIG_W1_SLAVE_DS2413=m +CONFIG_W1_SLAVE_DS2423=m +CONFIG_W1_SLAVE_DS2431=m +CONFIG_W1_SLAVE_DS2433=m +CONFIG_W1_SLAVE_DS2433_CRC=y +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_DS2780=m +CONFIG_W1_SLAVE_DS2781=m +CONFIG_W1_SLAVE_DS28E04=m +CONFIG_W1_SLAVE_BQ27000=m + +# +# Mice +# + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_POWEROFF=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_SOFT_WATCHDOG=m +CONFIG_WDTPCI=m +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_EUROTECH_WDT is not set +CONFIG_IB700_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_W83877F_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_MACHZ_WDT=m +# CONFIG_SC520_WDT is not set +CONFIG_ALIM7101_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_IT87_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +# CONFIG_SC1200_WDT is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_CPU5_WDT is not set +CONFIG_I6300ESB_WDT=m +CONFIG_IT8712F_WDT=m +# CONFIG_SBC8360_WDT is not set +# CONFIG_SBC7240_WDT is not set +CONFIG_SMSC_SCH311X_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_PCIPCWATCHDOG=m +CONFIG_USBPCWATCHDOG=m +# CONFIG_SBC_EPX_C3_WATCHDOG is not set +CONFIG_WM8350_WATCHDOG=m +CONFIG_WM831X_WATCHDOG=m +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_W83697UG_WDT=m +# CONFIG_MEN_A21_WDT is not set +# CONFIG_GPIO_WATCHDOG is not set + +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=m +CONFIG_HW_RANDOM_TPM=m +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_GEN_RTC is not set +CONFIG_RTC_HCTOSYS=y +# CONFIG_RTC_SYSTOHC is not set +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1511=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_DS1374=m +# CONFIG_RTC_DRV_EP93XX is not set +CONFIG_RTC_DRV_FM3130=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_MAX6900=m +# CONFIG_RTC_DRV_M48T86 is not set +CONFIG_RTC_DRV_PCF2127=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C372=m +# CONFIG_RTC_DRV_SA1100 is not set +# CONFIG_RTC_DRV_TEST is not set +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_DS2404=m +CONFIG_RTC_DRV_STK17TA8=m +# CONFIG_RTC_DRV_S35390A is not set +CONFIG_RTC_DRV_RX8581=m +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_DS1286=m +CONFIG_RTC_DRV_M48T35=m +CONFIG_RTC_DRV_BQ4802=m +CONFIG_RTC_DRV_WM8350=m +# CONFIG_RTC_DRV_AB3100 is not set +CONFIG_RTC_DRV_WM831X=m +CONFIG_RTC_DRV_BQ32K=m +CONFIG_RTC_DRV_MSM6242=m +CONFIG_RTC_DRV_RP5C01=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3029C2=m +CONFIG_RTC_DRV_PCF50633=m +CONFIG_RTC_DRV_DS3232=m +CONFIG_RTC_DRV_ISL12022=m +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_ISL12057 is not set + +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y + +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 + +# CONFIG_STUB_POULSBO is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set + +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m + +CONFIG_MWAVE=m +CONFIG_RAW_DRIVER=y +CONFIG_MAX_RAW_DEVS=8192 +CONFIG_HANGCHECK_TIMER=m + +CONFIG_MEDIA_PCI_SUPPORT=y +# +# Multimedia devices +# +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VIDEO_VIVI is not set +# CONFIG_USB_SI4713 is not set +# CONFIG_PLATFORM_SI4713 is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_USB_RAREMONO is not set + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_V4L_PCI_DRIVERS=y +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_V4L2=y +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_SR030PC30=m +CONFIG_VIDEO_NOON010PC30=m +CONFIG_VIDEO_CAFE_CCIC=m +# CONFIG_VIDEO_CPIA is not set +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CX23885=m +CONFIG_MEDIA_ALTERA_CI=m +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX18_ALSA=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_ENABLE_VP3054=y +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_EM28XX_RC=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_ALSA=m +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_VIDEO_CX231XX_RC=y +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_IVTV=m +# CONFIG_VIDEO_IVTV_ALSA is not set +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_PVRUSB2_DVB=y +# CONFIG_VIDEO_PMS is not set +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7134_RC=y +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_STK1160_COMMON=m +CONFIG_VIDEO_STK1160=m +CONFIG_VIDEO_STK1160_AC97=y +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +# CONFIG_V4L_ISA_PARPORT_DRIVERS is not set +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_SAA7164=m +CONFIG_VIDEO_TM6000=m +CONFIG_VIDEO_TM6000_ALSA=m +CONFIG_VIDEO_TM6000_DVB=m +CONFIG_VIDEO_TLG2300=m +CONFIG_VIDEO_USBTV=m + +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y + +# +# Radio Adapters +# +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m +CONFIG_RADIO_WL1273=m + +CONFIG_MEDIA_ATTACH=y + +# +# V4L/DVB tuners +# Selected automatically by not setting CONFIG_MEDIA_TUNER_CUSTOMISE +# +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set + +# +# Digital Video Broadcasting Devices +# +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CORE=m +CONFIG_DVB_NET=y +CONFIG_DVB_MAX_ADAPTERS=8 +CONFIG_DVB_DYNAMIC_MINORS=y + +# +# DVB frontends +# Selected automatically by not setting CONFIG_DVB_FE_CUSTOMISE +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# Supported DVB bridge Modules +# +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET_CORE=m +CONFIG_DVB_PLUTO2=m +CONFIG_SMS_SIANO_MDTV=m +CONFIG_SMS_SIANO_RC=y +# CONFIG_SMS_SIANO_DEBUGFS is not set +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_SMS_USB_DRV=m +CONFIG_SMS_SDIO_DRV=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_FRIIO=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_IT913X=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_DM1105=m +CONFIG_DVB_FIREDTV=m +CONFIG_DVB_NGENE=m +CONFIG_DVB_DDBRIDGE=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_V2=m + +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +CONFIG_DVB_TTUSB_BUDGET=m + +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set + +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_DIBUSB_MB=m +# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_AF9035=m + +CONFIG_DVB_PT1=m + +CONFIG_MANTIS_CORE=m +CONFIG_DVB_MANTIS=m +CONFIG_DVB_HOPPER=m + +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set + +CONFIG_RC_CORE=m +CONFIG_RC_DECODERS=y +CONFIG_LIRC=m +CONFIG_RC_LOOPBACK=m +CONFIG_RC_MAP=m +CONFIG_RC_DEVICES=y +CONFIG_RC_ATI_REMOTE=m +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_RC5_SZ_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_LIRC_CODEC=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_ITE_CIR=m +CONFIG_IR_NUVOTON=m +CONFIG_IR_FINTEK=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_ENE=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_WINBOND_CIR=m +CONFIG_IR_IGUANA=m +CONFIG_IR_TTUSBIR=m +CONFIG_IR_GPIO_CIR=m + +CONFIG_V4L_MEM2MEM_DRIVERS=y +# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set +# CONFIG_VIDEO_SH_VEU is not set +# CONFIG_VIDEO_RENESAS_VSP1 is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set + +# +# Broadcom Crystal HD video decoder driver +# +CONFIG_CRYSTALHD=m + +# +# Graphics support +# + +CONFIG_DISPLAY_SUPPORT=m +CONFIG_VIDEO_OUTPUT_CONTROL=m + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_VGACON_SOFT_SCROLLBACK=y +CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64 +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y + +# +# Logo configuration +# +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# + +# +# Advanced Linux Sound Architecture +# +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +# CONFIG_SND_DEBUG_VERBOSE is not set +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_SEQUENCER=y +CONFIG_SND_HRTIMER=y +CONFIG_SND_SEQ_HRTIMER_DEFAULT=y +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_RTCTIMER=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_MAX_CARDS=32 +# CONFIG_SND_SUPPORT_OLD_API is not set + +# +# Generic devices +# +CONFIG_SND_DUMMY=m +CONFIG_SND_ALOOP=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 + +CONFIG_SND_DRIVERS=y + +# +# ISA devices +# +CONFIG_SND_AD1889=m + +# +# PCI devices +# +CONFIG_SND_PCI=y +CONFIG_SND_ALI5451=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +# CONFIG_SND_AW2 is not set +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +# CONFIG_SND_BT87X_OVERCLOCK is not set +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_CS5530=m +CONFIG_SND_CS5535AUDIO=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_ES1968_INPUT=y +CONFIG_SND_ES1968_RADIO=y +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_CTXFI=m +CONFIG_SND_LX6464ES=m +CONFIG_SND_HDA_INTEL=y +CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_INPUT_BEEP_MODE=0 +CONFIG_SND_HDA_INPUT_JACK=y +CONFIG_SND_HDA_PATCH_LOADER=y +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS=y +CONFIG_SND_HDA_CODEC_CA0110=y +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_CODEC_CIRRUS=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_CODEC_HDMI=y +CONFIG_SND_HDA_I915=y +CONFIG_SND_HDA_CODEC_CA0132=y +CONFIG_SND_HDA_CODEC_CA0132_DSP=y +CONFIG_SND_HDA_GENERIC=y +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDA_RECONFIG=y +CONFIG_SND_HDA_PREALLOC_SIZE=4096 +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=y +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_INPUT=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_OXYGEN=m +CONFIG_SND_RME32=m +CONFIG_SND_PCSP=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SIS7019=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRTUOSO=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ASIHPI=m +CONFIG_SND_LOLA=m + +# +# ALSA USB devices +# +CONFIG_SND_USB=y +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_USX2Y=m +CONFIG_SND_USB_US122L=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_USB_HIFACE=m + +# +# PCMCIA devices +# +# CONFIG_SND_PCMCIA is not set + +CONFIG_SND_FIREWIRE=y +CONFIG_SND_FIREWIRE_SPEAKERS=m +CONFIG_SND_ISIGHT=m +CONFIG_SND_SCS1X=m +CONFIG_SND_DICE=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB_SUPPORT=y +# CONFIG_USB_DEBUG is not set + +# DEPRECATED: See bug 362221. Fix udev. +# CONFIG_USB_DEVICE_CLASS is not set + + +# +# Miscellaneous USB options +# + +# Deprecated. +# CONFIG_USB_DEVICEFS is not set + +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHCI_MV is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +CONFIG_USB_ISP1362_HCD=m +CONFIG_USB_FUSBH200_HCD=m +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_GR_UDC is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PCI=y +# CONFIG_USB_OHCI_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_OHCI_HCD_PLATFORM is not set +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_HCD_ISO=y +# CONFIG_USB_SL811_CS is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_XHCI_HCD=y +# CONFIG_USB_XHCI_HCD_DEBUGGING is not set + +# +# USB Device Class drivers +# + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_WDM=m +CONFIG_USB_TMC=m +# CONFIG_BLK_DEV_UB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_CYPRESS_ATACB=m +CONFIG_USB_STORAGE_DATAFAB=m +CONFIG_USB_STORAGE_FREECOM=m +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_ONETOUCH=m +CONFIG_USB_STORAGE_ALAUDA=m +CONFIG_USB_STORAGE_KARMA=m +CONFIG_USB_STORAGE_REALTEK=m +CONFIG_REALTEK_AUTOPM=y +CONFIG_USB_STORAGE_ENE_UB6250=m +# CONFIG_USB_LIBUSUAL is not set +# CONFIG_USB_UAS is not set + + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y + +CONFIG_HID_SUPPORT=y + +CONFIG_HID=y +CONFIG_I2C_HID=m +CONFIG_HID_BATTERY_STRENGTH=y +# debugging default is y upstream now +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_HID_LOGITECH_DJ=m +CONFIG_LOGIWII_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_PANTHERLORD_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_WACOM=m +CONFIG_HID_WACOM_POWER_SUPPLY=y +CONFIG_ZEROPLUS_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_IDMOUSE=m +CONFIG_DRAGONRISE_FF=y +CONFIG_GREENASIA_FF=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_NTRIG=y +CONFIG_HID_QUANTA=y +CONFIG_HID_PRIMAX=m +CONFIG_HID_PS3REMOTE=m +CONFIG_HID_PRODIKEYS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_HID_GYRATION=m +CONFIG_HID_ICADE=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m +CONFIG_HID_RMI=m +CONFIG_HID_ROCCAT=m +CONFIG_HID_ROCCAT_KONE=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m +CONFIG_SONY_FF=y +CONFIG_HID_SUNPLUS=m +CONFIG_HID_STEELSERIES=m +CONFIG_HID_GREENASIA=m +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THINGM=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_HID_XINMO=m +CONFIG_HID_ZEROPLUS=m +CONFIG_HID_ZYDACRON=m +CONFIG_HID_SENSOR_HUB=m +CONFIG_HID_SENSOR_GYRO_3D=m +CONFIG_HID_SENSOR_MAGNETOMETER_3D=m +CONFIG_HID_SENSOR_ALS=m +CONFIG_HID_SENSOR_ACCEL_3D=m +CONFIG_HID_EMS_FF=m +CONFIG_HID_ELECOM=m +CONFIG_HID_ELO=m +CONFIG_HID_UCLOGIC=m +CONFIG_HID_WALTOP=m +CONFIG_HID_ROCCAT_PYRA=m +CONFIG_HID_ROCCAT_KONEPLUS=m +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO_TPKBD=m +CONFIG_HID_ROCCAT_ARVO=m +CONFIG_HID_ROCCAT_ISKU=m +CONFIG_HID_ROCCAT_KOVAPLUS=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_HUION=m +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_WIIMOTE=m +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_KYE=m +CONFIG_HID_SAITEK=m +CONFIG_HID_TIVO=m +CONFIG_HID_GENERIC=y +CONFIG_HID_AUREAL=m +CONFIG_HID_APPLEIR=m + + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m + +# +# USB Multimedia devices +# + +CONFIG_USB_DSBR=m +# CONFIG_USB_ET61X251 is not set +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_GSPCA=m +CONFIG_USB_GSPCA_MR97310A=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_OV519=m +CONFIG_USB_GSPCA_OV534=m +CONFIG_USB_GSPCA_OV534_9=m +CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SN9C2028=m +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m +CONFIG_USB_GSPCA_SPCA500=m +CONFIG_USB_GSPCA_SPCA501=m +CONFIG_USB_GSPCA_SPCA505=m +CONFIG_USB_GSPCA_SPCA506=m +CONFIG_USB_GSPCA_SPCA508=m +CONFIG_USB_GSPCA_SPCA561=m +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STK1135=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +CONFIG_USB_GSPCA_PAC7302=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GL860=m +CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_USB_GSPCA_KONICA=m +CONFIG_USB_GSPCA_XIRLINK_CIT=m +CONFIG_USB_GSPCA_SPCA1528=m +CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_NW80X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_SE401=m + +CONFIG_USB_S2255=m +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set +# CONFIG_USB_SN9C102 is not set +CONFIG_USB_ZR364XX=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_HSO=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9700=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_CDC_NCM=m +CONFIG_USB_NET_HUAWEI_CDC_NCM=m +CONFIG_USB_NET_CDC_MBIM=m +CONFIG_USB_NET_ZAURUS=m +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_CDC_PHONET=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y + +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SYMBOL=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +# CONFIG_USB_SERIAL_F81232 is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_IUU=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +# CONFIG_USB_SERIAL_METRO is not set +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7715_PARPORT=y +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_ZTE is not set +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MOTOROLA=m +# CONFIG_USB_SERIAL_MXUPORT is not set +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_OPTICON=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_QUATECH2 is not set +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SIEMENS_MPI=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_QCAUX=m +CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m +CONFIG_USB_SERIAL_XSENS_MT=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m +CONFIG_USB_SERIAL_FLASHLOADER=m +CONFIG_USB_SERIAL_SUUNTO=m +CONFIG_USB_SERIAL_CONSOLE=y + +CONFIG_USB_EZUSB=y +CONFIG_USB_EMI62=m +CONFIG_USB_LED=m +# CONFIG_USB_CYPRESS_CY7C63 is not set + +# +# USB Miscellaneous drivers +# + +CONFIG_USB_ADUTUX=m +CONFIG_USB_SEVSEG=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_APPLEDISPLAY=m + +# Physical Layer USB driver +# CONFIG_USB_OTG_FSM is not set + +# CONFIG_GENERIC_PHY is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_SAMSUNG_USBPHY is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +CONFIG_USB_RCAR_PHY=m +CONFIG_USB_ATM=m +CONFIG_USB_CXACRU=m +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_EMI26=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_OXU210HP_HCD is not set +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_YUREX=m +CONFIG_USB_EZUSB_FX2=m +CONFIG_USB_HSIC_USB3503=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_MON=y +CONFIG_USB_PWC=m +CONFIG_USB_PWC_INPUT_EVDEV=y +# CONFIG_USB_PWC_DEBUG is not set +# CONFIG_USB_RIO500 is not set +CONFIG_USB_SISUSBVGA=m +CONFIG_USB_SISUSBVGA_CON=y +CONFIG_RADIO_SI470X=y +CONFIG_USB_KEENE=m +CONFIG_USB_MA901=m +CONFIG_USB_SI470X=m +CONFIG_I2C_SI470X=m +CONFIG_RADIO_SI4713=m +# CONFIG_RADIO_TEF6862 is not set +CONFIG_USB_MR800=m +CONFIG_USB_STKWEBCAM=m +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# CONFIG_USB_DWC2 is not set + +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# CONFIG_USB_ISP1301 is not set + +# CONFIG_USB_OTG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB=m +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_SDIOHOST=y +CONFIG_SSB_PCMCIAHOST=y +# CONFIG_SSB_SILENT is not set +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_GPIO=y + +# Multifunction USB devices +# CONFIG_MFD_PCF50633 is not set +CONFIG_PCF50633_ADC=m +CONFIG_PCF50633_GPIO=m +# CONFIG_AB3100_CORE is not set +CONFIG_INPUT_PCF50633_PMU=m +CONFIG_INPUT_GPIO_ROTARY_ENCODER=m + +CONFIG_MFD_SUPPORT=y +CONFIG_MFD_VX855=m +CONFIG_MFD_SM501=m +CONFIG_MFD_SM501_GPIO=y +CONFIG_MFD_RTSX_PCI=m +# CONFIG_MFD_TI_AM335X_TSCADC is not set +CONFIG_MFD_VIPERBOARD=m +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8350 is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_AB3100_OTP is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LPC_ICH is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_TPS6507X is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_ARIZONA is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_LP3943 is not set + +# +# File systems +# +CONFIG_MISC_FILESYSTEMS=y + +# ext4 is used for ext2 and ext3 filesystems +CONFIG_JBD2=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_XFS_FS=m +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +# Autofsv3 is obsolete. +# systemd is dependant upon AUTOFS, so build it in. +# CONFIG_EXOFS_FS is not set +# CONFIG_EXOFS_DEBUG is not set +CONFIG_NILFS2_FS=m +# CONFIG_LOGFS is not set +CONFIG_CEPH_FS=m +CONFIG_CEPH_FSCACHE=y +CONFIG_BLK_DEV_RBD=m +CONFIG_CEPH_LIB=m +CONFIG_CEPH_FS_POSIX_ACL=y +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set + +CONFIG_FSCACHE=m +CONFIG_FSCACHE_STATS=y +# CONFIG_FSCACHE_HISTOGRAM is not set +# CONFIG_FSCACHE_DEBUG is not set +CONFIG_FSCACHE_OBJECT_LIST=y + +CONFIG_CACHEFILES=m +# CONFIG_CACHEFILES_DEBUG is not set +# CONFIG_CACHEFILES_HISTOGRAM is not set + +# +# CD-ROM/DVD Filesystems +# + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +# CONFIG_DEBUG_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set + +CONFIG_CRAMFS=m +CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZLIB=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set +CONFIG_9P_FS=m +CONFIG_9P_FSCACHE=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +# CONFIG_OMFS_FS is not set +CONFIG_CUSE=m +# CONFIG_F2FS_FS is not set + +# +# Network File Systems +# +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +CONFIG_NFS_SWAP=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +# CONFIG_NFS_V4_1_MIGRATION is not set +CONFIG_NFS_V4_2=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_V4_SECURITY_LABEL=y +CONFIG_NFS_FSCACHE=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_PNFS_OBJLAYOUT=m +CONFIG_PNFS_BLOCK=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUNRPC_DEBUG=y +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_CIFS=m +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_SMB2=y +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_FSCACHE=y +CONFIG_CIFS_ACL=y +CONFIG_CIFS_WEAK_PW_HASH=y +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_NFSD_EXPORT=y +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_AFS_FS is not set +# CONFIG_AF_RXRPC is not set + +CONFIG_OCFS2_FS=m +# CONFIG_OCFS2_DEBUG_FS is not set +# CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_OCFS2_FS_O2CB=m +CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m +# CONFIG_OCFS2_FS_STATS is not set + +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +# Maybe see if we want this on for debug kernels? +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set + +CONFIG_CONFIGFS_FS=y + +CONFIG_DLM=m +CONFIG_DLM_DEBUG=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y + + +CONFIG_UBIFS_FS_XATTR=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +# CONFIG_UBIFS_FS_DEBUG is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_AIX_PARTITION=y +CONFIG_AMIGA_PARTITION=y +# CONFIG_ATARI_PARTITION is not set +CONFIG_BSD_DISKLABEL=y +CONFIG_EFI_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_OSF_PARTITION=y +CONFIG_SGI_PARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_SUN_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set + +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_MAC_ROMAN=m +CONFIG_NLS_MAC_CELTIC=m +CONFIG_NLS_MAC_CENTEURO=m +CONFIG_NLS_MAC_CROATIAN=m +CONFIG_NLS_MAC_CYRILLIC=m +CONFIG_NLS_MAC_GAELIC=m +CONFIG_NLS_MAC_GREEK=m +CONFIG_NLS_MAC_ICELAND=m +CONFIG_NLS_MAC_INUIT=m +CONFIG_NLS_MAC_ROMANIAN=m +CONFIG_NLS_MAC_TURKISH=m + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_OPROFILE_EVENT_MULTIPLEX=y + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x0 +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_HEADERS_CHECK=y +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_READABLE_ASM is not set + +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set + +# DEBUG options that don't get enabled/disabled with 'make debug/release' + +# This generates a huge amount of dmesg spew +# CONFIG_DEBUG_KOBJECT is not set +# +# This breaks booting until the module patches are in-tree +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# +# +# These debug options are deliberatly left on (even in 'make release' kernels). +# They aren't that much of a performance impact, and the value +# from getting useful bug-reports makes it worth leaving them on. +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DEBUG_DEVRES=y +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_DEBUG_NX_TEST=m +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DEBUG_BOOT_PARAMS=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_TIMEOUT=0 +CONFIG_ATOMIC64_SELFTEST=y +CONFIG_MEMORY_FAILURE=y +CONFIG_HWPOISON_INJECT=m +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +CONFIG_EARLY_PRINTK_DBGP=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRASH is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_RAMOOPS is not set + + +# +# Security options +# +CONFIG_SECURITY=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_NETWORK_XFRM=y +# CONFIG_SECURITY_PATH is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_AVC_STATS=y +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +# http://lists.fedoraproject.org/pipermail/kernel/2013-February/004125.html +CONFIG_AUDIT_LOGINUID_IMMUTABLE=y + +CONFIG_SECCOMP=y + +# CONFIG_SSBI is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_FIPS=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# Note, CONFIG_CRYPTO_MANAGER_DISABLE_TESTS needs to be unset, or FIPS will be disabled. +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_BLKCIPHER=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32=m +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRYPTO_LZ4=m +CONFIG_CRYPTO_LZ4HC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SALSA20_586=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_CRC32C_INTEL=m +CONFIG_CRYPTO_GHASH=m +CONFIG_CRYPTO_DEV_HIFN_795X=m +CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y +CONFIG_CRYPTO_PCRYPT=m + + + +# Random number generation + +# +# Library routines +# +CONFIG_CRC16=y +CONFIG_CRC32=m +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC_ITU_T=m +CONFIG_CRC8=m +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_CORDIC=m +# CONFIG_DDR is not set + +CONFIG_CRYPTO_ZLIB=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m + +CONFIG_INITRAMFS_SOURCE="" +CONFIG_KEYS=y +CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_BIG_KEYS=y +CONFIG_TRUSTED_KEYS=m +CONFIG_ENCRYPTED_KEYS=m +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set + +CONFIG_ATA_OVER_ETH=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PROGEAR=m + +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_PLATFORM=m + +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_AUTOGROUP=y + +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y + +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y +# CONFIG_CGROUP_HUGETLB is not set +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_NET_PRIO=m +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_BLK_CGROUP=y + +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set + +CONFIG_PRINTK_TIME=y + +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set + +CONFIG_KEXEC=y + +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +CONFIG_THERMAL_GOV_FAIR_SHARE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_EMULATION is not set + +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y + +# +# Bus devices +# +# CONFIG_OMAP_OCP2SCP is not set +CONFIG_PROC_EVENTS=y + +CONFIG_IBMASR=m + +CONFIG_PM_RUNTIME=y +# CONFIG_PM_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +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 + +# FIXME: Why? +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y + +CONFIG_TEST_KSTRTOX=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +# CONFIG_XZ_DEC_IA64 is not set +CONFIG_XZ_DEC_ARM=y +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set + +# CONFIG_POWER_AVS is not set + +CONFIG_TARGET_CORE=m +CONFIG_ISCSI_TARGET=m +CONFIG_LOOPBACK_TARGET=m +CONFIG_SBP_TARGET=m +CONFIG_TCM_IBLOCK=m +CONFIG_TCM_FILEIO=m +CONFIG_TCM_PSCSI=m +CONFIG_TCM_FC=m + +CONFIG_HWSPINLOCK=m + +CONFIG_PSTORE=y +CONFIG_PSTORE_RAM=m +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_FTRACE is not set + +# CONFIG_TEST_MODULE is not set +# CONFIG_TEST_USER_COPY is not set + +# CONFIG_AVERAGE is not set +# CONFIG_VMXNET3 is not set + +# CONFIG_SIGMA is not set + +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 + +CONFIG_BCMA=m +CONFIG_BCMA_BLOCKIO=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +CONFIG_BCMA_HOST_PCI=y +# CONFIG_BCMA_HOST_SOC is not set +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_BCMA_DRIVER_GPIO=y +# CONFIG_BCMA_DEBUG is not set + +# CONFIG_GOOGLE_FIRMWARE is not set +# CONFIG_INTEL_MID_PTI is not set + +# CONFIG_MAILBOX is not set + +CONFIG_FMC=m +CONFIG_FMC_FAKEDEV=m +CONFIG_FMC_TRIVIAL=m +CONFIG_FMC_WRITE_EEPROM=m +CONFIG_FMC_CHARDEV=m + +# CONFIG_GENWQE is not set + +# CONFIG_POWERCAP is not set + +# CONFIG_HSI is not set + + +# CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# CONFIG_MODULE_VERIFY_ELF is not set +# CONFIG_CRYPTO_KEY_TYPE is not set +# CONFIG_PGP_LIBRARY is not set +# CONFIG_PGP_PRELOAD is not set +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_PROC_DEVICETREE=y + diff -Nur linux-4.1.13.orig/arch/arm/configs/imx_v7_cbi_hb_xbian_defconfig linux-4.1.13/arch/arm/configs/imx_v7_cbi_hb_xbian_defconfig --- linux-4.1.13.orig/arch/arm/configs/imx_v7_cbi_hb_xbian_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/configs/imx_v7_cbi_hb_xbian_defconfig 2015-11-30 17:56:13.528141189 +0100 @@ -0,0 +1,6246 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 4.1.7 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ZONE_DMA=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_GENERIC_BUG=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_FHANDLE=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_HANDLE_DOMAIN_IRQ=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ is not set +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +# CONFIG_TICK_CPU_ACCOUNTING is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +CONFIG_SRCU=y +# CONFIG_TASKS_RCU is not set +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +CONFIG_BUILD_BIN2C=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=21 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=13 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_FREEZER is not set +CONFIG_CGROUP_DEVICE=y +# CONFIG_CPUSETS is not set +# CONFIG_CGROUP_CPUACCT is not set +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +# CONFIG_MEMCG_SWAP_ENABLED is not set +CONFIG_MEMCG_KMEM=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_SCHED is not set +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +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 is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +CONFIG_RD_LZO=y +CONFIG_RD_LZ4=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_BPF=y +CONFIG_EXPERT=y +# CONFIG_UID16 is not set +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +# CONFIG_BPF_SYSCALL is not set +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_PCI_QUIRKS=y +# CONFIG_EMBEDDED is not set +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_UPROBES is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_NONE is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_CGROUP_BFQIO is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_BFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="bfq" +CONFIG_PADATA=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_SHMOBILE_LEGACY is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set + +# +# Multiple platform selection +# + +# +# CPU Core family selection +# +# CONFIG_ARCH_MULTI_V6 is not set +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MULTI_V6_V7=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_MESON is not set +CONFIG_ARCH_MXC=y +CONFIG_HAVE_IMX_ANATOP=y +CONFIG_HAVE_IMX_GPC=y +CONFIG_HAVE_IMX_MMDC=y +CONFIG_HAVE_IMX_SRC=y + +# +# Device tree only +# +# CONFIG_SOC_IMX50 is not set +# CONFIG_SOC_IMX51 is not set +# CONFIG_SOC_IMX53 is not set +CONFIG_SOC_IMX6=y +CONFIG_SOC_IMX6Q=y +CONFIG_SOC_IMX6SL=y +# CONFIG_SOC_IMX6SX is not set +# CONFIG_SOC_VF610 is not set +# CONFIG_SOC_LS1021A is not set +# CONFIG_ARCH_MEDIATEK is not set + +# +# TI OMAP/AM/DM/DRA Family +# +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_ZYNQ is not set + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_VDSO=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_PL310_ERRATA_753970 is not set +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_KERNMEM_PERMS is not set +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +CONFIG_ARM_ERRATA_754322=y +# CONFIG_ARM_ERRATA_754327 is not set +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_773022 is not set + +# +# Bus support +# +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +CONFIG_PCIE_DW=y +CONFIG_PCI_IMX6=y +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCIE_IPROC is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEBUG is not set +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +# CONFIG_MCPM is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_VMSPLIT_3G is not set +CONFIG_VMSPLIT_2G=y +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set +CONFIG_HZ_FIXED=0 +# CONFIG_HZ_100 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_500=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=500 +CONFIG_SCHED_HRTICK=y +CONFIG_THUMB2_KERNEL=y +CONFIG_THUMB2_AVOID_R_ARM_THM_JUMP11=y +CONFIG_ARM_ASM_UNIFIED=y +CONFIG_AEABI=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_NO_BOOTMEM=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=8192 +CONFIG_CLEANCACHE=y +CONFIG_FRONTSWAP=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_AREAS=7 +CONFIG_ZSWAP=y +CONFIG_ZPOOL=y +CONFIG_ZBUD=y +# CONFIG_ZSMALLOC is not set +CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +CONFIG_SWIOTLB=y +CONFIG_IOMMU_HELPER=y +# CONFIG_XEN is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="console=ttymxc0,115200" +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_CMDLINE_EXTEND=y +# CONFIG_CMDLINE_FORCE is not set +CONFIG_KEXEC=y +# CONFIG_ATAGS_PROC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +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 + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +CONFIG_ARM_IMX6Q_CPUFREQ=y +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_QORIQ_CPUFREQ is not set + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_DT_IDLE_STATES=y + +# +# ARM CPU Idle Drivers +# +CONFIG_ARM_CPUIDLE=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +CONFIG_BINFMT_MISC=m +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_HIBERNATION is not set +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS_GC=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_SLEEP_DEBUG=y +# CONFIG_APM_EMULATION is not set +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_CPU_PM=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_MIGRATE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_CLASSID=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=m +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=m +CONFIG_IP_MROUTE=y +# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=m +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_GENEVE is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_UDP_DIAG=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=y +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=y +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_DCTCP=m +CONFIG_DEFAULT_VEGAS=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="vegas" +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=m +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=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_VTI=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_GRE=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CT_PROTO_DCCP=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_BROADCAST=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_QUEUE_CT=y +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=m +CONFIG_NF_NAT_PROTO_UDPLITE=m +CONFIG_NF_NAT_PROTO_SCTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_REDIRECT=m +CONFIG_NETFILTER_SYNPROXY=m +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_MASQ is not set +# CONFIG_NFT_REDIR is not set +CONFIG_NFT_NAT=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_REJECT_INET=m +CONFIG_NFT_COMPAT=m +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +CONFIG_NETFILTER_XT_CONNMARK=m +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +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_HL=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_NAT=m +CONFIG_NETFILTER_XT_TARGET_NETMAP=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_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m + +# +# Xtables matches +# +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_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=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_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_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=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_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=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_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_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_MAC is not set +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 +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +# CONFIG_IP_VS_FO is not set +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 + +# +# IPVS application helper +# +# CONFIG_IP_VS_FTP is not set +CONFIG_IP_VS_NFCT=y +# CONFIG_IP_VS_PE_SIP is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_NF_TABLES_IPV4=m +CONFIG_NFT_CHAIN_ROUTE_IPV4=m +CONFIG_NFT_REJECT_IPV4=m +CONFIG_NF_TABLES_ARP=m +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +CONFIG_NF_REJECT_IPV4=m +CONFIG_NF_NAT_IPV4=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NF_NAT_MASQUERADE_IPV4=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_IP_NF_IPTABLES=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_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=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_CLUSTERIP=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 + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_TABLES_IPV6=m +CONFIG_NFT_CHAIN_ROUTE_IPV6=m +CONFIG_NFT_REJECT_IPV6=m +CONFIG_NF_REJECT_IPV6=m +CONFIG_NF_LOG_IPV6=m +CONFIG_NF_NAT_IPV6=m +CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NF_NAT_MASQUERADE_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=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_RT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_NF_TABLES_BRIDGE=m +# CONFIG_NFT_BRIDGE_META is not set +# CONFIG_NFT_BRIDGE_REJECT is not set +# CONFIG_NF_LOG_BRIDGE is not set +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m + +# +# DCCP CCIDs Configuration +# +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=y +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=y + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_SCTP=m +CONFIG_SCTP_DBG_OBJCNT=y +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y +# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 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_RDS=m +# CONFIG_RDS_TCP is not set +# CONFIG_RDS_DEBUG is not set +CONFIG_TIPC=m +CONFIG_TIPC_MEDIA_UDP=y +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_HAVE_NET_DSA=y +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +CONFIG_LLC2=m +# CONFIG_IPX is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_SFQ=y +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=y +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_INGRESS=m +CONFIG_NET_SCH_PLUG=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=m +CONFIG_NET_CLS_BPF=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +# CONFIG_NET_EMATCH_CANID is not set +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +# CONFIG_NET_ACT_VLAN is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CONNMARK is not set +CONFIG_NET_CLS_IND=y +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +CONFIG_OPENVSWITCH_VXLAN=m +# CONFIG_VSOCKETS is not set +CONFIG_NETLINK_MMAP=y +CONFIG_NETLINK_DIAG=m +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_CGROUP_NET_CLASSID=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +CONFIG_CAN=m +CONFIG_CAN_RAW=m +CONFIG_CAN_BCM=m +CONFIG_CAN_GW=m + +# +# CAN Device Drivers +# +# CONFIG_CAN_VCAN is not set +# CONFIG_CAN_SLCAN is not set +CONFIG_CAN_DEV=m +CONFIG_CAN_CALC_BITTIMING=y +# CONFIG_CAN_LEDS is not set +# CONFIG_CAN_TI_HECC is not set +CONFIG_CAN_FLEXCAN=m +# CONFIG_CAN_GRCAN is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAN_SJA1000 is not set +# CONFIG_CAN_C_CAN is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_CC770 is not set + +# +# CAN SPI interfaces +# +# CONFIG_CAN_MCP251X is not set + +# +# CAN USB interfaces +# +CONFIG_CAN_EMS_USB=m +CONFIG_CAN_ESD_USB2=m +CONFIG_CAN_GS_USB=m +CONFIG_CAN_KVASER_USB=m +CONFIG_CAN_PEAK_USB=m +CONFIG_CAN_8DEV_USB=m +# CONFIG_CAN_SOFTING is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TOIM3232_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=y +CONFIG_BT_BREDR=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_CMTP=m +CONFIG_BT_HIDP=m +CONFIG_BT_LE=y +# CONFIG_BT_SELFTEST is not set +CONFIG_BT_DEBUGFS=y + +# +# Bluetooth device drivers +# +CONFIG_BT_INTEL=m +CONFIG_BT_BCM=m +CONFIG_BT_RTL=m +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTUSB_BCM=y +CONFIG_BT_HCIBTUSB_RTL=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_HCIUART_LL=y +CONFIG_BT_HCIUART_3WIRE=y +# CONFIG_BT_HCIUART_INTEL is not set +# CONFIG_BT_HCIUART_BCM is not set +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIVHCI=m +CONFIG_BT_MRVL=m +CONFIG_BT_MRVL_SDIO=m +CONFIG_BT_ATH3K=m +# CONFIG_BT_WILINK is not set +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +# CONFIG_RXKAD is not set +CONFIG_FIB_RULES=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=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CFG80211_DEFAULT_PS is not set +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_CFG80211_WEXT_EXPORT=y +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_HAS_RC=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAC80211_RC_MINSTREL_VHT=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_LEDS=y +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +CONFIG_MAC80211_DEBUG_MENU=y +# CONFIG_MAC80211_NOINLINE is not set +# CONFIG_MAC80211_VERBOSE_DEBUG is not set +# CONFIG_MAC80211_MLME_DEBUG is not set +# CONFIG_MAC80211_STA_DEBUG is not set +# CONFIG_MAC80211_HT_DEBUG is not set +# CONFIG_MAC80211_OCB_DEBUG is not set +# CONFIG_MAC80211_IBSS_DEBUG is not set +# CONFIG_MAC80211_PS_DEBUG is not set +# CONFIG_MAC80211_MPL_DEBUG is not set +# CONFIG_MAC80211_MPATH_DEBUG is not set +# CONFIG_MAC80211_MHWMP_DEBUG is not set +# CONFIG_MAC80211_MESH_SYNC_DEBUG is not set +# CONFIG_MAC80211_MESH_CSA_DEBUG is not set +# CONFIG_MAC80211_MESH_PS_DEBUG is not set +# CONFIG_MAC80211_TDLS_DEBUG is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_REGULATOR=y +CONFIG_RFKILL_GPIO=y +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +CONFIG_CAIF_NETDEV=m +CONFIG_CAIF_USB=m +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y +CONFIG_NFC=m +# CONFIG_NFC_DIGITAL is not set +# CONFIG_NFC_NCI is not set +# CONFIG_NFC_HCI is not set + +# +# Near Field Communication (NFC) devices +# +# CONFIG_NFC_PN533 is not set +# CONFIG_NFC_SIM is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_WANT_DEV_COREDUMP=y +CONFIG_ALLOW_DEV_COREDUMP=y +CONFIG_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_IRQ=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_FENCE_TRACE is not set +CONFIG_DMA_CMA=y + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=288 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 + +# +# Bus devices +# +CONFIG_ARM_CCI=y +CONFIG_ARM_CCI400_COMMON=y +CONFIG_ARM_CCI400_PMU=y +CONFIG_ARM_CCN=y +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_IMX_WEIM=y +# CONFIG_VEXPRESS_CONFIG is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# 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 +# CONFIG_MTD_PARTITIONED_MASTER is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS 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_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_CFI_UTIL=y +# 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_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_IMPA7 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_DATAFLASH=y +# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set +# CONFIG_MTD_DATAFLASH_OTP is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_SST25L=y +# 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_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_MXC=y +# CONFIG_MTD_NAND_HISI504 is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR & LPDDR2 PCM memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +CONFIG_MTD_SPI_NOR=m +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_SPI_FSL_QUADSPI=m +CONFIG_MTD_UBI=y +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 +# CONFIG_MTD_UBI_BLOCK is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_ADDRESS_PCI=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_MTD=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MG_DISK=y +CONFIG_MG_DISK_RES=0 +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +CONFIG_TIFM_CORE=y +CONFIG_TIFM_7XX1=y +# CONFIG_ICS932S401 is not set +CONFIG_ENCLOSURE_SERVICES=y +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_SRAM=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +CONFIG_EEPROM_MAX6875=y +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +CONFIG_CB710_CORE=y +# CONFIG_CB710_DEBUG is not set +CONFIG_CB710_DEBUG_ASSUMPTIONS=y + +# +# Texas Instruments shared transport line discipline +# +CONFIG_TI_ST=m +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +CONFIG_ALTERA_STAPL=m + +# +# Intel MIC Bus Driver +# + +# +# Intel MIC Host Driver +# + +# +# Intel MIC Card Driver +# +CONFIG_ECHO=m +# CONFIG_CXL_BASE is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_ENCLOSURE=y +# CONFIG_SCSI_CONSTANTS is not set +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +CONFIG_SCSI_UFSHCD=m +# CONFIG_SCSI_UFSHCD_PCI is not set +CONFIG_SCSI_UFSHCD_PLATFORM=m +# CONFIG_SCSI_HPTIOP is not set +CONFIG_LIBFC=m +CONFIG_LIBFCOE=m +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +CONFIG_SCSI_DH=m +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_SCSI_OSD_INITIATOR=m +# CONFIG_SCSI_OSD_ULD is not set +CONFIG_SCSI_OSD_DPRINT_SENSE=1 +# CONFIG_SCSI_OSD_DEBUG is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_VERBOSE_ERROR is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +# CONFIG_SATA_AHCI is not set +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_IMX=y +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_SIL24 is not set +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +CONFIG_PATA_IMX=y +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=y +CONFIG_MD_RAID456=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BCACHE=m +# CONFIG_BCACHE_DEBUG is not set +# CONFIG_BCACHE_CLOSURES_DEBUG is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_MQ_DEFAULT is not set +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +CONFIG_DM_BIO_PRISON=m +CONFIG_DM_PERSISTENT_DATA=m +# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_CACHE_MQ=m +CONFIG_DM_CACHE_CLEANER=m +# CONFIG_DM_ERA is not set +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_DELAY=m +CONFIG_DM_UEVENT=y +CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +CONFIG_BONDING=m +CONFIG_DUMMY=m +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_IFB is not set +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_BROADCAST=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_RANDOM=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_VXLAN=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NLMON=m +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# +# CONFIG_CAIF_TTY is not set +# CONFIG_CAIF_SPI_SLAVE is not set +# CONFIG_CAIF_HSI is not set +# CONFIG_CAIF_VIRTIO is not set + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +CONFIG_ETHERNET=y +CONFIG_MDIO=y +CONFIG_NET_VENDOR_3COM=y +# CONFIG_VORTEX is not set +# CONFIG_TYPHOON is not set +CONFIG_NET_VENDOR_ADAPTEC=y +# CONFIG_ADAPTEC_STARFIRE is not set +CONFIG_NET_VENDOR_AGERE=y +CONFIG_ET131X=m +CONFIG_NET_VENDOR_ALTEON=y +# CONFIG_ACENIC is not set +# CONFIG_ALTERA_TSE is not set +CONFIG_NET_VENDOR_AMD=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_PCNET32 is not set +CONFIG_NET_VENDOR_ARC=y +# CONFIG_ARC_EMAC is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_ATL2=y +CONFIG_ATL1=y +CONFIG_ATL1E=y +CONFIG_ATL1C=y +CONFIG_ALX=y +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +CONFIG_NET_VENDOR_BROCADE=y +# CONFIG_BNA is not set +CONFIG_NET_VENDOR_CHELSIO=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +CONFIG_NET_VENDOR_CISCO=y +# CONFIG_ENIC is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_DEC=y +# CONFIG_NET_TULIP is not set +CONFIG_NET_VENDOR_DLINK=y +# CONFIG_DL2K is not set +# CONFIG_SUNDANCE is not set +CONFIG_NET_VENDOR_EMULEX=y +# CONFIG_BE2NET is not set +CONFIG_NET_VENDOR_EXAR=y +# CONFIG_S2IO is not set +# CONFIG_VXGE is not set +# CONFIG_NET_VENDOR_FARADAY is not set +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_FEC=y +# CONFIG_FSL_PQ_MDIO is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_NET_VENDOR_HISILICON=y +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HIP04_ETH is not set +CONFIG_NET_VENDOR_HP=y +# CONFIG_HP100 is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +CONFIG_NET_VENDOR_MELLANOX=y +# CONFIG_MLX4_EN is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +CONFIG_NET_VENDOR_MYRI=y +# CONFIG_MYRI10GE is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +CONFIG_NET_VENDOR_NVIDIA=y +# CONFIG_FORCEDETH is not set +CONFIG_NET_VENDOR_OKI=y +# CONFIG_ETHOC is not set +CONFIG_NET_PACKET_ENGINE=y +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +CONFIG_NET_VENDOR_QLOGIC=y +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_NETXEN_NIC is not set +CONFIG_NET_VENDOR_QUALCOMM=y +# CONFIG_QCA7000 is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +CONFIG_NET_VENDOR_RDC=y +# CONFIG_R6040 is not set +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +# CONFIG_SXGBE_ETH is not set +# CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_NET_VENDOR_SILAN=y +# CONFIG_SC92031 is not set +CONFIG_NET_VENDOR_SIS=y +# CONFIG_SIS900 is not set +# CONFIG_SIS190 is not set +# CONFIG_SFC is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_NET_VENDOR_SUN=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NIU is not set +CONFIG_NET_VENDOR_TEHUTI=y +# CONFIG_TEHUTI is not set +CONFIG_NET_VENDOR_TI=y +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TLAN is not set +CONFIG_NET_VENDOR_VIA=y +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +CONFIG_AT803X_PHY=y +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +CONFIG_BROADCOM_PHY=y +CONFIG_BCM7XXX_PHY=m +CONFIG_BCM87XX_PHY=y +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +CONFIG_MICREL_PHY=m +CONFIG_FIXED_PHY=y +CONFIG_MDIO_BITBANG=m +CONFIG_MDIO_GPIO=m +CONFIG_MDIO_BUS_MUX=m +CONFIG_MDIO_BUS_MUX_GPIO=m +CONFIG_MDIO_BUS_MUX_MMIOREG=m +CONFIG_MDIO_BCM_UNIMAC=m +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_SLIP=m +CONFIG_SLHC=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=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_DM9601=m +CONFIG_USB_NET_SR9700=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=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_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=m +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_HSO=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_WLAN=y +CONFIG_LIBERTAS_THINFIRM=m +# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set +CONFIG_LIBERTAS_THINFIRM_USB=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_AT76C50X_USB=m +CONFIG_PRISM54=m +CONFIG_USB_ZD1201=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_RTL8180=m +CONFIG_RTL8187=m +CONFIG_RTL8187_LEDS=y +CONFIG_ADM8211=m +# CONFIG_MAC80211_HWSIM is not set +CONFIG_MWL8K=m +CONFIG_ATH_COMMON=m +CONFIG_ATH_CARDS=m +# CONFIG_ATH_DEBUG is not set +CONFIG_ATH5K=m +# CONFIG_ATH5K_DEBUG is not set +CONFIG_ATH5K_PCI=y +CONFIG_ATH9K_HW=m +CONFIG_ATH9K_COMMON=m +CONFIG_ATH9K_BTCOEX_SUPPORT=y +CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +CONFIG_ATH9K_AHB=y +# CONFIG_ATH9K_DEBUGFS is not set +# CONFIG_ATH9K_DYNACK is not set +CONFIG_ATH9K_WOW=y +CONFIG_ATH9K_RFKILL=y +CONFIG_ATH9K_CHANNEL_CONTEXT=y +CONFIG_ATH9K_PCOEM=y +CONFIG_ATH9K_HTC=m +# CONFIG_ATH9K_HTC_DEBUGFS is not set +CONFIG_CARL9170=m +CONFIG_CARL9170_LEDS=y +CONFIG_CARL9170_WPC=y +CONFIG_CARL9170_HWRNG=y +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m +# CONFIG_ATH6KL_DEBUG is not set +CONFIG_AR5523=m +CONFIG_WIL6210=m +CONFIG_WIL6210_ISR_COR=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +# CONFIG_ATH10K_DEBUG is not set +# CONFIG_ATH10K_DEBUGFS is not set +CONFIG_WCN36XX=m +# CONFIG_WCN36XX_DEBUGFS is not set +CONFIG_B43=m +CONFIG_B43_BCMA=y +CONFIG_B43_SSB=y +CONFIG_B43_BUSES_BCMA_AND_SSB=y +# CONFIG_B43_BUSES_BCMA is not set +# CONFIG_B43_BUSES_SSB is not set +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_SDIO=y +CONFIG_B43_BCMA_PIO=y +CONFIG_B43_PIO=y +CONFIG_B43_PHY_G=y +CONFIG_B43_PHY_N=y +CONFIG_B43_PHY_LP=y +CONFIG_B43_PHY_HT=y +CONFIG_B43_LEDS=y +CONFIG_B43_HWRNG=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_LEDS=y +CONFIG_B43LEGACY_HWRNG=y +# 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_BRCMUTIL=m +CONFIG_BRCMSMAC=m +CONFIG_BRCMFMAC=m +CONFIG_BRCMFMAC_PROTO_BCDC=y +CONFIG_BRCMFMAC_PROTO_MSGBUF=y +CONFIG_BRCMFMAC_SDIO=y +# CONFIG_BRCMFMAC_USB is not set +CONFIG_BRCMFMAC_PCIE=y +# CONFIG_BRCM_TRACING is not set +# CONFIG_BRCMDBG is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_DEBUG=y +CONFIG_LIBIPW=m +# CONFIG_LIBIPW_DEBUG is not set +CONFIG_IWLWIFI=m +CONFIG_IWLWIFI_LEDS=y +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_IWLWIFI_OPMODE_MODULAR=y +CONFIG_IWLWIFI_BCAST_FILTERING=y +CONFIG_IWLWIFI_UAPSD=y + +# +# Debugging Options +# +# CONFIG_IWLWIFI_DEBUG is not set +CONFIG_IWLEGACY=m +CONFIG_IWL4965=m +CONFIG_IWL3945=m + +# +# iwl3945 / iwl4965 Debugging Options +# +# CONFIG_IWLEGACY_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_SPI=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_MESH=y +CONFIG_HERMES=m +CONFIG_HERMES_PRISM=y +CONFIG_HERMES_CACHE_FW_ON_INIT=y +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_NORTEL_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ORINOCO_USB=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +CONFIG_P54_SPI=m +CONFIG_P54_SPI_DEFAULT_EEPROM=y +CONFIG_P54_LEDS=y +CONFIG_RT2X00=m +CONFIG_RT2400PCI=m +CONFIG_RT2500PCI=m +CONFIG_RT61PCI=m +CONFIG_RT2800PCI=m +CONFIG_RT2800PCI_RT33XX=y +CONFIG_RT2800PCI_RT35XX=y +CONFIG_RT2800PCI_RT53XX=y +CONFIG_RT2800PCI_RT3290=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=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_RT2800_LIB=m +CONFIG_RT2800_LIB_MMIO=m +CONFIG_RT2X00_LIB_MMIO=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_CRYPTO=y +CONFIG_RT2X00_LIB_LEDS=y +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RTL_CARDS=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8723BE=m +CONFIG_RTL8188EE=m +CONFIG_RTL8192EE=m +CONFIG_RTL8821AE=m +CONFIG_RTL8192CU=m +CONFIG_RTLWIFI=m +CONFIG_RTLWIFI_PCI=m +CONFIG_RTLWIFI_USB=m +CONFIG_RTLWIFI_DEBUG=y +CONFIG_RTL8192C_COMMON=m +CONFIG_RTL8723_COMMON=m +CONFIG_RTLBTCOEXIST=m +CONFIG_WL_TI=y +CONFIG_WL1251=m +CONFIG_WL1251_SPI=m +CONFIG_WL1251_SDIO=m +CONFIG_WL12XX=m +CONFIG_WL18XX=m +CONFIG_WLCORE=m +CONFIG_WLCORE_SPI=m +CONFIG_WLCORE_SDIO=m +CONFIG_WILINK_PLATFORM_DATA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_PCIE=m +CONFIG_MWIFIEX_USB=m +CONFIG_CW1200=m +CONFIG_CW1200_WLAN_SDIO=m +CONFIG_CW1200_WLAN_SPI=m +CONFIG_RSI_91X=m +CONFIG_RSI_DEBUGFS=y +CONFIG_RSI_SDIO=m +CONFIG_RSI_USB=m + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +CONFIG_WAN=y +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m + +# +# X.25/LAPB support is disabled +# +# CONFIG_PCI200SYN is not set +CONFIG_WANXL=m +# CONFIG_WANXL_BUILD_FIRMWARE is not set +CONFIG_PC300TOO=m +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +# CONFIG_DSCC4_PCISYNC is not set +# CONFIG_DSCC4_PCI_RST is not set +# CONFIG_DLCI is not set +# CONFIG_VMXNET3 is not set +CONFIG_ISDN=y +CONFIG_ISDN_I4L=m +# CONFIG_ISDN_PPP is not set +# CONFIG_ISDN_AUDIO is not set + +# +# ISDN feature submodules +# +# CONFIG_ISDN_DIVERSION is not set + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +# CONFIG_ISDN_DRV_HISAX is not set + +# +# Active cards +# +CONFIG_ISDN_CAPI=m +CONFIG_CAPI_TRACE=y +# CONFIG_ISDN_CAPI_CAPI20 is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set + +# +# CAPI hardware drivers +# +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_CAPI=y +# CONFIG_GIGASET_I4L is not set +# CONFIG_GIGASET_DUMMYLL is not set +# CONFIG_GIGASET_BASE is not set +# CONFIG_GIGASET_M105 is not set +# CONFIG_GIGASET_M101 is not set +# CONFIG_GIGASET_DEBUG is not set +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y +CONFIG_MISDN=m +CONFIG_MISDN_DSP=m +CONFIG_MISDN_L1OIP=m + +# +# mISDN hardware drivers +# +CONFIG_MISDN_HFCPCI=m +CONFIG_MISDN_HFCMULTI=m +CONFIG_MISDN_HFCUSB=m +CONFIG_MISDN_AVMFRITZ=m +CONFIG_MISDN_SPEEDFAX=m +CONFIG_MISDN_INFINEON=m +CONFIG_MISDN_W6692=m +CONFIG_MISDN_NETJET=m +CONFIG_MISDN_IPAC=m +CONFIG_MISDN_ISAR=m +CONFIG_ISDN_HDLC=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_SPARSEKMAP=y +CONFIG_INPUT_MATRIXKMAP=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_GPIO_POLLED=y +CONFIG_KEYBOARD_TCA6416=m +CONFIG_KEYBOARD_TCA8418=m +CONFIG_KEYBOARD_MATRIX=m +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +CONFIG_KEYBOARD_IMX=y +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP4 is not set +CONFIG_KEYBOARD_XTKBD=m +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_BCM is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_PS2_ELANTECH=y +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_FOCALTECH=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_BCM5974=m +CONFIG_MOUSE_CYAPA=m +CONFIG_MOUSE_ELAN_I2C=m +CONFIG_MOUSE_ELAN_I2C_I2C=y +# CONFIG_MOUSE_ELAN_I2C_SMBUS is not set +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOUSE_GPIO=m +CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=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_TWIDJOY=m +CONFIG_JOYSTICK_ZHENHUA=m +CONFIG_JOYSTICK_AS5011=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_OF_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_DA9052 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +CONFIG_TOUCHSCREEN_EETI=m +CONFIG_TOUCHSCREEN_EGALAX=m +CONFIG_TOUCHSCREEN_FUJITSU=m +# CONFIG_TOUCHSCREEN_GOODIX is not set +CONFIG_TOUCHSCREEN_ILI210X=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELAN=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_WACOM_W8001=m +CONFIG_TOUCHSCREEN_WACOM_I2C=m +CONFIG_TOUCHSCREEN_MAX11801=m +CONFIG_TOUCHSCREEN_MCS5000=m +CONFIG_TOUCHSCREEN_MMS114=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_PIXCIR=m +CONFIG_TOUCHSCREEN_WM97XX=m +CONFIG_TOUCHSCREEN_WM9705=y +CONFIG_TOUCHSCREEN_WM9712=y +CONFIG_TOUCHSCREEN_WM9713=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_MC13783=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_JASTEC=y +CONFIG_TOUCHSCREEN_USB_ELO=y +CONFIG_TOUCHSCREEN_USB_E2I=y +CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y +CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y +CONFIG_TOUCHSCREEN_USB_NEXIO=y +CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y +CONFIG_TOUCHSCREEN_TOUCHIT213=m +CONFIG_TOUCHSCREEN_TSC_SERIO=m +CONFIG_TOUCHSCREEN_TSC2005=m +CONFIG_TOUCHSCREEN_TSC2007=m +CONFIG_TOUCHSCREEN_ST1232=m +CONFIG_TOUCHSCREEN_SUR40=m +# CONFIG_TOUCHSCREEN_SX8654 is not set +CONFIG_TOUCHSCREEN_TPS6507X=m +CONFIG_TOUCHSCREEN_ZFORCE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_AD714X_I2C=m +CONFIG_INPUT_AD714X_SPI=m +CONFIG_INPUT_BMA150=m +# CONFIG_INPUT_E3X0_BUTTON is not set +CONFIG_INPUT_MC13783_PWRBUTTON=m +CONFIG_INPUT_MMA8450=y +CONFIG_INPUT_MPU3050=m +CONFIG_INPUT_GP2A=m +CONFIG_INPUT_GPIO_BEEPER=m +CONFIG_INPUT_GPIO_TILT_POLLED=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_KXTJ9=m +CONFIG_INPUT_KXTJ9_POLLED_MODE=y +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_CM109=m +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_PCF8574=m +CONFIG_INPUT_PWM_BEEPER=m +CONFIG_INPUT_GPIO_ROTARY_ENCODER=m +CONFIG_INPUT_DA9052_ONKEY=m +CONFIG_INPUT_ADXL34X=m +CONFIG_INPUT_ADXL34X_I2C=m +CONFIG_INPUT_ADXL34X_SPI=m +CONFIG_INPUT_IMS_PCU=m +CONFIG_INPUT_CMA3000=m +CONFIG_INPUT_CMA3000_I2C=m +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_INPUT_DRV260X_HAPTICS=m +CONFIG_INPUT_DRV2667_HAPTICS=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=m +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +CONFIG_GAMEPORT=m +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_FM801 is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=m +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=m +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST=y +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +CONFIG_SERIAL_FSL_LPUART=m +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_ST_ASC is not set +CONFIG_TTY_PRINTK=m +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=m +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_XILLYBUS is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +CONFIG_I2C_ARB_GPIO_CHALLENGE=y +CONFIG_I2C_MUX_GPIO=y +CONFIG_I2C_MUX_PCA9541=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_MUX_PINCTRL=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=m +CONFIG_I2C_DESIGNWARE_PLATFORM=m +# CONFIG_I2C_DESIGNWARE_PCI is not set +CONFIG_I2C_GPIO=y +CONFIG_I2C_IMX=y +CONFIG_I2C_OCORES=y +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_EEPROM=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +CONFIG_SPI_BITBANG=m +# CONFIG_SPI_CADENCE is not set +CONFIG_SPI_GPIO=m +CONFIG_SPI_IMX=m +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set +# CONFIG_NTP_PPS is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +CONFIG_PPS_CLIENT_LDISC=y +CONFIG_PPS_CLIENT_GPIO=y + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINCTRL_IMX=y +CONFIG_PINCTRL_IMX6Q=y +CONFIG_PINCTRL_IMX6SL=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_OF_GPIO=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GENERIC=y + +# +# Memory mapped GPIO drivers +# +CONFIG_GPIO_74XX_MMIO=y +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +CONFIG_GPIO_GENERIC_PLATFORM=y +# CONFIG_GPIO_GRGPIO is not set +CONFIG_GPIO_MXC=y +# CONFIG_GPIO_SCH311X is not set +CONFIG_GPIO_SYSCON=y +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_ZEVIO is not set + +# +# I2C GPIO expanders +# +CONFIG_GPIO_ADP5588=m +CONFIG_GPIO_ADNP=m +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_PCF857X=m +CONFIG_GPIO_SX150X=y + +# +# MFD GPIO expanders +# +# CONFIG_GPIO_DA9052 is not set + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders +# +CONFIG_GPIO_74X164=y +# CONFIG_GPIO_MAX7301 is not set +CONFIG_GPIO_MCP23S08=y +CONFIG_GPIO_MC33880=y + +# +# USB GPIO expanders +# +CONFIG_W1=y +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_MXC=m +CONFIG_W1_MASTER_DS1WM=m +CONFIG_W1_MASTER_GPIO=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2408=m +CONFIG_W1_SLAVE_DS2408_READBACK=y +CONFIG_W1_SLAVE_DS2413=m +CONFIG_W1_SLAVE_DS2406=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 +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +CONFIG_TEST_POWER=m +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_DA9052 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +CONFIG_CHARGER_GPIO=m +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_BRCMSTB is not set +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_IMX=y +CONFIG_POWER_RESET_LTC2952=y +CONFIG_POWER_RESET_RESTART=y +CONFIG_POWER_RESET_VERSATILE=y +# CONFIG_POWER_RESET_SNVS is not set +CONFIG_POWER_RESET_SYSCON=y +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +CONFIG_POWER_AVS=y +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DA9052_ADC is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +CONFIG_SENSORS_MC13783_ADC=y +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +CONFIG_SENSORS_MAX1111=y +CONFIG_SENSORS_MAX16065=y +CONFIG_SENSORS_MAX1619=y +CONFIG_SENSORS_MAX1668=y +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +CONFIG_SENSORS_PWM_FAN=y +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=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_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_CPU_THERMAL=y +CONFIG_CLOCK_THERMAL=y +# CONFIG_THERMAL_EMULATION is not set +CONFIG_IMX_THERMAL=y + +# +# Texas Instruments thermal drivers +# +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +# CONFIG_DA9052_WATCHDOG is not set +CONFIG_GPIO_WATCHDOG=m +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +CONFIG_IMX2_WDT=y +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +CONFIG_SSB=y +CONFIG_SSB_SPROM=y +CONFIG_SSB_BLOCKIO=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_B43_PCI_BRIDGE=y +CONFIG_SSB_SDIOHOST_POSSIBLE=y +CONFIG_SSB_SDIOHOST=y +# CONFIG_SSB_SILENT is not set +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +CONFIG_BCMA=m +CONFIG_BCMA_BLOCKIO=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +# CONFIG_BCMA_HOST_PCI is not set +# CONFIG_BCMA_HOST_SOC is not set +CONFIG_BCMA_DRIVER_PCI=y +# CONFIG_BCMA_DRIVER_GMAC_CMN is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +# CONFIG_BCMA_DEBUG is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +CONFIG_PMIC_DA9052=y +CONFIG_MFD_DA9052_SPI=y +CONFIG_MFD_DA9052_I2C=y +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +CONFIG_MFD_MXC_HDMI=y +# CONFIG_MFD_DLN2 is not set +CONFIG_MFD_MC13XXX=y +CONFIG_MFD_MC13XXX_SPI=y +CONFIG_MFD_MC13XXX_I2C=y +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +CONFIG_MFD_SI476X_CORE=y +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SYSCON=y +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +CONFIG_MFD_WL1273_CORE=m +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_USERSPACE_CONSUMER=m +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_ANATOP=y +# CONFIG_REGULATOR_DA9052 is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_FAN53555 is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +CONFIG_REGULATOR_MC13XXX_CORE=y +CONFIG_REGULATOR_MC13783=y +CONFIG_REGULATOR_MC13892=y +CONFIG_REGULATOR_PFUZE100=y +CONFIG_REGULATOR_PWM=y +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_MEDIA_SUPPORT=m + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SDR_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=m +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_TUNER=m +CONFIG_V4L2_MEM2MEM_DEV=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF2_CORE=m +CONFIG_VIDEOBUF2_MEMOPS=m +CONFIG_VIDEOBUF2_DMA_CONTIG=m +CONFIG_VIDEOBUF2_VMALLOC=m +CONFIG_VIDEOBUF2_DMA_SG=m +CONFIG_VIDEOBUF2_DVB=m +CONFIG_DVB_CORE=m +CONFIG_DVB_NET=y +CONFIG_TTPCI_EEPROM=m +CONFIG_DVB_MAX_ADAPTERS=8 +# CONFIG_DVB_DYNAMIC_MINORS is not set + +# +# Media drivers +# +CONFIG_RC_CORE=m +CONFIG_RC_MAP=m +CONFIG_RC_DECODERS=y +CONFIG_LIRC=m +CONFIG_IR_LIRC_CODEC=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_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +CONFIG_RC_DEVICES=y +CONFIG_RC_ATI_REMOTE=m +CONFIG_IR_HIX5HD2=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_IGORPLUGUSB=m +CONFIG_IR_IGUANA=m +CONFIG_IR_TTUSBIR=m +CONFIG_RC_LOOPBACK=m +CONFIG_IR_GPIO_CIR=m +CONFIG_MEDIA_USB_SUPPORT=y + +# +# Webcam devices +# +CONFIG_USB_VIDEO_CLASS=m +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_GL860=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_DTCS033=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_KONICA=m +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_MR97310A=m +CONFIG_USB_GSPCA_NW80X=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_PAC7302=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SE401=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_SPCA1528=m +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STK1135=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m +# CONFIG_USB_GSPCA_TOUPTEK is not set +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_XIRLINK_CIT=m +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_PWC_INPUT_EVDEV=y +CONFIG_VIDEO_CPIA2=m +CONFIG_USB_ZR364XX=m +CONFIG_USB_STKWEBCAM=m +CONFIG_USB_S2255=m +CONFIG_VIDEO_USBTV=m + +# +# Analog TV USB devices +# +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_PVRUSB2_DVB=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_STK1160_COMMON=m +CONFIG_VIDEO_STK1160_AC97=y +CONFIG_VIDEO_STK1160=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_LOADER=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m + +# +# Analog/digital TV USB devices +# +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_V4L2=y +CONFIG_VIDEO_AU0828_RC=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_RC=y +CONFIG_VIDEO_CX231XX_ALSA=m +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_VIDEO_TM6000=m +CONFIG_VIDEO_TM6000_ALSA=m +CONFIG_VIDEO_TM6000_DVB=m + +# +# Digital TV USB devices +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_FRIIO=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_DVBSKY=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_SMS_USB_DRV=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set +CONFIG_DVB_AS102=m + +# +# Webcam, TV (analog/digital) USB devices +# +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_EM28XX_RC=m + +# +# Software defined radio USB devices +# +CONFIG_USB_AIRSPY=m +CONFIG_USB_HACKRF=m +CONFIG_USB_MSI2500=m +CONFIG_MEDIA_PCI_SUPPORT=y + +# +# Media capture support +# + +# +# Media capture/analog TV support +# +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_IVTV_ALSA=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_SOLO6X10=m +CONFIG_VIDEO_TW68=m + +# +# Media capture/analog/hybrid TV support +# +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX18_ALSA=m +CONFIG_VIDEO_CX23885=m +CONFIG_MEDIA_ALTERA_CI=m +CONFIG_VIDEO_CX25821=m +CONFIG_VIDEO_CX25821_ALSA=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_ENABLE_VP3054=y +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX88_MPEG=m +# CONFIG_VIDEO_BT848 is not set +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_RC=y +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7134_GO7007=m +CONFIG_VIDEO_SAA7164=m + +# +# Media digital TV PCI Adapters +# +CONFIG_DVB_AV7110_IR=y +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET_CORE=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_DM1105=m +CONFIG_DVB_PT1=m +CONFIG_DVB_PT3=m +CONFIG_MANTIS_CORE=m +CONFIG_DVB_MANTIS=m +CONFIG_DVB_HOPPER=m +CONFIG_DVB_NGENE=m +CONFIG_DVB_DDBRIDGE=m +CONFIG_DVB_SMIPCIE=m +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_MXC_OUTPUT is not set +# CONFIG_VIDEO_MXC_CAPTURE is not set +CONFIG_SOC_CAMERA=m +CONFIG_SOC_CAMERA_PLATFORM=m +# CONFIG_VIDEO_XILINX is not set +CONFIG_V4L_MEM2MEM_DRIVERS=y +# CONFIG_VIDEO_CODA is not set +CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m +CONFIG_VIDEO_SH_VEU=m +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +CONFIG_SMS_SDIO_DRV=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_TEA575X=m +# CONFIG_RADIO_SI470X is not set +CONFIG_RADIO_SI4713=m +CONFIG_USB_SI4713=m +CONFIG_PLATFORM_SI4713=m +CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m +CONFIG_USB_MR800=m +CONFIG_USB_DSBR=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m +CONFIG_USB_KEENE=m +CONFIG_USB_RAREMONO=m +CONFIG_USB_MA901=m +CONFIG_RADIO_TEA5764=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m + +# +# Texas Instruments WL128x FM driver (ST based) +# +CONFIG_RADIO_WL128X=m +CONFIG_MEDIA_COMMON_OPTIONS=y + +# +# common driver options +# +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_CYPRESS_FIRMWARE=m +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_SMS_SIANO_MDTV=m +CONFIG_SMS_SIANO_RC=y +# CONFIG_SMS_SIANO_DEBUGFS is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +CONFIG_MEDIA_ATTACH=y +CONFIG_VIDEO_IR_I2C=m + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS5345=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_UDA1342=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_SONY_BTF_MPX=m + +# +# RDS decoders +# +CONFIG_VIDEO_SAA6588=m + +# +# Video decoders +# +CONFIG_VIDEO_ADV7180=m +CONFIG_VIDEO_ADV7183=m +CONFIG_VIDEO_ADV7604=m +CONFIG_VIDEO_ADV7842=m +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_ML86V7667=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_TVP514X=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_TVP7002=m +CONFIG_VIDEO_TW2804=m +CONFIG_VIDEO_TW9903=m +CONFIG_VIDEO_TW9906=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_SAA717X=m +CONFIG_VIDEO_CX25840=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +CONFIG_VIDEO_ADV7343=m +CONFIG_VIDEO_ADV7393=m +CONFIG_VIDEO_ADV7511=m +CONFIG_VIDEO_AD9389B=m +CONFIG_VIDEO_AK881X=m +CONFIG_VIDEO_THS8200=m + +# +# Camera sensor devices +# +CONFIG_VIDEO_APTINA_PLL=m +CONFIG_VIDEO_SMIAPP_PLL=m +CONFIG_VIDEO_OV2659=m +CONFIG_VIDEO_OV7640=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OV9650=m +CONFIG_VIDEO_VS6624=m +CONFIG_VIDEO_MT9M032=m +CONFIG_VIDEO_MT9P031=m +CONFIG_VIDEO_MT9T001=m +CONFIG_VIDEO_MT9V011=m +CONFIG_VIDEO_MT9V032=m +CONFIG_VIDEO_SR030PC30=m +CONFIG_VIDEO_NOON010PC30=m +CONFIG_VIDEO_M5MOLS=m +CONFIG_VIDEO_S5K6AA=m +CONFIG_VIDEO_S5K6A3=m +CONFIG_VIDEO_S5K4ECGX=m +CONFIG_VIDEO_S5K5BAF=m +CONFIG_VIDEO_SMIAPP=m +CONFIG_VIDEO_S5C73M3=m + +# +# Flash devices +# +CONFIG_VIDEO_ADP1653=m +CONFIG_VIDEO_AS3645A=m +CONFIG_VIDEO_LM3560=m +CONFIG_VIDEO_LM3646=m + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m + +# +# Audio/Video compression chips +# +CONFIG_VIDEO_SAA6752HS=m + +# +# Miscellaneous helper chips +# +CONFIG_VIDEO_THS7303=m +CONFIG_VIDEO_M52790=m + +# +# Sensors used on soc_camera driver +# + +# +# soc_camera sensor drivers +# +CONFIG_SOC_CAMERA_IMX074=m +CONFIG_SOC_CAMERA_MT9M001=m +CONFIG_SOC_CAMERA_MT9M111=m +CONFIG_SOC_CAMERA_MT9T031=m +CONFIG_SOC_CAMERA_MT9T112=m +CONFIG_SOC_CAMERA_MT9V022=m +CONFIG_SOC_CAMERA_OV2640=m +CONFIG_SOC_CAMERA_OV5642=m +CONFIG_SOC_CAMERA_OV6650=m +CONFIG_SOC_CAMERA_OV772X=m +CONFIG_SOC_CAMERA_OV9640=m +CONFIG_SOC_CAMERA_OV9740=m +CONFIG_SOC_CAMERA_RJ54N1=m +CONFIG_SOC_CAMERA_TW9910=m +CONFIG_MEDIA_TUNER=m + +# +# Customize TV tuners +# +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MSI001=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_MT2060=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_MEDIA_TUNER_MT2266=m +CONFIG_MEDIA_TUNER_MT2131=m +CONFIG_MEDIA_TUNER_QT1010=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_XC4000=m +CONFIG_MEDIA_TUNER_MXL5005S=m +CONFIG_MEDIA_TUNER_MXL5007T=m +CONFIG_MEDIA_TUNER_MC44S803=m +CONFIG_MEDIA_TUNER_MAX2165=m +CONFIG_MEDIA_TUNER_TDA18218=m +CONFIG_MEDIA_TUNER_FC0011=m +CONFIG_MEDIA_TUNER_FC0012=m +CONFIG_MEDIA_TUNER_FC0013=m +CONFIG_MEDIA_TUNER_TDA18212=m +CONFIG_MEDIA_TUNER_E4000=m +CONFIG_MEDIA_TUNER_FC2580=m +CONFIG_MEDIA_TUNER_M88RS6000T=m +CONFIG_MEDIA_TUNER_TUA9001=m +CONFIG_MEDIA_TUNER_SI2157=m +CONFIG_MEDIA_TUNER_IT913X=m +CONFIG_MEDIA_TUNER_R820T=m +CONFIG_MEDIA_TUNER_MXL301RF=m +CONFIG_MEDIA_TUNER_QM1D1C0042=m + +# +# Customise DVB Frontends +# + +# +# Multistandard (satellite) frontends +# +CONFIG_DVB_STB0899=m +CONFIG_DVB_STB6100=m +CONFIG_DVB_STV090x=m +CONFIG_DVB_STV6110x=m +CONFIG_DVB_M88DS3103=m + +# +# Multistandard (cable + terrestrial) frontends +# +CONFIG_DVB_DRXK=m +CONFIG_DVB_TDA18271C2DD=m +CONFIG_DVB_SI2165=m + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_MT312=m +CONFIG_DVB_ZL10036=m +CONFIG_DVB_ZL10039=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_STV0288=m +CONFIG_DVB_STB6000=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_STV6110=m +CONFIG_DVB_STV0900=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8261=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_TUNER_ITD1000=m +CONFIG_DVB_TUNER_CX24113=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_CX24116=m +CONFIG_DVB_CX24117=m +CONFIG_DVB_SI21XX=m +CONFIG_DVB_TS2020=m +CONFIG_DVB_DS3000=m +CONFIG_DVB_MB86A16=m +CONFIG_DVB_TDA10071=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_S5H1432=m +CONFIG_DVB_DRXD=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +CONFIG_DVB_DIB9000=m +CONFIG_DVB_TDA10048=m +CONFIG_DVB_AF9013=m +CONFIG_DVB_EC100=m +CONFIG_DVB_HD29L2=m +CONFIG_DVB_STV0367=m +CONFIG_DVB_CXD2820R=m +CONFIG_DVB_RTL2830=m +CONFIG_DVB_RTL2832=m +CONFIG_DVB_RTL2832_SDR=m +CONFIG_DVB_SI2168=m +CONFIG_DVB_AS102_FE=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LGDT3305=m +CONFIG_DVB_LGDT3306A=m +CONFIG_DVB_LG2160=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_AU8522=m +CONFIG_DVB_AU8522_DTV=m +CONFIG_DVB_AU8522_V4L=m +CONFIG_DVB_S5H1411=m + +# +# ISDB-T (terrestrial) frontends +# +CONFIG_DVB_S921=m +CONFIG_DVB_DIB8000=m +CONFIG_DVB_MB86A20S=m + +# +# ISDB-S (satellite) & ISDB-T (terrestrial) frontends +# +CONFIG_DVB_TC90522=m + +# +# Digital terrestrial only tuners/PLL +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_DIB0090=m + +# +# SEC control devices for DVB-S +# +CONFIG_DVB_DRX39XYJ=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_LNBP22=m +CONFIG_DVB_ISL6405=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_ISL6423=m +CONFIG_DVB_A8293=m +CONFIG_DVB_SP2=m +CONFIG_DVB_LGS8GL5=m +CONFIG_DVB_LGS8GXX=m +CONFIG_DVB_ATBM8830=m +CONFIG_DVB_TDA665x=m +CONFIG_DVB_IX2505V=m +CONFIG_DVB_M88RS2000=m +CONFIG_DVB_AF9033=m + +# +# Tools to develop new frontends +# +CONFIG_DVB_DUMMY_FE=m + +# +# Graphics support +# +# CONFIG_VGA_ARB is not set +# CONFIG_IMX_IPUV3_CORE is not set + +# +# Direct Rendering Manager +# +CONFIG_DRM=m +# CONFIG_DRM_PTN3460 is not set +# CONFIG_DRM_PS8622 is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_R128 is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_ARMADA is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_STI is not set +CONFIG_DRM_VIVANTE=m + +# +# Frame buffer Devices +# +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_CMDLINE=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +CONFIG_FB_UDL=m +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_MXS is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_FB_MXC=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_DCIC=y +CONFIG_FB_MXC_EDID=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_L4F00242T03=m +CONFIG_LCD_LMS283GF05=m +CONFIG_LCD_LTV350QV=m +CONFIG_LCD_ILI922X=m +CONFIG_LCD_ILI9320=m +CONFIG_LCD_TDO24M=m +CONFIG_LCD_VGG2432A4=m +CONFIG_LCD_PLATFORM=y +CONFIG_LCD_S6E63M0=m +CONFIG_LCD_LD9040=m +CONFIG_LCD_AMS369FG06=m +CONFIG_LCD_LMS501KF03=m +CONFIG_LCD_HX8357=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_DA9052=m +CONFIG_BACKLIGHT_ADP8860=m +CONFIG_BACKLIGHT_ADP8870=m +CONFIG_BACKLIGHT_LM3630A=m +CONFIG_BACKLIGHT_LM3639=m +CONFIG_BACKLIGHT_LP855X=m +CONFIG_BACKLIGHT_GPIO=m +CONFIG_BACKLIGHT_LV5207LP=m +CONFIG_BACKLIGHT_BD6107=m +# CONFIG_VGASTATE is not set +CONFIG_VIDEOMODE_HELPERS=y +CONFIG_HDMI=y + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +CONFIG_SOUND_OSS_CORE=y +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_DMAENGINE_PCM=y +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_HRTIMER=y +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_VMASTER=y +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_MPU401_UART=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DRIVERS=y +CONFIG_SND_DUMMY=m +CONFIG_SND_ALOOP=m +CONFIG_SND_MTPAV=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_USB_HIFACE=m +CONFIG_SND_BCD2000=m +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_VARIAX is not set +CONFIG_SND_SOC=y +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +CONFIG_SND_SOC_FSL_SAI=y +CONFIG_SND_SOC_FSL_SSI=y +CONFIG_SND_SOC_FSL_SPDIF=y +CONFIG_SND_SOC_FSL_ESAI=y +CONFIG_SND_SOC_FSL_HDMI=y +CONFIG_SND_SOC_FSL_UTILS=y +CONFIG_SND_SOC_IMX_PCM_DMA=y +CONFIG_SND_SOC_IMX_HDMI_DMA=y +CONFIG_SND_SOC_IMX_AUDMUX=y +CONFIG_SND_IMX_SOC=y + +# +# SoC Audio support for Freescale i.MX boards: +# +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +CONFIG_SND_SOC_IMX_SGTL5000=y +CONFIG_SND_SOC_IMX_SPDIF=y +# CONFIG_SND_SOC_IMX_MC13783 is not set +CONFIG_SND_SOC_IMX_HDMI=y +CONFIG_SND_SOC_FSL_ASOC_CARD=m +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=y + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=y +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +CONFIG_SND_SOC_SGTL5000=y +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=y +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=m + +# +# HID support +# +CONFIG_HID=y +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=m +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=m +CONFIG_HID_APPLEIR=m +CONFIG_HID_AUREAL=m +CONFIG_HID_BELKIN=m +# CONFIG_HID_BETOP_FF is not set +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_PRODIKEYS=m +CONFIG_HID_CP2112=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=m +CONFIG_HID_ELECOM=m +CONFIG_HID_ELO=m +CONFIG_HID_EZKEY=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_GT683R=m +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_KYE=m +CONFIG_HID_UCLOGIC=m +CONFIG_HID_WALTOP=m +CONFIG_HID_GYRATION=m +CONFIG_HID_ICADE=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_HID_LOGITECH_HIDPP=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PENMOUNT=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m +CONFIG_HID_PICOLCD_FB=y +CONFIG_HID_PICOLCD_BACKLIGHT=y +CONFIG_HID_PICOLCD_LCD=y +CONFIG_HID_PICOLCD_LEDS=y +CONFIG_HID_PICOLCD_CIR=y +CONFIG_HID_PLANTRONICS=m +CONFIG_HID_PRIMAX=m +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAITEK=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m +CONFIG_SONY_FF=y +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_STEELSERIES=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_RMI=m +CONFIG_HID_GREENASIA=m +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THINGM=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_WACOM=m +CONFIG_HID_WIIMOTE=m +CONFIG_HID_XINMO=m +CONFIG_HID_ZEROPLUS=m +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=m +CONFIG_HID_SENSOR_HUB=m +# CONFIG_HID_SENSOR_CUSTOM_SENSOR is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +CONFIG_I2C_HID=m +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_OTG_FSM=y +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_FSL_MPH_DR_OF=m +CONFIG_USB_EHCI_PCI=y +# CONFIG_USB_EHCI_MXC is not set +CONFIG_USB_EHCI_HCD_PLATFORM=y +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_IMX21_HCD is not set +# CONFIG_USB_HCD_BCMA is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_WDM=m +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_REALTEK=y +CONFIG_REALTEK_AUTOPM=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_STORAGE_ENE_UB6250=y +CONFIG_USB_UAS=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_HOST=m +# CONFIG_USBIP_DEBUG is not set +CONFIG_USB_MUSB_HDRC=m +CONFIG_USB_MUSB_HOST=y +# CONFIG_USB_MUSB_GADGET is not set +# CONFIG_USB_MUSB_DUAL_ROLE is not set + +# +# Platform Glue Layer +# +CONFIG_MUSB_PIO_ONLY=y +CONFIG_USB_DWC3=m +CONFIG_USB_DWC3_HOST=y +# CONFIG_USB_DWC3_GADGET is not set +# CONFIG_USB_DWC3_DUAL_ROLE is not set + +# +# Platform Glue Driver Support +# +CONFIG_USB_DWC3_PCI=m + +# +# Debugging features +# +# CONFIG_USB_DWC3_DEBUG is not set +CONFIG_USB_DWC2=m +CONFIG_USB_DWC2_HOST=y + +# +# Gadget/Dual-role mode requires USB Gadget support to be enabled +# +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +CONFIG_USB_DWC2_PLATFORM=m +CONFIG_USB_DWC2_PCI=m +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_OF=y +CONFIG_USB_CHIPIDEA_PCI=y +# CONFIG_USB_CHIPIDEA_UDC is not set +CONFIG_USB_CHIPIDEA_HOST=y +# CONFIG_USB_CHIPIDEA_DEBUG is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_SEVSEG=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +CONFIG_USB_SISUSBVGA_CON=y +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +CONFIG_USB_ISIGHTFW=m +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_CHAOSKEY is not set + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_AM335X_CONTROL_USB=m +CONFIG_AM335X_PHY_USB=m +CONFIG_USB_GPIO_VBUS=m +CONFIG_USB_ISP1301=m +CONFIG_USB_MXS_PHY=y +# CONFIG_USB_ULPI is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +CONFIG_USB_FSL_USB2=m +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_BDC_UDC is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=m +CONFIG_USB_F_ACM=m +CONFIG_USB_F_SS_LB=m +CONFIG_USB_U_SERIAL=m +CONFIG_USB_U_ETHER=m +CONFIG_USB_F_SERIAL=m +CONFIG_USB_F_OBEX=m +CONFIG_USB_F_NCM=m +CONFIG_USB_F_ECM=m +CONFIG_USB_F_EEM=m +CONFIG_USB_F_SUBSET=m +CONFIG_USB_F_RNDIS=m +CONFIG_USB_F_MASS_STORAGE=m +CONFIG_USB_F_FS=m +CONFIG_USB_F_UAC1=m +CONFIG_USB_F_UAC2=m +CONFIG_USB_F_UVC=m +CONFIG_USB_F_MIDI=m +CONFIG_USB_F_HID=m +CONFIG_USB_F_PRINTER=m +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_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +# CONFIG_USB_CONFIGFS_F_UVC is not set +# CONFIG_USB_CONFIGFS_F_PRINTER is not set +CONFIG_USB_ZERO=m +CONFIG_USB_ZERO_HNPTEST=y +# CONFIG_USB_AUDIO is not set +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_ETH_EEM=y +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_FUNCTIONFS=m +CONFIG_USB_FUNCTIONFS_ETH=y +CONFIG_USB_FUNCTIONFS_RNDIS=y +CONFIG_USB_FUNCTIONFS_GENERIC=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_USB_MIDI_GADGET=m +CONFIG_USB_G_PRINTER=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_G_ACM_MS=m +CONFIG_USB_G_MULTI=m +CONFIG_USB_G_MULTI_RNDIS=y +CONFIG_USB_G_MULTI_CDC=y +# CONFIG_USB_G_HID is not set +CONFIG_USB_G_DBGP=m +# CONFIG_USB_G_DBGP_PRINTK is not set +CONFIG_USB_G_DBGP_SERIAL=y +CONFIG_USB_G_WEBCAM=m +CONFIG_USB_LED_TRIG=y +# CONFIG_UWB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=m +CONFIG_MMC_SDHCI_ESDHC_IMX=y +# CONFIG_MMC_SDHCI_F_SDH30 is not set +CONFIG_MMC_MXC=y +CONFIG_MMC_TIFM_SD=m +CONFIG_MMC_CB710=m +# CONFIG_MMC_VIA_SDMMC is not set +CONFIG_MMC_DW=y +CONFIG_MMC_DW_IDMAC=y +CONFIG_MMC_DW_PLTFM=y +CONFIG_MMC_DW_EXYNOS=y +# CONFIG_MMC_DW_K3 is not set +# CONFIG_MMC_DW_PCI is not set +CONFIG_MMC_VUB300=m +CONFIG_MMC_USHC=y +CONFIG_MMC_USDHI6ROL0=m +CONFIG_MMC_TOSHIBA_PCI=m +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m +# CONFIG_LEDS_CLASS_FLASH is not set + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DA9052 is not set +# CONFIG_LEDS_DAC124S085 is not set +CONFIG_LEDS_PWM=m +CONFIG_LEDS_REGULATOR=m +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_MC13783 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_PM8941_WLED is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=m +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_LEDS_TRIGGER_TRANSIENT=m +CONFIG_LEDS_TRIGGER_CAMERA=m +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +# CONFIG_RTC_SYSTOHC is not set +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +CONFIG_RTC_DRV_PCF8523=y +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_MCP795 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DA9052 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_IMXDI=y +CONFIG_RTC_DRV_MC13XXX=y +CONFIG_RTC_DRV_MXC=y +CONFIG_RTC_DRV_SNVS=y +# CONFIG_RTC_DRV_XGENE is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DW_DMAC_CORE=m +CONFIG_DW_DMAC=m +CONFIG_DW_DMAC_PCI=m +# CONFIG_HSU_DMA_PCI is not set +# CONFIG_MX3_IPU is not set +CONFIG_IMX_SDMA=y +# CONFIG_IMX_DMA is not set +CONFIG_MXS_DMA=y +CONFIG_FSL_EDMA=m +# CONFIG_NBPFAXI_DMA is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=m +CONFIG_DMA_OF=y + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +CONFIG_PRISM2_USB=m +CONFIG_COMEDI=m +# CONFIG_COMEDI_DEBUG is not set +CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB=2048 +CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB=20480 +# CONFIG_COMEDI_MISC_DRIVERS is not set +# CONFIG_COMEDI_ISA_DRIVERS is not set +# CONFIG_COMEDI_PCI_DRIVERS is not set +# CONFIG_COMEDI_USB_DRIVERS is not set +# CONFIG_COMEDI_8255 is not set +# CONFIG_COMEDI_KCOMEDILIB is not set +CONFIG_RTL8192U=m +CONFIG_RTLLIB=m +CONFIG_RTLLIB_CRYPTO_CCMP=m +CONFIG_RTLLIB_CRYPTO_TKIP=m +CONFIG_RTLLIB_CRYPTO_WEP=m +CONFIG_RTL8192E=m +CONFIG_R8712U=m +CONFIG_R8188EU=m +CONFIG_88EU_AP_MODE=y +CONFIG_R8723AU=m +CONFIG_8723AU_AP_MODE=y +CONFIG_8723AU_BT_COEXIST=y +CONFIG_RTS5208=m +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set + +# +# IIO staging drivers +# + +# +# Accelerometers +# +# 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 + +# +# Analog to digital converters +# +# CONFIG_AD7606 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7280 is not set + +# +# Analog digital bi-direction converters +# +# CONFIG_ADT7316 is not set + +# +# Capacitance to digital converters +# +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7746 is not set + +# +# Direct Digital Synthesis +# +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16060 is not set + +# +# Network Analyzer, Impedance Converters +# +# CONFIG_AD5933 is not set + +# +# Light sensors +# +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set + +# +# Magnetometer sensors +# +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set + +# +# Active energy metering IC +# +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set + +# +# Resolver to digital converters +# +# CONFIG_AD2S90 is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set + +# +# Triggers - standalone +# +CONFIG_IIO_PERIODIC_RTC_TRIGGER=m +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_FB_SM750 is not set +# CONFIG_FB_XGI is not set +CONFIG_FT1000=m +CONFIG_FT1000_USB=m + +# +# Speakup console speech +# +CONFIG_SPEAKUP=m +CONFIG_SPEAKUP_SYNTH_ACNTSA=m +CONFIG_SPEAKUP_SYNTH_APOLLO=m +CONFIG_SPEAKUP_SYNTH_AUDPTR=m +CONFIG_SPEAKUP_SYNTH_BNS=m +CONFIG_SPEAKUP_SYNTH_DECTLK=m +CONFIG_SPEAKUP_SYNTH_DECEXT=m +CONFIG_SPEAKUP_SYNTH_LTLK=m +CONFIG_SPEAKUP_SYNTH_SOFT=m +CONFIG_SPEAKUP_SYNTH_SPKOUT=m +CONFIG_SPEAKUP_SYNTH_TXPRT=m +CONFIG_SPEAKUP_SYNTH_DUMMY=m +CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=m +CONFIG_STAGING_MEDIA=y +CONFIG_I2C_BCM2048=m +CONFIG_DVB_CXD2099=m +CONFIG_VIDEO_DT3155=m +CONFIG_DT3155_CCIR=y +CONFIG_DT3155_STREAMING=y +CONFIG_DVB_MN88472=m +CONFIG_DVB_MN88473=m +CONFIG_LIRC_STAGING=y +CONFIG_LIRC_BT829=m +CONFIG_LIRC_IMON=m +CONFIG_LIRC_SASEM=m +CONFIG_LIRC_SERIAL=m +CONFIG_LIRC_SERIAL_TRANSMITTER=y +CONFIG_LIRC_SIR=m +CONFIG_LIRC_ZILOG=m + +# +# Android +# +CONFIG_USB_WPAN_HCD=m +CONFIG_WIMAX_GDM72XX=m +CONFIG_WIMAX_GDM72XX_QOS=y +CONFIG_WIMAX_GDM72XX_K_MODE=y +CONFIG_WIMAX_GDM72XX_WIMAX2=y +CONFIG_WIMAX_GDM72XX_USB=y +# CONFIG_WIMAX_GDM72XX_SDIO is not set +CONFIG_WIMAX_GDM72XX_USB_PM=y +CONFIG_LTE_GDM724X=m +CONFIG_MTD_SPINAND_MT29F=m +# CONFIG_MTD_SPINAND_ONDIEECC is not set +# CONFIG_LUSTRE_FS is not set +CONFIG_DGNC=m +CONFIG_DGAP=m +# CONFIG_GS_FPGABOOT is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +# CONFIG_FB_TFT is not set +# CONFIG_I2O is not set +# CONFIG_CHROME_PLATFORMS is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_CDCE706 is not set + +# +# Hardware Spinlock drivers +# + +# +# Clock Source drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_MMIO=y +# CONFIG_ATMEL_PIT is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_EM_TIMER_STI is not set +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +# CONFIG_ARM_SMMU is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# + +# +# SOC (System On Chip) specific Drivers +# +# CONFIG_SOC_TI is not set +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m +CONFIG_DEVFREQ_GOV_PERFORMANCE=m +CONFIG_DEVFREQ_GOV_POWERSAVE=m +CONFIG_DEVFREQ_GOV_USERSPACE=m + +# +# DEVFREQ Drivers +# +# CONFIG_PM_DEVFREQ_EVENT is not set +CONFIG_EXTCON=m + +# +# Extcon Device Drivers +# +CONFIG_EXTCON_ADC_JACK=m +CONFIG_EXTCON_GPIO=m +CONFIG_EXTCON_RT8973A=m +CONFIG_EXTCON_SM5502=m +# CONFIG_EXTCON_USB_GPIO is not set +# CONFIG_MEMORY is not set +CONFIG_IIO=m +CONFIG_IIO_BUFFER=y +# CONFIG_IIO_BUFFER_CB is not set +CONFIG_IIO_KFIFO_BUF=m +CONFIG_IIO_TRIGGERED_BUFFER=m +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 + +# +# Accelerometers +# +# CONFIG_BMA180 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_HID_SENSOR_ACCEL_3D is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_KXSD9 is not set +# CONFIG_MMA8452 is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set + +# +# Analog to digital converters +# +# CONFIG_AD7266 is not set +# CONFIG_AD7291 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_AD799X is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_NAU7802 is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_VF610_ADC is not set + +# +# Amplifiers +# +# CONFIG_AD8366 is not set + +# +# Hid Sensor IIO Common +# +CONFIG_HID_SENSOR_IIO_COMMON=m +CONFIG_HID_SENSOR_IIO_TRIGGER=m + +# +# SSP Sensor Common +# +# CONFIG_IIO_SSP_SENSORHUB is not set + +# +# Digital to analog converters +# +# CONFIG_AD5064 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 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_MAX517 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set + +# +# Frequency Synthesizers DDS/PLL +# + +# +# Clock Generator/Distribution +# +# CONFIG_AD9523 is not set + +# +# Phase-Locked Loop (PLL) frequency synthesizers +# +# CONFIG_ADF4350 is not set + +# +# Digital gyroscope sensors +# +# 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_BMG160 is not set +CONFIG_HID_SENSOR_GYRO_3D=m +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_ITG3200 is not set + +# +# Humidity sensors +# +CONFIG_DHT11=m +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_KMX61 is not set +# CONFIG_INV_MPU6050_IIO is not set + +# +# Light sensors +# +# CONFIG_ADJD_S311 is not set +# CONFIG_AL3320A is not set +# CONFIG_APDS9300 is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM36651 is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_ISL29125 is not set +# CONFIG_HID_SENSOR_ALS is not set +# CONFIG_HID_SENSOR_PROX is not set +# CONFIG_JSA1212 is not set +# CONFIG_LTR501 is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_TSL4531 is not set +# CONFIG_VCNL4000 is not set + +# +# Magnetometer sensors +# +# CONFIG_AK8975 is not set +# CONFIG_AK09911 is not set +# CONFIG_MAG3110 is not set +# CONFIG_HID_SENSOR_MAGNETOMETER_3D is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set + +# +# Inclinometer sensors +# +# CONFIG_HID_SENSOR_INCLINOMETER_3D is not set +# CONFIG_HID_SENSOR_DEVICE_ROTATION is not set + +# +# Triggers - standalone +# +CONFIG_IIO_INTERRUPT_TRIGGER=m +CONFIG_IIO_SYSFS_TRIGGER=m + +# +# Pressure sensors +# +# CONFIG_BMP280 is not set +# CONFIG_HID_SENSOR_PRESS is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL3115 is not set +# CONFIG_MS5611 is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_T5403 is not set + +# +# Lightning sensors +# +# CONFIG_AS3935 is not set + +# +# Proximity sensors +# +# CONFIG_SX9500 is not set + +# +# Temperature sensors +# +# CONFIG_MLX90614 is not set +# CONFIG_TMP006 is not set +# CONFIG_VME_BUS is not set +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +CONFIG_PWM_FSL_FTM=y +CONFIG_PWM_IMX=y +CONFIG_PWM_PCA9685=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_FMC is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +CONFIG_POWERCAP=y +# CONFIG_MCB is not set +CONFIG_RAS=y +# CONFIG_THUNDERBOLT is not set + +# +# Android +# +# CONFIG_ANDROID is not set + +# +# MXC support drivers +# +CONFIG_MXC_IPU=y + +# +# Vivante GPU support +# +CONFIG_MXC_GPU_VIV=y +CONFIG_MXC_IPU_V3_FSL=y + +# +# MXC Asynchronous Sample Rate Converter support +# +# CONFIG_MXC_ASRC is not set + +# +# MXC VPU(Video Processing Unit) support +# +CONFIG_MXC_VPU=y +# CONFIG_MXC_VPU_DEBUG is not set +# CONFIG_MX6_VPU_352M is not set + +# +# MXC HDMI CEC (Consumer Electronics Control) support +# +CONFIG_MXC_HDMI_CEC=y + +# +# MXC MIPI Support +# +CONFIG_MXC_MIPI_CSI2=m + +# +# MXC Media Local Bus Driver +# +CONFIG_MXC_MLB=y +CONFIG_MXC_MLB150=m + +# +# Firmware Drivers +# +# CONFIG_FIRMWARE_MEMMAP is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +# CONFIG_REISERFS_FS_SECURITY is not set +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=y +CONFIG_BTRFS_FS_POSIX_ACL=y +# 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_NILFS2_FS is not set +CONFIG_F2FS_FS=m +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +# CONFIG_F2FS_FS_SECURITY is not set +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_FANOTIFY=y +# CONFIG_QUOTA is not set +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_QUOTACTL=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_OVERLAY_FS=y + +# +# Caches +# +CONFIG_FSCACHE=m +# CONFIG_FSCACHE_STATS is not set +# CONFIG_FSCACHE_HISTOGRAM is not set +# CONFIG_FSCACHE_DEBUG is not set +# CONFIG_FSCACHE_OBJECT_LIST is not set +CONFIG_CACHEFILES=m +# CONFIG_CACHEFILES_DEBUG is not set +# CONFIG_CACHEFILES_HISTOGRAM is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_UBIFS_FS=m +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_LOGFS=m +# CONFIG_CRAMFS is not set +CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_FILE_CACHE=y +# CONFIG_SQUASHFS_FILE_DIRECT is not set +CONFIG_SQUASHFS_DECOMP_SINGLE=y +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_ZLIB=y +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XZ is not set +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +CONFIG_SYSV_FS=m +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_SWAP is not set +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_PNFS_FILE_LAYOUT=y +CONFIG_PNFS_BLOCK=m +CONFIG_PNFS_FLEXFILE_LAYOUT=m +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +CONFIG_NFS_V4_1_MIGRATION=y +CONFIG_ROOT_NFS=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +# CONFIG_NFSD_PNFS is not set +# CONFIG_NFSD_FAULT_INJECTION is not set +CONFIG_GRACE_PERIOD=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUNRPC_BACKCHANNEL=y +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_UPCALL is not set +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_ACL=y +# CONFIG_CIFS_DEBUG is not set +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_SMB2=y +CONFIG_CIFS_FSCACHE=y +CONFIG_NCP_FS=m +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=y +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_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=y +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_ISO8859_15=y +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 +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_PAGE_OWNER is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=60 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_TIMER_STATS is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_STACKTRACE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set + +# +# Runtime Testing +# +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_MEMTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_IMX_UART_PORT=1 +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEBUG_UART_8250 is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set +# CONFIG_CORESIGHT is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_XOR_BLOCKS=y +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_PCRYPT=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=y +# CONFIG_CRYPTO_MCRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_SEQIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LRW=y +CONFIG_CRYPTO_PCBC=y +CONFIG_CRYPTO_XTS=y + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_VMAC=y + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_GHASH=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_BLOWFISH_COMMON=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST_COMMON=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_ZLIB=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_LZ4HC=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_DRBG_MENU is not set +CONFIG_CRYPTO_USER_API=m +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +# CONFIG_CRYPTO_USER_API_RNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 +# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set +CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=m +CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=m +CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y +# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set +CONFIG_CRYPTO_DEV_FSL_CAAM_SM=m +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_DEV_SAHARA is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ARM_CRYPTO is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_RAID6_PQ=y +CONFIG_BITREVERSE=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_RATIONAL=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_STMP_DEVICE=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +CONFIG_CRC7=m +CONFIG_LIBCRC32C=y +CONFIG_CRC8=y +CONFIG_AUDIT_GENERIC=y +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4HC_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +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 +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_BTREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +CONFIG_AVERAGE=y +CONFIG_CORDIC=m +# CONFIG_DDR is not set +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_FONT_SUPPORT=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_ARCH_HAS_SG_CHAIN=y +# CONFIG_VIRTUALIZATION is not set diff -Nur linux-4.1.13.orig/arch/arm/configs/imx_v7_defconfig linux-4.1.13/arch/arm/configs/imx_v7_defconfig --- linux-4.1.13.orig/arch/arm/configs/imx_v7_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/configs/imx_v7_defconfig 2015-11-30 17:56:13.528141189 +0100 @@ -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-4.1.13.orig/arch/arm/configs/imx_v7_mfg_defconfig linux-4.1.13/arch/arm/configs/imx_v7_mfg_defconfig --- linux-4.1.13.orig/arch/arm/configs/imx_v7_mfg_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/configs/imx_v7_mfg_defconfig 2015-11-30 17:56:13.528141189 +0100 @@ -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-4.1.13.orig/arch/arm/include/asm/glue-cache.h linux-4.1.13/arch/arm/include/asm/glue-cache.h --- linux-4.1.13.orig/arch/arm/include/asm/glue-cache.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/include/asm/glue-cache.h 2015-11-30 17:56:13.528141189 +0100 @@ -102,19 +102,19 @@ #endif #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) -# ifdef _CACHE +//# ifdef _CACHE # define MULTI_CACHE 1 -# else -# define _CACHE v6 -# endif +//# else +//# define _CACHE v6 +//# endif #endif #if defined(CONFIG_CPU_V7) -# ifdef _CACHE +//# ifdef _CACHE # define MULTI_CACHE 1 -# else -# define _CACHE v7 -# endif +//# else +//# define _CACHE v7 +//# endif #endif #if defined(CONFIG_CPU_V7M) diff -Nur linux-4.1.13.orig/arch/arm/Kconfig linux-4.1.13/arch/arm/Kconfig --- linux-4.1.13.orig/arch/arm/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/Kconfig 2015-11-30 17:56:13.528141189 +0100 @@ -1689,6 +1689,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-4.1.13.orig/arch/arm/mach-imx/busfreq_ddr3.c linux-4.1.13/arch/arm/mach-imx/busfreq_ddr3.c --- linux-4.1.13.orig/arch/arm/mach-imx/busfreq_ddr3.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/busfreq_ddr3.c 2015-11-30 17:56:13.528141189 +0100 @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file busfreq_ddr3.c + * + * @brief iMX6 DDR3 frequency change specific file. + * + * @ingroup PM + */ +#define DEBUG + +#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" + +/* DDR settings */ +static unsigned long (*iram_ddr_settings)[2]; +static unsigned long (*normal_mmdc_settings)[2]; +static unsigned long (*iram_iomux_settings)[2]; + +static void __iomem *mmdc_base; +static void __iomem *iomux_base; +static void __iomem *ccm_base; +static void __iomem *l2_base; +static void __iomem *gic_dist_base; +static u32 *irqs_used; + +static void *ddr_freq_change_iram_base; +static int ddr_settings_size; +static int iomux_settings_size; +static volatile unsigned int cpus_in_wfe; +static volatile bool wait_for_ddr_freq_update; +static int curr_ddr_rate; + +void (*mx6_change_ddr_freq)(u32 freq, void *ddr_settings, + bool dll_mode, void *iomux_offsets) = NULL; + +extern unsigned int ddr_med_rate; +extern unsigned int ddr_normal_rate; +extern int low_bus_freq_mode; +extern int audio_bus_freq_mode; +extern void mx6_ddr3_freq_change(u32 freq, void *ddr_settings, + bool dll_mode, void *iomux_offsets); +extern unsigned long save_ttbr1(void); +extern void restore_ttbr1(unsigned long ttbr1); + +#ifdef CONFIG_SMP +extern void __iomem *imx_scu_base; +static unsigned int online_cpus; +#endif + +#define MIN_DLL_ON_FREQ 333000000 +#define MAX_DLL_OFF_FREQ 125000000 +#define DDR_FREQ_CHANGE_SIZE 0x2000 + +unsigned long ddr3_dll_mx6q[][2] = { + {0x0c, 0x0}, + {0x10, 0x0}, + {0x1C, 0x04088032}, + {0x1C, 0x0408803a}, + {0x1C, 0x08408030}, + {0x1C, 0x08408038}, + {0x818, 0x0}, +}; + +unsigned long ddr3_calibration[][2] = { + {0x83c, 0x0}, + {0x840, 0x0}, + {0x483c, 0x0}, + {0x4840, 0x0}, + {0x848, 0x0}, + {0x4848, 0x0}, + {0x850, 0x0}, + {0x4850, 0x0}, +}; + +unsigned long ddr3_dll_mx6dl[][2] = { + {0x0c, 0x0}, + {0x10, 0x0}, + {0x1C, 0x04008032}, + {0x1C, 0x0400803a}, + {0x1C, 0x07208030}, + {0x1C, 0x07208038}, + {0x818, 0x0}, +}; + +unsigned long iomux_offsets_mx6q[][2] = { + {0x5A8, 0x0}, + {0x5B0, 0x0}, + {0x524, 0x0}, + {0x51C, 0x0}, + {0x518, 0x0}, + {0x50C, 0x0}, + {0x5B8, 0x0}, + {0x5C0, 0x0}, +}; + +unsigned long iomux_offsets_mx6dl[][2] = { + {0x4BC, 0x0}, + {0x4C0, 0x0}, + {0x4C4, 0x0}, + {0x4C8, 0x0}, + {0x4CC, 0x0}, + {0x4D0, 0x0}, + {0x4D4, 0x0}, + {0x4D8, 0x0}, +}; + +unsigned long ddr3_400[][2] = { + {0x83c, 0x42490249}, + {0x840, 0x02470247}, + {0x483c, 0x42570257}, + {0x4840, 0x02400240}, + {0x848, 0x4039363C}, + {0x4848, 0x3A39333F}, + {0x850, 0x38414441}, + {0x4850, 0x472D4833} +}; + +int can_change_ddr_freq(void) +{ + return 0; +} + +/* + * each active core apart from the one changing + * the DDR frequency will execute this function. + * the rest of the cores have to remain in WFE + * state until the frequency is changed. + */ +irqreturn_t wait_in_wfe_irq(int irq, void *dev_id) +{ + u32 me = smp_processor_id(); + + *((char *)(&cpus_in_wfe) + (u8)me) = 0xff; + + while (wait_for_ddr_freq_update) + wfe(); + + *((char *)(&cpus_in_wfe) + (u8)me) = 0; + + return IRQ_HANDLED; +} + +/* change the DDR frequency. */ +int update_ddr_freq(int ddr_rate) +{ + int i, j; + 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() && + ddr_med_rate != ddr_normal_rate) { + 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));*/ + + /* + * Flush the TLB, to ensure no TLB maintenance occurs + * when DDR is in self-refresh. + */ + local_flush_tlb_all(); + + 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; +} + +int init_mmdc_ddr3_settings(struct platform_device *busfreq_pdev) +{ + struct device *dev = &busfreq_pdev->dev; + struct platform_device *ocram_dev; + unsigned int iram_paddr; + int i, err; + u32 cpu; + struct device_node *node; + struct gen_pool *iram_pool; + void *iram_addr; + + node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc-combine"); + if (!node) { + pr_err("failed to find imx6q-mmdc device tree data!\n"); + return -EINVAL; + } + mmdc_base = of_iomap(node, 0); + WARN(!mmdc_base, "unable to map mmdc registers\n"); + + node = NULL; + if (cpu_is_imx6q()) + node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-iomuxc"); + if (cpu_is_imx6dl()) + node = of_find_compatible_node(NULL, NULL, + "fsl,imx6dl-iomuxc"); + if (!node) { + pr_err("failed to find imx6q-iomux device tree data!\n"); + return -EINVAL; + } + iomux_base = of_iomap(node, 0); + WARN(!iomux_base, "unable to map iomux registers\n"); + + node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm"); + if (!node) { + pr_err("failed to find imx6q-ccm device tree data!\n"); + return -EINVAL; + } + ccm_base = of_iomap(node, 0); + WARN(!ccm_base, "unable to map mmdc registers\n"); + + node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache"); + if (!node) { + pr_err("failed to find imx6q-pl310-cache device tree data!\n"); + return -EINVAL; + } + l2_base = of_iomap(node, 0); + WARN(!ccm_base, "unable to map mmdc registers\n"); + + node = NULL; + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); + if (!node) { + pr_err("failed to find imx6q-a9-gic device tree data!\n"); + return -EINVAL; + } + gic_dist_base = of_iomap(node, 0); + WARN(!gic_dist_base, "unable to map gic dist registers\n"); + + if (cpu_is_imx6q()) + ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6q) + + ARRAY_SIZE(ddr3_calibration); + if (cpu_is_imx6dl()) + ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6dl) + + ARRAY_SIZE(ddr3_calibration); + + normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL); + if (cpu_is_imx6q()) { + memcpy(normal_mmdc_settings, ddr3_dll_mx6q, + sizeof(ddr3_dll_mx6q)); + memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6q)), + ddr3_calibration, sizeof(ddr3_calibration)); + } + if (cpu_is_imx6dl()) { + memcpy(normal_mmdc_settings, ddr3_dll_mx6dl, + sizeof(ddr3_dll_mx6dl)); + memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6dl)), + ddr3_calibration, sizeof(ddr3_calibration)); + } + /* store the original DDR settings at boot. */ + for (i = 0; i < ddr_settings_size; i++) { + /* + * writes via command mode register cannot be read back. + * hence hardcode them in the initial static array. + * this may require modification on a per customer basis. + */ + if (normal_mmdc_settings[i][0] != 0x1C) + normal_mmdc_settings[i][1] = + readl_relaxed(mmdc_base + + normal_mmdc_settings[i][0]); + } + + irqs_used = devm_kzalloc(dev, sizeof(u32) * num_present_cpus(), + GFP_KERNEL); + + for_each_online_cpu(cpu) { + int irq; + + /* + * set up a reserved interrupt to get all + * the active cores into a WFE state + * before changing the DDR frequency. + */ + irq = platform_get_irq(busfreq_pdev, cpu); + err = request_irq(irq, wait_in_wfe_irq, + IRQF_PERCPU, "mmdc_1", NULL); + if (err) { + dev_err(dev, + "Busfreq:request_irq failed %d, err = %d\n", + irq, err); + return err; + } + err = irq_set_affinity(irq, cpumask_of(cpu)); + if (err) { + dev_err(dev, + "Busfreq: Cannot set irq affinity irq=%d,\n", + irq); + return err; + } + irqs_used[cpu] = irq; + } + + node = NULL; + node = of_find_compatible_node(NULL, NULL, "mmio-sram"); + if (!node) { + dev_err(dev, "%s: failed to find ocram node\n", + __func__); + return -EINVAL; + } + + ocram_dev = of_find_device_by_node(node); + if (!ocram_dev) { + dev_err(dev, "failed to find ocram device!\n"); + return -EINVAL; + } + + iram_pool = dev_get_gen_pool(&ocram_dev->dev); + if (!iram_pool) { + dev_err(dev, "iram pool unavailable!\n"); + return -EINVAL; + } + + iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q); + iram_addr = (void *)gen_pool_alloc(iram_pool, + (iomux_settings_size * 8) + 8); + iram_iomux_settings = iram_addr; + if (!iram_iomux_settings) { + dev_err(dev, "unable to alloc iram for IOMUX settings!\n"); + return -ENOMEM; + } + + /* + * Allocate extra space to store the number of entries in the + * ddr_settings plus 4 extra regsiter information that needs + * to be passed to the frequency change code. + * sizeof(iram_ddr_settings) = sizeof(ddr_settings) + + * entries in ddr_settings + 16. + * The last 4 enties store the addresses of the registers: + * CCM_BASE_ADDR + * MMDC_BASE_ADDR + * IOMUX_BASE_ADDR + * L2X0_BASE_ADDR + */ + iram_addr = (void *)gen_pool_alloc(iram_pool, + (ddr_settings_size * 8) + 8 + 32); + iram_ddr_settings = iram_addr; + if (!iram_ddr_settings) { + dev_err(dev, "unable to alloc iram for ddr settings!\n"); + return -ENOMEM; + } + + i = ddr_settings_size + 1; + iram_ddr_settings[i][0] = (unsigned long)mmdc_base; + iram_ddr_settings[i+1][0] = (unsigned long)ccm_base; + iram_ddr_settings[i+2][0] = (unsigned long)iomux_base; + iram_ddr_settings[i+3][0] = (unsigned long)l2_base; + + if (cpu_is_imx6q()) { + /* store the IOMUX settings at boot. */ + for (i = 0; i < iomux_settings_size; i++) { + iomux_offsets_mx6q[i][1] = + readl_relaxed(iomux_base + + iomux_offsets_mx6q[i][0]); + iram_iomux_settings[i+1][0] = iomux_offsets_mx6q[i][0]; + iram_iomux_settings[i+1][1] = iomux_offsets_mx6q[i][1]; + } + } + + if (cpu_is_imx6dl()) { + for (i = 0; i < iomux_settings_size; i++) { + iomux_offsets_mx6dl[i][1] = + readl_relaxed(iomux_base + + iomux_offsets_mx6dl[i][0]); + iram_iomux_settings[i+1][0] = iomux_offsets_mx6dl[i][0]; + iram_iomux_settings[i+1][1] = iomux_offsets_mx6dl[i][1]; + } + } + + ddr_freq_change_iram_base = (void *)gen_pool_alloc(iram_pool, + DDR_FREQ_CHANGE_SIZE); + if (!ddr_freq_change_iram_base) { + dev_err(dev, "Cannot alloc iram for ddr freq change code!\n"); + return -ENOMEM; + } + + iram_paddr = gen_pool_virt_to_phys(iram_pool, + (unsigned long)ddr_freq_change_iram_base); + /* + * Need to remap the area here since we want + * the memory region to be executable. + */ + ddr_freq_change_iram_base = __arm_ioremap(iram_paddr, + DDR_FREQ_CHANGE_SIZE, + MT_MEMORY_RWX_NONCACHED); + mx6_change_ddr_freq = (void *)fncpy(ddr_freq_change_iram_base, + &mx6_ddr3_freq_change, DDR_FREQ_CHANGE_SIZE); + + curr_ddr_rate = ddr_normal_rate; + + return 0; +} diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/busfreq-imx6.c linux-4.1.13/arch/arm/mach-imx/busfreq-imx6.c --- linux-4.1.13.orig/arch/arm/mach-imx/busfreq-imx6.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/busfreq-imx6.c 2015-11-30 17:56:13.528141189 +0100 @@ -0,0 +1,994 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + * @file busfreq-imx6.c + * + * @brief A common API for the Freescale Semiconductor iMX6 Busfreq API + * + * The APIs are for setting bus frequency to different values based on the + * highest freqeuncy requested. + * + * @ingroup PM + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hardware.h" + +#define LPAPM_CLK 24000000 +#define DDR3_AUDIO_CLK 50000000 +#define LPDDR2_AUDIO_CLK 100000000 + +int vpu352 = 0; + +int high_bus_freq_mode; +int med_bus_freq_mode; +int audio_bus_freq_mode; +int low_bus_freq_mode; +int ultra_low_bus_freq_mode; +unsigned int ddr_med_rate; +unsigned int ddr_normal_rate; + +#ifdef CONFIG_ARM_IMX6Q_CPUFREQ +static int bus_freq_scaling_initialized; +static struct device *busfreq_dev; +static int busfreq_suspended; +static u32 org_arm_rate; +static int bus_freq_scaling_is_active; +static int high_bus_count, med_bus_count, audio_bus_count, low_bus_count; +static unsigned int ddr_low_rate; + +extern int init_mmdc_lpddr2_settings(struct platform_device *dev); +extern int init_mmdc_ddr3_settings(struct platform_device *dev); +extern int update_ddr_freq(int ddr_rate); +extern int update_lpddr2_freq(int ddr_rate); + +DEFINE_MUTEX(bus_freq_mutex); +static DEFINE_SPINLOCK(freq_lock); + +static struct clk *pll2_400; +static struct clk *periph_clk; +static struct clk *periph_pre_clk; +static struct clk *periph_clk2_sel; +static struct clk *periph_clk2; +static struct clk *osc_clk; +static struct clk *cpu_clk; +static struct clk *pll3; +static struct clk *pll2; +static struct clk *pll2_200; +static struct clk *pll1_sys; +static struct clk *periph2_clk; +static struct clk *ocram_clk; +static struct clk *ahb_clk; +static struct clk *pll1_sw_clk; +static struct clk *periph2_pre_clk; +static struct clk *periph2_clk2_sel; +static struct clk *periph2_clk2; +static struct clk *step_clk; +static struct clk *axi_sel_clk; +static struct clk *pll3_pfd1_540m; + +static u32 pll2_org_rate; +static struct delayed_work low_bus_freq_handler; +static struct delayed_work bus_freq_daemon; + +static void enter_lpm_imx6sl(void) +{ + unsigned long flags; + + if (high_bus_freq_mode) { + pll2_org_rate = clk_get_rate(pll2); + /* Set periph_clk to be sourced from OSC_CLK */ + clk_set_parent(periph_clk2_sel, osc_clk); + clk_set_parent(periph_clk, periph_clk2); + /* Ensure AHB/AXI clks are at 24MHz. */ + clk_set_rate(ahb_clk, LPAPM_CLK); + clk_set_rate(ocram_clk, LPAPM_CLK); + } + if (audio_bus_count) { + /* Set AHB to 8MHz to lower pwer.*/ + clk_set_rate(ahb_clk, LPAPM_CLK / 3); + + /* Set up DDR to 100MHz. */ + spin_lock_irqsave(&freq_lock, flags); + update_lpddr2_freq(LPDDR2_AUDIO_CLK); + spin_unlock_irqrestore(&freq_lock, flags); + + /* Fix the clock tree in kernel */ + clk_set_rate(pll2, pll2_org_rate); + clk_set_parent(periph2_pre_clk, pll2_200); + clk_set_parent(periph2_clk, periph2_pre_clk); + + if (low_bus_freq_mode || ultra_low_bus_freq_mode) { + /* + * Swtich ARM to run off PLL2_PFD2_400MHz + * since DDR is anyway at 100MHz. + */ + clk_set_parent(step_clk, pll2_400); + clk_set_parent(pll1_sw_clk, step_clk); + /* + * Ensure that the clock will be + * at original speed. + */ + clk_set_rate(cpu_clk, org_arm_rate); + } + low_bus_freq_mode = 0; + ultra_low_bus_freq_mode = 0; + audio_bus_freq_mode = 1; + } else { + u32 arm_div, pll1_rate; + org_arm_rate = clk_get_rate(cpu_clk); + if (low_bus_freq_mode && low_bus_count == 0) { + /* + * We are already in DDR @ 24MHz state, but + * no one but ARM needs the DDR. In this case, + * we can lower the DDR freq to 1MHz when ARM + * enters WFI in this state. Keep track of this state. + */ + ultra_low_bus_freq_mode = 1; + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + } else { + if (!ultra_low_bus_freq_mode && !low_bus_freq_mode) { + /* + * Anyway, make sure the AHB is running at 24MHz + * in low_bus_freq_mode. + */ + if (audio_bus_freq_mode) + 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. + */ + clk_set_rate(pll1_sys, + clk_round_rate(pll1_sys, org_arm_rate)); + pll1_rate = clk_get_rate(pll1_sys); + arm_div = pll1_rate / org_arm_rate + 1; + /* + * Ensure ARM CLK is lower before + * changing the parent. + */ + clk_set_rate(cpu_clk, org_arm_rate / arm_div); + /* Now set the ARM clk parent to PLL1_SYS. */ + clk_set_parent(pll1_sw_clk, pll1_sys); + + /* + * Set STEP_CLK back to OSC to save power and + * also to maintain the parent.The WFI iram code + * will switch step_clk to osc, but the clock API + * is not aware of the change and when a new request + * to change the step_clk parent to pll2_pfd2_400M + * is requested sometime later, the change is ignored. + */ + clk_set_parent(step_clk, osc_clk); + /* Now set DDR to 24MHz. */ + spin_lock_irqsave(&freq_lock, flags); + update_lpddr2_freq(LPAPM_CLK); + spin_unlock_irqrestore(&freq_lock, flags); + + /* + * Fix the clock tree in kernel. + * Make sure PLL2 rate is updated as it gets + * bypassed in the DDR freq change code. + */ + clk_set_rate(pll2, LPAPM_CLK); + clk_set_parent(periph2_clk2_sel, pll2); + clk_set_parent(periph2_clk, periph2_clk2_sel); + + } + if (low_bus_count == 0) { + ultra_low_bus_freq_mode = 1; + low_bus_freq_mode = 0; + } else { + ultra_low_bus_freq_mode = 0; + low_bus_freq_mode = 1; + } + audio_bus_freq_mode = 0; + } + } +} + +static void exit_lpm_imx6sl(void) +{ + unsigned long flags; + + spin_lock_irqsave(&freq_lock, flags); + /* Change DDR freq in IRAM. */ + update_lpddr2_freq(ddr_normal_rate); + spin_unlock_irqrestore(&freq_lock, flags); + + /* + * Fix the clock tree in kernel. + * Make sure PLL2 rate is updated as it gets + * un-bypassed in the DDR freq change code. + */ + clk_set_rate(pll2, pll2_org_rate); + clk_set_parent(periph2_pre_clk, pll2_400); + clk_set_parent(periph2_clk, periph2_pre_clk); + + /* Ensure that periph_clk is sourced from PLL2_400. */ + clk_set_parent(periph_pre_clk, pll2_400); + /* + * Before switching the perhiph_clk, ensure that the + * AHB/AXI will not be too fast. + */ + clk_set_rate(ahb_clk, LPAPM_CLK / 3); + clk_set_rate(ocram_clk, LPAPM_CLK / 2); + clk_set_parent(periph_clk, periph_pre_clk); + + if (low_bus_freq_mode || ultra_low_bus_freq_mode) { + /* Move ARM from PLL1_SW_CLK to PLL2_400. */ + clk_set_parent(step_clk, pll2_400); + clk_set_parent(pll1_sw_clk, step_clk); + clk_set_rate(cpu_clk, org_arm_rate); + ultra_low_bus_freq_mode = 0; + } +} + +int reduce_bus_freq(void) +{ + int ret = 0; + clk_prepare_enable(pll3); + if (cpu_is_imx6sl()) + enter_lpm_imx6sl(); + else { + if (cpu_is_imx6dl() && (clk_get_parent(axi_sel_clk) + != periph_clk)) + /* Set axi to periph_clk */ + clk_set_parent(axi_sel_clk, periph_clk); + + if (audio_bus_count) { + /* Need to ensure that PLL2_PFD_400M is kept ON. */ + clk_prepare_enable(pll2_400); + update_ddr_freq(DDR3_AUDIO_CLK); + /* Make sure periph clk's parent also got updated */ + ret = clk_set_parent(periph_clk2_sel, pll3); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + ret = clk_set_parent(periph_pre_clk, pll2_200); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + ret = clk_set_parent(periph_clk, periph_pre_clk); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + audio_bus_freq_mode = 1; + low_bus_freq_mode = 0; + } else { + update_ddr_freq(LPAPM_CLK); + /* Make sure periph clk's parent also got updated */ + ret = clk_set_parent(periph_clk2_sel, osc_clk); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + /* Set periph_clk parent to OSC via periph_clk2_sel */ + ret = clk_set_parent(periph_clk, periph_clk2); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + if (audio_bus_freq_mode) + clk_disable_unprepare(pll2_400); + low_bus_freq_mode = 1; + audio_bus_freq_mode = 0; + } + } + clk_disable_unprepare(pll3); + + med_bus_freq_mode = 0; + high_bus_freq_mode = 0; + + if (audio_bus_freq_mode) + dev_dbg(busfreq_dev, "Bus freq set to audio mode. Count:\ + high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); + if (low_bus_freq_mode) + dev_dbg(busfreq_dev, "Bus freq set to low mode. Count:\ + high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); + + return ret; +} + +static void reduce_bus_freq_handler(struct work_struct *work) +{ + mutex_lock(&bus_freq_mutex); + + reduce_bus_freq(); + + mutex_unlock(&bus_freq_mutex); +} + +/* + * Set the DDR, AHB to 24MHz. + * This mode will be activated only when none of the modules that + * need a higher DDR or AHB frequency are active. + */ +int set_low_bus_freq(void) +{ + if (busfreq_suspended) + return 0; + + if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) + return 0; + + /* + * Check to see if we need to got from + * low bus freq mode to audio bus freq mode. + * If so, the change needs to be done immediately. + */ + if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode)) + reduce_bus_freq(); + else + /* + * Don't lower the frequency immediately. Instead + * scheduled a delayed work and drop the freq if + * the conditions still remain the same. + */ + schedule_delayed_work(&low_bus_freq_handler, + usecs_to_jiffies(3000000)); + return 0; +} + +/* + * Set the DDR to either 528MHz or 400MHz for iMX6qd + * or 400MHz for iMX6dl. + */ +int set_high_bus_freq(int high_bus_freq) +{ + int ret = 0; + struct clk *periph_clk_parent; + + if (bus_freq_scaling_initialized && bus_freq_scaling_is_active) + cancel_delayed_work_sync(&low_bus_freq_handler); + + if (busfreq_suspended) + return 0; + + if (cpu_is_imx6q()) + periph_clk_parent = pll2; + else + periph_clk_parent = pll2_400; + + if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) + return 0; + + if (high_bus_freq_mode) + return 0; + + /* medium bus freq is only supported for MX6DQ */ + if (med_bus_freq_mode && !high_bus_freq) + return 0; + + clk_prepare_enable(pll3); + if (cpu_is_imx6sl()) + exit_lpm_imx6sl(); + else { + if (high_bus_freq) { + update_ddr_freq(ddr_normal_rate); + /* Make sure periph clk's parent also got updated */ + ret = clk_set_parent(periph_clk2_sel, pll3); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + ret = clk_set_parent(periph_pre_clk, periph_clk_parent); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + ret = clk_set_parent(periph_clk, periph_pre_clk); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + if (cpu_is_imx6dl() && (clk_get_parent(axi_sel_clk) + != pll3_pfd1_540m)) + /* Set axi to pll3_pfd1_540m */ + clk_set_parent(axi_sel_clk, pll3_pfd1_540m); + } else { + update_ddr_freq(ddr_med_rate); + /* Make sure periph clk's parent also got updated */ + ret = clk_set_parent(periph_clk2_sel, pll3); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + ret = clk_set_parent(periph_pre_clk, pll2_400); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + ret = clk_set_parent(periph_clk, periph_pre_clk); + if (ret) + dev_WARN(busfreq_dev, + "%s: %d: clk set parent fail!\n", + __func__, __LINE__); + } + if (audio_bus_freq_mode) + clk_disable_unprepare(pll2_400); + } + + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + + clk_disable_unprepare(pll3); + + if (high_bus_freq_mode) + dev_dbg(busfreq_dev, "Bus freq set to high mode. Count:\ + high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); + if (med_bus_freq_mode) + dev_dbg(busfreq_dev, "Bus freq set to med mode. Count:\ + high %d, med %d, audio %d\n", + high_bus_count, med_bus_count, audio_bus_count); + + return 0; +} +#endif + +void request_bus_freq(enum bus_freq_mode mode) +{ + if (vpu352) + return; +#ifdef CONFIG_ARM_IMX6Q_CPUFREQ + mutex_lock(&bus_freq_mutex); + + if (mode == BUS_FREQ_HIGH) + high_bus_count++; + else if (mode == BUS_FREQ_MED) + med_bus_count++; + else if (mode == BUS_FREQ_AUDIO) + audio_bus_count++; + else if (mode == BUS_FREQ_LOW) + low_bus_count++; + + if (busfreq_suspended || !bus_freq_scaling_initialized || + !bus_freq_scaling_is_active) { + mutex_unlock(&bus_freq_mutex); + return; + } + cancel_delayed_work_sync(&low_bus_freq_handler); + + if (cpu_is_imx6dl()) { + /* No support for medium setpoint on MX6DL. */ + if (mode == BUS_FREQ_MED) { + high_bus_count++; + mode = BUS_FREQ_HIGH; + } + } + + if ((mode == BUS_FREQ_HIGH) && (!high_bus_freq_mode)) { + set_high_bus_freq(1); + mutex_unlock(&bus_freq_mutex); + return; + } + + if ((mode == BUS_FREQ_MED) && (!high_bus_freq_mode) && + (!med_bus_freq_mode)) { + set_high_bus_freq(0); + mutex_unlock(&bus_freq_mutex); + return; + } + if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) && + (!med_bus_freq_mode) && (!audio_bus_freq_mode)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + mutex_unlock(&bus_freq_mutex); +#endif + return; +} +EXPORT_SYMBOL(request_bus_freq); + +void release_bus_freq(enum bus_freq_mode mode) +{ + if (vpu352) + return; +#ifdef CONFIG_ARM_IMX6Q_CPUFREQ + mutex_lock(&bus_freq_mutex); + + if (mode == BUS_FREQ_HIGH) { + if (high_bus_count == 0) { + dev_err(busfreq_dev, "high bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + high_bus_count--; + } else if (mode == BUS_FREQ_MED) { + if (med_bus_count == 0) { + dev_err(busfreq_dev, "med bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + med_bus_count--; + } else if (mode == BUS_FREQ_AUDIO) { + if (audio_bus_count == 0) { + dev_err(busfreq_dev, "audio bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + audio_bus_count--; + } else if (mode == BUS_FREQ_LOW) { + if (low_bus_count == 0) { + dev_err(busfreq_dev, "low bus count mismatch!\n"); + dump_stack(); + mutex_unlock(&bus_freq_mutex); + return; + } + low_bus_count--; + } + + if (busfreq_suspended || !bus_freq_scaling_initialized || + !bus_freq_scaling_is_active) { + mutex_unlock(&bus_freq_mutex); + return; + } + + if (cpu_is_imx6dl()) { + /* No support for medium setpoint on MX6DL. */ + if (mode == BUS_FREQ_MED) { + high_bus_count--; + mode = BUS_FREQ_HIGH; + } + } + + if ((!audio_bus_freq_mode) && (high_bus_count == 0) && + (med_bus_count == 0) && (audio_bus_count != 0)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + if ((!low_bus_freq_mode) && (high_bus_count == 0) && + (med_bus_count == 0) && (audio_bus_count == 0) && + (low_bus_count != 0)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + if ((!ultra_low_bus_freq_mode) && (high_bus_count == 0) && + (med_bus_count == 0) && (audio_bus_count == 0) && + (low_bus_count == 0)) { + set_low_bus_freq(); + mutex_unlock(&bus_freq_mutex); + return; + } + + mutex_unlock(&bus_freq_mutex); +#endif + return; +} +EXPORT_SYMBOL(release_bus_freq); + +#ifdef CONFIG_ARM_IMX6Q_CPUFREQ +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 vpu352_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (vpu352) + return sprintf(buf, "VPU352M is enabled\n"); + else + return sprintf(buf, "VPU352M is disabled\n"); +} + +static int vpu352_setup(char *options) +{ + return kstrtol(options, 0, (long int *)&vpu352); +} + +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); +static DEVICE_ATTR(vpu352, 0444, vpu352_enable_show, + NULL); +#endif + +/*! + * This is the probe routine for the bus frequency driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ + +static int busfreq_probe(struct platform_device *pdev) +{ +#ifdef CONFIG_ARM_IMX6Q_CPUFREQ + u32 err; + + busfreq_dev = &pdev->dev; + + pll2_400 = devm_clk_get(&pdev->dev, "pll2_pfd2_396m"); + if (IS_ERR(pll2_400)) { + dev_err(busfreq_dev, "%s: failed to get pll2_pfd2_396m\n", + __func__); + return PTR_ERR(pll2_400); + } + + pll2_200 = devm_clk_get(&pdev->dev, "pll2_198m"); + if (IS_ERR(pll2_200)) { + dev_err(busfreq_dev, "%s: failed to get pll2_198m\n", + __func__); + return PTR_ERR(pll2_200); + } + + pll2 = devm_clk_get(&pdev->dev, "pll2_bus"); + if (IS_ERR(pll2)) { + dev_err(busfreq_dev, "%s: failed to get pll2_bus\n", + __func__); + return PTR_ERR(pll2); + } + + cpu_clk = devm_clk_get(&pdev->dev, "arm"); + if (IS_ERR(cpu_clk)) { + dev_err(busfreq_dev, "%s: failed to get cpu_clk\n", + __func__); + return PTR_ERR(cpu_clk); + } + + pll3 = devm_clk_get(&pdev->dev, "pll3_usb_otg"); + if (IS_ERR(pll3)) { + dev_err(busfreq_dev, "%s: failed to get pll3_usb_otg\n", + __func__); + return PTR_ERR(pll3); + } + + periph_clk = devm_clk_get(&pdev->dev, "periph"); + if (IS_ERR(periph_clk)) { + dev_err(busfreq_dev, "%s: failed to get periph\n", + __func__); + return PTR_ERR(periph_clk); + } + + periph_pre_clk = devm_clk_get(&pdev->dev, "periph_pre"); + if (IS_ERR(periph_pre_clk)) { + dev_err(busfreq_dev, "%s: failed to get periph_pre\n", + __func__); + return PTR_ERR(periph_pre_clk); + } + + periph_clk2 = devm_clk_get(&pdev->dev, "periph_clk2"); + if (IS_ERR(periph_clk2)) { + dev_err(busfreq_dev, "%s: failed to get periph_clk2\n", + __func__); + return PTR_ERR(periph_clk2); + } + + periph_clk2_sel = devm_clk_get(&pdev->dev, "periph_clk2_sel"); + if (IS_ERR(periph_clk2_sel)) { + dev_err(busfreq_dev, "%s: failed to get periph_clk2_sel\n", + __func__); + return PTR_ERR(periph_clk2_sel); + } + + osc_clk = devm_clk_get(&pdev->dev, "osc"); + if (IS_ERR(osc_clk)) { + dev_err(busfreq_dev, "%s: failed to get osc_clk\n", + __func__); + return PTR_ERR(osc_clk); + } + + if (cpu_is_imx6dl()) { + axi_sel_clk = devm_clk_get(&pdev->dev, "axi_sel"); + if (IS_ERR(axi_sel_clk)) { + dev_err(busfreq_dev, "%s: failed to get axi_sel_clk\n", + __func__); + return PTR_ERR(axi_sel_clk); + } + + pll3_pfd1_540m = devm_clk_get(&pdev->dev, "pll3_pfd1_540m"); + if (IS_ERR(pll3_pfd1_540m)) { + dev_err(busfreq_dev, + "%s: failed to get pll3_pfd1_540m\n", __func__); + return PTR_ERR(pll3_pfd1_540m); + } + } + + if (cpu_is_imx6sl()) { + pll1_sys = devm_clk_get(&pdev->dev, "pll1_sys"); + if (IS_ERR(pll1_sys)) { + dev_err(busfreq_dev, "%s: failed to get pll1_sys\n", + __func__); + return PTR_ERR(pll1_sys); + } + + ahb_clk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(ahb_clk)) { + dev_err(busfreq_dev, "%s: failed to get ahb_clk\n", + __func__); + return PTR_ERR(ahb_clk); + } + + ocram_clk = devm_clk_get(&pdev->dev, "ocram"); + if (IS_ERR(ocram_clk)) { + dev_err(busfreq_dev, "%s: failed to get ocram_clk\n", + __func__); + return PTR_ERR(ocram_clk); + } + + pll1_sw_clk = devm_clk_get(&pdev->dev, "pll1_sw"); + if (IS_ERR(pll1_sw_clk)) { + dev_err(busfreq_dev, "%s: failed to get pll1_sw_clk\n", + __func__); + return PTR_ERR(pll1_sw_clk); + } + + periph2_clk = devm_clk_get(&pdev->dev, "periph2"); + if (IS_ERR(periph2_clk)) { + dev_err(busfreq_dev, "%s: failed to get periph2\n", + __func__); + return PTR_ERR(periph2_clk); + } + + periph2_pre_clk = devm_clk_get(&pdev->dev, "periph2_pre"); + if (IS_ERR(periph2_pre_clk)) { + dev_err(busfreq_dev, + "%s: failed to get periph2_pre_clk\n", + __func__); + return PTR_ERR(periph2_pre_clk); + } + + periph2_clk2 = devm_clk_get(&pdev->dev, "periph2_clk2"); + if (IS_ERR(periph2_clk2)) { + dev_err(busfreq_dev, + "%s: failed to get periph2_clk2\n", + __func__); + return PTR_ERR(periph2_clk2); + } + + periph2_clk2_sel = devm_clk_get(&pdev->dev, "periph2_clk2_sel"); + if (IS_ERR(periph2_clk2_sel)) { + dev_err(busfreq_dev, + "%s: failed to get periph2_clk2_sel\n", + __func__); + return PTR_ERR(periph2_clk2_sel); + } + + step_clk = devm_clk_get(&pdev->dev, "step"); + if (IS_ERR(step_clk)) { + dev_err(busfreq_dev, + "%s: failed to get step_clk\n", + __func__); + return PTR_ERR(periph2_clk2_sel); + } + + } + + err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + if (err) { + dev_err(busfreq_dev, + "Unable to register sysdev entry for BUSFREQ"); + return err; + } + err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_vpu352.attr); + if (err) { + dev_err(busfreq_dev, + "Unable to register sysdev entry for BUSFREQ"); + return err; + } + + if (of_property_read_u32(pdev->dev.of_node, "fsl,max_ddr_freq", + &ddr_normal_rate)) { + dev_err(busfreq_dev, "max_ddr_freq entry missing\n"); + return -EINVAL; + } +#endif + + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + ultra_low_bus_freq_mode = 0; + +#ifdef CONFIG_ARM_IMX6Q_CPUFREQ + bus_freq_scaling_is_active = 1; + bus_freq_scaling_initialized = 1; + + ddr_low_rate = LPAPM_CLK; + if (cpu_is_imx6q()) { + if (of_property_read_u32(pdev->dev.of_node, "fsl,med_ddr_freq", + &ddr_med_rate)) { + dev_info(busfreq_dev, + "DDR medium rate not supported.\n"); + ddr_med_rate = ddr_normal_rate; + } + } + + INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler); + INIT_DELAYED_WORK(&bus_freq_daemon, bus_freq_daemon_handler); + register_pm_notifier(&imx_bus_freq_pm_notifier); + register_reboot_notifier(&imx_busfreq_reboot_notifier); + + if (cpu_is_imx6sl()) + err = init_mmdc_lpddr2_settings(pdev); + else + err = init_mmdc_ddr3_settings(pdev); + if (err) { + dev_err(busfreq_dev, "Busfreq init of MMDC failed\n"); + return err; + } +#endif + return 0; +} + +static const struct of_device_id imx6_busfreq_ids[] = { + { .compatible = "fsl,imx6_busfreq", }, + { /* sentinel */ } +}; + +static struct platform_driver busfreq_driver = { + .driver = { + .name = "imx6_busfreq", + .owner = THIS_MODULE, + .of_match_table = imx6_busfreq_ids, + }, + .probe = busfreq_probe, +}; + +/*! + * Initialise the busfreq_driver. + * + * @return The function always returns 0. + */ + +static int __init busfreq_init(void) +{ + if (vpu352) { + printk(KERN_INFO "VPU@352Mhz activated. Bus freq driver module inactive\n"); + return 0; + } + + if (platform_driver_register(&busfreq_driver) != 0) + return -ENODEV; + + printk(KERN_INFO "Bus freq driver module loaded\n"); + + return 0; +} + +static void __exit busfreq_cleanup(void) +{ +#ifdef CONFIG_ARM_IMX6Q_CPUFREQ + sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + + bus_freq_scaling_initialized = 0; +#endif + /* Unregister the device structure */ + platform_driver_unregister(&busfreq_driver); +} + +__setup("vpu352=", vpu352_setup); +module_init(busfreq_init); +module_exit(busfreq_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("BusFreq driver"); +MODULE_LICENSE("GPL"); diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/busfreq_lpddr2.c linux-4.1.13/arch/arm/mach-imx/busfreq_lpddr2.c --- linux-4.1.13.orig/arch/arm/mach-imx/busfreq_lpddr2.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/busfreq_lpddr2.c 2015-11-30 17:56:13.528141189 +0100 @@ -0,0 +1,183 @@ +/* + * 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" + +/* DDR settings */ +static void __iomem *mmdc_base; +static void __iomem *anatop_base; +static void __iomem *ccm_base; +static void __iomem *l2_base; +static struct device *busfreq_dev; +static void *ddr_freq_change_iram_base; +static int curr_ddr_rate; + +unsigned long reg_addrs[4]; + +void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode, + void *iram_addr) = NULL; + +extern unsigned int ddr_normal_rate; +extern int low_bus_freq_mode; +extern int ultra_low_bus_freq_mode; +extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode, + void *iram_addr); + + +#define LPDDR2_FREQ_CHANGE_SIZE 0x1000 + + +/* change the DDR frequency. */ +int update_lpddr2_freq(int ddr_rate) +{ + if (ddr_rate == curr_ddr_rate) + return 0; + + pr_debug("Bus freq set to %d start...\n", ddr_rate); + + /* + * Flush the TLB, to ensure no TLB maintenance occurs + * when DDR is in self-refresh. + */ + local_flush_tlb_all(); + /* Now change DDR frequency. */ + mx6_change_lpddr2_freq(ddr_rate, + (low_bus_freq_mode | ultra_low_bus_freq_mode), + reg_addrs); + + curr_ddr_rate = ddr_rate; + + pr_debug("Bus freq set to %d done...\n", ddr_rate); + + return 0; +} + +int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev) +{ + struct platform_device *ocram_dev; + unsigned int iram_paddr; + struct device_node *node; + struct gen_pool *iram_pool; + + busfreq_dev = &busfreq_pdev->dev; + node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-mmdc"); + if (!node) { + printk(KERN_ERR "failed to find imx6sl-mmdc device tree data!\n"); + return -EINVAL; + } + mmdc_base = of_iomap(node, 0); + WARN(!mmdc_base, "unable to map mmdc registers\n"); + + node = NULL; + node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-ccm"); + if (!node) { + printk(KERN_ERR "failed to find imx6sl-ccm device tree data!\n"); + return -EINVAL; + } + ccm_base = of_iomap(node, 0); + WARN(!ccm_base, "unable to map ccm registers\n"); + + node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache"); + if (!node) { + printk(KERN_ERR "failed to find imx6sl-pl310-cache device tree data!\n"); + return -EINVAL; + } + l2_base = of_iomap(node, 0); + WARN(!l2_base, "unable to map PL310 registers\n"); + + node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); + if (!node) { + printk(KERN_ERR "failed to find imx6sl-pl310-cache device tree data!\n"); + return -EINVAL; + } + anatop_base = of_iomap(node, 0); + WARN(!anatop_base, "unable to map anatop registers\n"); + + node = NULL; + node = of_find_compatible_node(NULL, NULL, "mmio-sram"); + if (!node) { + dev_err(busfreq_dev, "%s: failed to find ocram node\n", + __func__); + return -EINVAL; + } + + ocram_dev = of_find_device_by_node(node); + if (!ocram_dev) { + dev_err(busfreq_dev, "failed to find ocram device!\n"); + return -EINVAL; + } + + iram_pool = dev_get_gen_pool(&ocram_dev->dev); + if (!iram_pool) { + dev_err(busfreq_dev, "iram pool unavailable!\n"); + return -EINVAL; + } + + reg_addrs[0] = (unsigned long)anatop_base; + reg_addrs[1] = (unsigned long)ccm_base; + reg_addrs[2] = (unsigned long)mmdc_base; + reg_addrs[3] = (unsigned long)l2_base; + + ddr_freq_change_iram_base = (void *)gen_pool_alloc(iram_pool, + LPDDR2_FREQ_CHANGE_SIZE); + if (!ddr_freq_change_iram_base) { + dev_err(busfreq_dev, + "Cannot alloc iram for ddr freq change code!\n"); + return -ENOMEM; + } + + iram_paddr = gen_pool_virt_to_phys(iram_pool, + (unsigned long)ddr_freq_change_iram_base); + /* + * Need to remap the area here since we want + * the memory region to be executable. + */ + ddr_freq_change_iram_base = __arm_ioremap(iram_paddr, + LPDDR2_FREQ_CHANGE_SIZE, + MT_MEMORY_RWX_NONCACHED); + mx6_change_lpddr2_freq = (void *)fncpy(ddr_freq_change_iram_base, + &mx6_lpddr2_freq_change, LPDDR2_FREQ_CHANGE_SIZE); + + curr_ddr_rate = ddr_normal_rate; + + return 0; +} diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk.h linux-4.1.13/arch/arm/mach-imx/clk.h --- linux-4.1.13.orig/arch/arm/mach-imx/clk.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk.h 2015-11-30 17:56:13.528141189 +0100 @@ -55,6 +55,34 @@ 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 int 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); + return 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, void __iomem *reg, u8 idx); @@ -125,6 +153,15 @@ &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, + CLK_SET_RATE_NO_REPARENT, 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-4.1.13.orig/arch/arm/mach-imx/clk-imx1.c linux-4.1.13/arch/arm/mach-imx/clk-imx1.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx1.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx1.c 2015-11-30 17:56:13.528141189 +0100 @@ -75,7 +75,8 @@ int __init mx1_clocks_init(unsigned long fref) { - ccm = MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR); + ccm = ioremap(MX1_CCM_BASE_ADDR, SZ_4K); + BUG_ON(!ccm); _mx1_clocks_init(fref); @@ -98,7 +99,7 @@ clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-fb.0"); clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ahb", "imx1-fb.0"); - mxc_timer_init(MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), MX1_TIM1_INT); + mxc_timer_init(MX1_TIM1_BASE_ADDR, MX1_TIM1_INT); return 0; } diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-imx21.c linux-4.1.13/arch/arm/mach-imx/clk-imx21.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx21.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx21.c 2015-11-30 17:56:13.528141189 +0100 @@ -153,7 +153,7 @@ clk_register_clkdev(clk[IMX21_CLK_I2C_GATE], NULL, "imx21-i2c.0"); clk_register_clkdev(clk[IMX21_CLK_OWIRE_GATE], NULL, "mxc_w1.0"); - mxc_timer_init(MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), MX21_INT_GPT1); + mxc_timer_init(MX21_GPT1_BASE_ADDR, MX21_INT_GPT1); return 0; } diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-imx27.c linux-4.1.13/arch/arm/mach-imx/clk-imx27.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx27.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx27.c 2015-11-30 17:56:13.528141189 +0100 @@ -229,7 +229,7 @@ clk_register_clkdev(clk[IMX27_CLK_EMMA_AHB_GATE], "ahb", "m2m-emmaprp.0"); clk_register_clkdev(clk[IMX27_CLK_EMMA_IPG_GATE], "ipg", "m2m-emmaprp.0"); - mxc_timer_init(MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), MX27_INT_GPT1); + mxc_timer_init(MX27_GPT1_BASE_ADDR, MX27_INT_GPT1); return 0; } diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-imx31.c linux-4.1.13/arch/arm/mach-imx/clk-imx31.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx31.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx31.c 2015-11-30 17:56:13.528141189 +0100 @@ -50,9 +50,12 @@ int __init mx31_clocks_init(unsigned long fref) { - void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); + void __iomem *base; struct device_node *np; + base = ioremap(MX31_CCM_BASE_ADDR, SZ_4K); + BUG_ON(!base); + clk[dummy] = imx_clk_fixed("dummy", 0); clk[ckih] = imx_clk_fixed("ckih", fref); clk[ckil] = imx_clk_fixed("ckil", 32768); @@ -182,7 +185,7 @@ mx31_revision(); clk_disable_unprepare(clk[iim_gate]); - mxc_timer_init(MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), MX31_INT_GPT); + mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT); return 0; } diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-imx35.c linux-4.1.13/arch/arm/mach-imx/clk-imx35.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx35.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx35.c 2015-11-30 17:56:13.528141189 +0100 @@ -71,11 +71,14 @@ int __init mx35_clocks_init(void) { - void __iomem *base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR); + void __iomem *base; u32 pdr0, consumer_sel, hsp_sel; struct arm_ahb_div *aad; unsigned char *hsp_div; + base = ioremap(MX35_CCM_BASE_ADDR, SZ_4K); + BUG_ON(!base); + pdr0 = __raw_readl(base + MXC_CCM_PDR0); consumer_sel = (pdr0 >> 16) & 0xf; aad = &clk_consumer[consumer_sel]; @@ -279,7 +282,7 @@ #ifdef CONFIG_MXC_USE_EPIT epit_timer_init(MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1); #else - mxc_timer_init(MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT); + mxc_timer_init(MX35_GPT1_BASE_ADDR, MX35_INT_GPT); #endif return 0; diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-imx6q.c linux-4.1.13/arch/arm/mach-imx/clk-imx6q.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx6q.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx6q.c 2015-11-30 17:56:13.532140921 +0100 @@ -24,7 +24,6 @@ #include "clk.h" #include "common.h" #include "hardware.h" - 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", }; @@ -32,7 +31,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", }; @@ -40,6 +40,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", }; @@ -121,6 +123,18 @@ static unsigned int share_count_ssi3; static unsigned int share_count_mipi_core_cfg; +static void __iomem *ccm_base; + +static inline int clk_on_imx6q(void) +{ + return of_machine_is_compatible("fsl,imx6q"); +} + +static inline int clk_on_imx6dl(void) +{ + return of_machine_is_compatible("fsl,imx6dl"); +} + static void __init imx6q_clocks_init(struct device_node *ccm_node) { struct device_node *np; @@ -141,7 +155,7 @@ WARN_ON(!base); /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ - if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { + if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { post_div_table[1].div = 1; post_div_table[2].div = 1; video_div_table[1].div = 1; @@ -174,13 +188,13 @@ 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 */ - clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]); - clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]); - clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]); - clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]); - clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]); - clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]); - clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]); + 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_gate("pll1_sys", "pll1_bypass", base + 0x00, 13); clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); @@ -248,7 +262,7 @@ clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20); - if (cpu_is_imx6dl()) { + if (clk_on_imx6dl()) { clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1); clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1); } @@ -259,11 +273,9 @@ clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); np = ccm_node; - base = of_iomap(np, 0); + ccm_base = base = of_iomap(np, 0); WARN_ON(!base); - imx6q_pm_set_ccm_base(base); - /* 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("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); @@ -271,11 +283,12 @@ 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("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_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_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()) { + if (clk_on_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)); } @@ -286,6 +299,8 @@ 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); @@ -335,9 +350,9 @@ 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_PODF] = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0); + 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_PODF] = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0); + 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); @@ -378,11 +393,13 @@ 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()) + if (clk_on_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); @@ -392,7 +409,7 @@ 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()) + if (clk_on_imx6dl()) /* * The multiplexer and divider of imx6q clock gpu3d_shader get * redefined/reused as gpu2d_core_sel and gpu2d_core_podf on imx6dl. @@ -414,13 +431,13 @@ 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_podf", base + 0x74, 12); - clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14); clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10); + 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_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg); clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg); clk[IMX6QDL_CLK_MIPI_IPG] = imx_clk_gate2_shared("mipi_ipg", "ipg", base + 0x74, 16, &share_count_mipi_core_cfg); - if (cpu_is_imx6dl()) + if (clk_on_imx6dl()) /* * The multiplexer and divider of the imx6q clock gpu2d get * redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl. @@ -470,7 +487,7 @@ * The gpt_3m clock is not available on i.MX6Q TO1.0. Let's point it * to clock gpt_ipg_per to ease the gpt driver code. */ - if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) + if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) clk[IMX6QDL_CLK_GPT_3M] = clk[IMX6QDL_CLK_GPT_IPG_PER]; imx_check_clocks(clk, ARRAY_SIZE(clk)); @@ -479,56 +496,114 @@ clk_data.clk_num = ARRAY_SIZE(clk); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + clk_register_clkdev(clk[IMX6QDL_CLK_GPT_3M], "gpt_3m", "imx-gpt.0"); clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL); if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) || - cpu_is_imx6dl()) { - clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + clk_on_imx6dl()) { + imx_clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + imx_clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); } - clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_SEL], clk[IMX6QDL_CLK_IPU1_DI0_PRE]); - clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_SEL], clk[IMX6QDL_CLK_IPU1_DI1_PRE]); - clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_SEL], clk[IMX6QDL_CLK_IPU2_DI0_PRE]); - clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_SEL], clk[IMX6QDL_CLK_IPU2_DI1_PRE]); + 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]); + } /* * The gpmi needs 100MHz frequency in the EDO/Sync mode, * 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[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_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]); + /* 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. + */ +#if 1 + 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); + } +#endif if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { - clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]); - clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]); + imx_clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]); + imx_clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]); } /* * 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[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]); + ret = imx_clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]); if (!ret) - ret = clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]); + ret = imx_clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]); if (ret) pr_warn("failed to set up CLKO: %d\n", ret); /* Audio-related clocks configuration */ - clk_set_parent(clk[IMX6QDL_CLK_SPDIF_SEL], clk[IMX6QDL_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[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]); + imx_clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]); + + /* + * 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]]); + + 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); - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); + /* + * 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. + */ + if (vpu352) { + imx_clk_set_rate(clk[IMX6QDL_CLK_PLL2_PFD0_352M], 352000000); + pr_info("VPU 352M is enabled!\n"); + } } CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-imx6sl.c linux-4.1.13/arch/arm/mach-imx/clk-imx6sl.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx6sl.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx6sl.c 2015-11-30 17:56:13.532140921 +0100 @@ -288,9 +288,6 @@ 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)); @@ -443,8 +440,5 @@ clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL], clks[IMX6SL_CLK_PLL2_PFD2]); - - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); } CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init); diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-imx6sx.c linux-4.1.13/arch/arm/mach-imx/clk-imx6sx.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-imx6sx.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-imx6sx.c 2015-11-30 17:56:13.532140921 +0100 @@ -268,8 +268,6 @@ 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("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); @@ -560,8 +558,5 @@ clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]); clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]); - - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); } CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init); diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/clk-pllv3.c linux-4.1.13/arch/arm/mach-imx/clk-pllv3.c --- linux-4.1.13.orig/arch/arm/mach-imx/clk-pllv3.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/clk-pllv3.c 2015-11-30 17:56:13.532140921 +0100 @@ -23,6 +23,7 @@ #define PLL_DENOM_OFFSET 0x20 #define BM_PLL_POWER (0x1 << 12) +#define BM_PLL_BYPASS (0x1 << 16) #define BM_PLL_LOCK (0x1 << 31) /** @@ -237,9 +238,10 @@ struct clk_pllv3 *pll = to_clk_pllv3(hw); unsigned long min_rate = parent_rate * 27; unsigned long max_rate = parent_rate * 54; - u32 val, div; + u32 val, newval, div; u32 mfn, mfd = 1000000; s64 temp64; + int ret; if (rate < min_rate || rate > max_rate) return -EINVAL; @@ -251,13 +253,27 @@ mfn = temp64; val = readl_relaxed(pll->base); - val &= ~pll->div_mask; - val |= div; - writel_relaxed(val, pll->base); + + /* set the PLL into bypass mode */ + newval = val | BM_PLL_BYPASS; + writel_relaxed(newval, pll->base); + + /* configure the new frequency */ + newval &= ~pll->div_mask; + newval |= div; + writel_relaxed(newval, pll->base); writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); - return clk_pllv3_wait_lock(pll); + ret = clk_pllv3_wait_lock(pll); + if (ret == 0 && val & BM_PLL_POWER) { + /* only if it locked can we switch back to the PLL */ + newval &= ~BM_PLL_BYPASS; + newval |= val & BM_PLL_BYPASS; + writel_relaxed(newval, pll->base); + } + + return ret; } static const struct clk_ops clk_pllv3_av_ops = { diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/common.h linux-4.1.13/arch/arm/mach-imx/common.h --- linux-4.1.13.orig/arch/arm/mach-imx/common.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/common.h 2015-11-30 17:56:13.532140921 +0100 @@ -44,7 +44,7 @@ void imx31_soc_init(void); void imx35_soc_init(void); void epit_timer_init(void __iomem *base, int irq); -void mxc_timer_init(void __iomem *, int); +void mxc_timer_init(unsigned long, int); int mx1_clocks_init(unsigned long fref); int mx21_clocks_init(unsigned long lref, unsigned long fref); int mx27_clocks_init(unsigned long fref); @@ -56,6 +56,7 @@ void mxc_set_cpu_type(unsigned int type); void mxc_restart(enum reboot_mode, const char *); void mxc_arch_reset_init(void __iomem *); +void mxc_arch_reset_init_dt(void); int mx51_revision(void); int mx53_revision(void); void imx_set_aips(void __iomem *); @@ -86,6 +87,8 @@ MX3_SLEEP, }; +extern int vpu352; + void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode); void imx_print_silicon_rev(const char *cpu, int srev); @@ -102,6 +105,7 @@ static inline void imx_smp_prepare(void) {} #endif void imx_src_init(void); + void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); void imx_gpc_mask_all(void); @@ -111,10 +115,11 @@ void imx_anatop_init(void); void imx_anatop_pre_suspend(void); void imx_anatop_post_resume(void); -int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); void imx6q_set_int_mem_clk_lpm(bool enable); void imx6sl_set_wait_clk(bool enter); int imx_mmdc_get_ddr_type(void); +void imx6_enet_mac_init(const char *compatible); void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); @@ -127,11 +132,11 @@ static inline void imx6_suspend(void __iomem *ocram_vbase) {} #endif +void imx6_pm_ccm_init(const char *ccm_compat); 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 imx51_pm_init(void); diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/common-imx6.c linux-4.1.13/arch/arm/mach-imx/common-imx6.c --- linux-4.1.13.orig/arch/arm/mach-imx/common-imx6.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/common-imx6.c 2015-11-30 17:56:13.532140921 +0100 @@ -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-4.1.13.orig/arch/arm/mach-imx/cpuidle-imx6q.c linux-4.1.13/arch/arm/mach-imx/cpuidle-imx6q.c --- linux-4.1.13.orig/arch/arm/mach-imx/cpuidle-imx6q.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/cpuidle-imx6q.c 2015-11-30 17:56:13.532140921 +0100 @@ -27,9 +27,9 @@ */ if (!spin_trylock(&master_lock)) goto idle; - imx6q_set_lpm(WAIT_UNCLOCKED); + imx6_set_lpm(WAIT_UNCLOCKED); cpu_do_idle(); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); spin_unlock(&master_lock); goto done; } diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/cpuidle-imx6sl.c linux-4.1.13/arch/arm/mach-imx/cpuidle-imx6sl.c --- linux-4.1.13.orig/arch/arm/mach-imx/cpuidle-imx6sl.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/cpuidle-imx6sl.c 2015-11-30 17:56:13.532140921 +0100 @@ -16,7 +16,7 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - imx6q_set_lpm(WAIT_UNCLOCKED); + imx6_set_lpm(WAIT_UNCLOCKED); /* * Software workaround for ERR005311, see function * description for details. @@ -24,7 +24,7 @@ imx6sl_set_wait_clk(true); cpu_do_idle(); imx6sl_set_wait_clk(false); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); return index; } diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/cpuidle-imx6sx.c linux-4.1.13/arch/arm/mach-imx/cpuidle-imx6sx.c --- linux-4.1.13.orig/arch/arm/mach-imx/cpuidle-imx6sx.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/cpuidle-imx6sx.c 2015-11-30 17:56:13.532140921 +0100 @@ -25,7 +25,7 @@ static int imx6sx_enter_wait(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - imx6q_set_lpm(WAIT_UNCLOCKED); + imx6_set_lpm(WAIT_UNCLOCKED); switch (index) { case 1: @@ -50,7 +50,7 @@ break; } - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); return index; } diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/ddr3_freq_imx6.S linux-4.1.13/arch/arm/mach-imx/ddr3_freq_imx6.S --- linux-4.1.13.orig/arch/arm/mach-imx/ddr3_freq_imx6.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/ddr3_freq_imx6.S 2015-11-30 17:56:13.532140921 +0100 @@ -0,0 +1,893 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#define MMDC0_MDPDC 0x4 +#define MMDC0_MDCF0 0x0c +#define MMDC0_MDCF1 0x10 +#define MMDC0_MDMISC 0x18 +#define MMDC0_MDSCR 0x1c +#define MMDC0_MAPSR 0x404 +#define MMDC0_MADPCR0 0x410 +#define MMDC0_MPZQHWCTRL 0x800 +#define MMDC1_MPZQHWCTRL 0x4800 +#define MMDC0_MPODTCTRL 0x818 +#define MMDC1_MPODTCTRL 0x4818 +#define MMDC0_MPDGCTRL0 0x83c +#define MMDC1_MPDGCTRL0 0x483c +#define MMDC0_MPMUR0 0x8b8 +#define MMDC1_MPMUR0 0x48b8 + +#define CCM_CBCDR 0x14 +#define CCM_CBCMR 0x18 +#define CCM_CSCMR1 0x1c +#define CCM_CDHIPR 0x48 + +#define L2_CACHE_SYNC 0x730 + + .align 3 + + .macro switch_to_528MHz + + /* check if periph_clk_sel is already set */ + ldr r0, [r6, #CCM_CBCDR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq set_ahb_podf_before_switch + + /* change periph_clk to be sourced from pll3_clk. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(3 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 20) + str r0, [r6, #CCM_CBCDR] + + /* + * set the AHB dividers before the switch, + * don't change AXI clock divider, + * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0xd00 + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update528: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update528 + + /* now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch3: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch3 + + b switch_pre_periph_clk_528 + +set_ahb_podf_before_switch: + /* + * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0xd00 + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update528_1: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update528_1 + +switch_pre_periph_clk_528: + + /* now switch pre_periph_clk to PLL2_528MHz. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0xc << 16) + str r0, [r6, #CCM_CBCMR] + + /* now switch periph_clk back. */ + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch4: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch4 + + .endm + + .macro switch_to_400MHz + + /* check if periph_clk_sel is already set. */ + ldr r0, [r6, #CCM_CBCDR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq set_ahb_podf_before_switch1 + + /* change periph_clk to be sourced from pll3_clk. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(3 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 24) + str r0, [r6, #CCM_CBCDR] + + /* now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch5: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch5 + + b switch_pre_periph_clk_400 + +set_ahb_podf_before_switch1: + /* + * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(0x9 << 8) + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update400_1: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update400_1 + +switch_pre_periph_clk_400: + + /* now switch pre_periph_clk to PFD_400MHz. */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0xc << 16) + orr r0, r0, #(0x4 << 16) + str r0, [r6, #CCM_CBCMR] + + /* now switch periph_clk back. */ + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch6: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch6 + + /* + * change AHB divider so that we are at 400/3=133MHz. + * don't change AXI clock divider. + * set the MMDC_DIV=1, AXI_DIV=2, AHB_DIV=3, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(0x9 << 8) + orr r0, r0, #(1 << 16) + str r0, [r6, #CCM_CBCDR] + +wait_div_update400_2: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update400_2 + + .endm + + .macro switch_to_50MHz + + /* check if periph_clk_sel is already set. */ + ldr r0, [r6, #CCM_CBCDR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq switch_pre_periph_clk_50 + + /* + * set the periph_clk to be sourced from PLL2_PFD_200M + * change periph_clk to be sourced from pll3_clk. + * ensure PLL3 is the source and set the divider to 1. + */ + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0x3 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 24) + str r0, [r6, #CCM_CBCDR] + + /* now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch_50: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch_50 + +switch_pre_periph_clk_50: + + /* now switch pre_periph_clk to PFD_200MHz. */ + ldr r0, [r6, #CCM_CBCMR] + orr r0, r0, #(0xc << 16) + str r0, [r6, #CCM_CBCMR] + + /* + * set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8, + */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(0x18 << 16) + orr r0, r0, #(0x3 << 16) + + /* + * if changing AHB divider remember to change + * the IPGPER divider too below. + */ + orr r0, r0, #0x1d00 + str r0, [r6, #CCM_CBCDR] + +wait_div_update_50: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update_50 + + /* now switch periph_clk back. */ + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch2: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch2 + + .endm + + .macro switch_to_24MHz + /* + * change the freq now try setting DDR to 24MHz. + * source it from the periph_clk2 ensure the + * periph_clk2 is sourced from 24MHz and the + * divider is 1. + */ + + ldr r0, [r6, #CCM_CBCMR] + bic r0, r0, #(0x3 << 12) + orr r0, r0, #(1 << 12) + str r0, [r6, #CCM_CBCMR] + + ldr r0, [r6, #CCM_CBCDR] + bic r0, r0, #(0x38 << 24) + str r0, [r6, #CCM_CBCDR] + + /* now switch periph_clk to 24MHz. */ + ldr r0, [r6, #CCM_CBCDR] + orr r0, r0, #(1 << 25) + str r0, [r6, #CCM_CBCDR] + +periph_clk_switch1: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne periph_clk_switch1 + + /* change all the dividers to 1. */ + ldr r0, [r6, #CCM_CBCDR] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #(1 << 8) + str r0, [r6, #CCM_CBCDR] + + /* Wait for the divider to change. */ +wait_div_update: + ldr r0, [r6, #CCM_CDHIPR] + cmp r0, #0 + bne wait_div_update + + .endm + +/* + * mx6_ddr3_freq_change + * + * idle the processor (eg, wait for interrupt). + * make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx6_ddr3_freq_change) + + stmfd sp!, {r4-r12} + + /* + * r5 -> mmdc_base + * r6 -> ccm_base + * r7 -> iomux_base + * r12 -> l2_base + */ + mov r4, r0 + mov r8, r1 + mov r9, r2 + mov r11, r3 + + /* + * Get the addresses of the registers. + * They are last few entries in the + * ddr_settings parameter. + * The first entry contains the count, + * and each entry is 2 words. + */ + ldr r0, [r1] + add r0, r0, #1 + lsl r0, r0, #3 + add r1, r0, r1 + /* mmdc_base. */ + ldr r5, [r1] + add r1, #8 + /* ccm_base */ + ldr r6, [r1] + add r1, #8 + /*iomux_base */ + ldr r7, [r1] + add r1, #8 + /*l2_base */ + ldr r12, [r1] + +ddr_freq_change: + /* + * make sure no TLB miss will occur when + * the DDR is in self refresh. invalidate + * TLB single entry to ensure that the + * address is not already in the TLB. + */ + + adr r10, ddr_freq_change + + ldr r2, [r6] + ldr r2, [r5] + ldr r2, [r7] + ldr r2, [r8] + ldr r2, [r10] + ldr r2, [r11] + ldr r2, [r12] + +#ifdef CONFIG_CACHE_L2X0 + /* + * Make sure the L2 buffers are drained. + * Sync operation on L2 drains the buffers. + */ + mov r1, #0x0 + str r1, [r12, #L2_CACHE_SYNC] +#endif + + /* disable automatic power saving. */ + ldr r0, [r5, #MMDC0_MAPSR] + orr r0, r0, #0x01 + str r0, [r5, #MMDC0_MAPSR] + + /* disable MMDC power down timer. */ + ldr r0, [r5, #MMDC0_MDPDC] + bic r0, r0, #(0xff << 8) + str r0, [r5, #MMDC0_MDPDC] + + /* delay for a while */ + ldr r1, =4 +delay1: + ldr r2, =0 +cont1: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont1 + sub r1, r1, #1 + cmp r1, #0 + bgt delay1 + + /* set CON_REG */ + ldr r0, =0x8000 + str r0, [r5, #MMDC0_MDSCR] +poll_conreq_set_1: + ldr r0, [r5, #MMDC0_MDSCR] + and r0, r0, #(0x4 << 12) + cmp r0, #(0x4 << 12) + bne poll_conreq_set_1 + + ldr r0, =0x00008050 + str r0, [r5, #MMDC0_MDSCR] + ldr r0, =0x00008058 + 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, =0x00011680 + str r0, [r5, #MMDC0_MDMISC] + + /* enable dqs pull down in the IOMUX. */ + ldr r1, [r11] + add r11, r11, #8 + ldr r2, =0x3028 +update_iomux: + ldr r0, [r11, #0x0] + ldr r3, [r7, r0] + bic r3, r3, r2 + orr r3, r3, #(0x3 << 12) + orr r3, r3, #0x28 + str r3, [r7, r0] + add r11, r11, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_iomux + + /* ODT disabled. */ + ldr r0, =0x0 + ldr r2, =MMDC0_MPODTCTRL + str r0, [r5, r2] + ldr r2, =MMDC1_MPODTCTRL + str r0, [r5, r2] + + /* DQS gating disabled. */ + ldr r2, =MMDC0_MPDGCTRL0 + ldr r0, [r5, r2] + orr r0, r0, #(1 << 29) + str r0, [r5, r2] + + ldr r2, =MMDC1_MPDGCTRL0 + ldr r0, [r5, r2] + orr r0, r0, #(0x1 << 29) + str r0, [r5, r2] + + /* MMDC0_MAPSR adopt power down enable. */ + ldr r0, [r5, #MMDC0_MAPSR] + bic r0, r0, #0x01 + str r0, [r5, #MMDC0_MAPSR] + + /* frc_msr + mu bypass */ + ldr r0, =0x00000060 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + ldr r0, =0x00000460 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + ldr r0, =0x00000c60 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + +continue_dll_off_3: + /* clear SBS - unblock accesses to DDR. */ + ldr r0, [r5, #MMDC0_MADPCR0] + bic r0, r0, #(0x1 << 8) + str r0, [r5, #MMDC0_MADPCR0] + + mov r0, #0x0 + str r0, [r5, #MMDC0_MDSCR] +poll_conreq_clear_1: + ldr r0, [r5, #MMDC0_MDSCR] + and r0, r0, #(0x4 << 12) + cmp r0, #(0x4 << 12) + beq poll_conreq_clear_1 + + b done + +dll_on_mode: + /* assert DVFS - enter self refresh mode. */ + ldr r0, [r5, #MMDC0_MAPSR] + orr r0, r0, #(1 << 21) + str r0, [r5, #MMDC0_MAPSR] + + /* de-assert CON_REQ. */ + mov r0, #0x0 + str r0, [r5, #MMDC0_MDSCR] + + /* poll DVFS ack. */ +poll_dvfs_set_2: + ldr r0, [r5, #MMDC0_MAPSR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + bne poll_dvfs_set_2 + + ldr r1, =528000000 + cmp r4, r1 + beq switch_freq_528 + + switch_to_400MHz + + b continue_dll_on + +switch_freq_528: + switch_to_528MHz + +continue_dll_on: + + /* set SBS step-by-step mode. */ + ldr r0, [r5, #MMDC0_MADPCR0] + orr r0, r0, #( 1 << 8) + str r0, [r5, #MMDC0_MADPCR0] + + /* clear DVFS - exit self refresh mode. */ + ldr r0, [r5, #MMDC0_MAPSR] + bic r0, r0, #(1 << 21) + str r0, [r5, #MMDC0_MAPSR] + +poll_dvfs_clear_2: + ldr r0, [r5, #MMDC0_MAPSR] + and r0, r0, #(1 << 25) + cmp r0, #(1 << 25) + beq poll_dvfs_clear_2 + + /* if DLL is currently off, turn it back on. */ + cmp r9, #0 + beq update_calibration_only + + ldr r0, =0xa5390003 + str r0, [r5, #MMDC0_MPZQHWCTRL] + ldr r2, =MMDC1_MPZQHWCTRL + str r0, [r5, r2] + + /* enable DQS gating. */ + ldr r2, =MMDC0_MPDGCTRL0 + ldr r0, [r5, r2] + bic r0, r0, #(1 << 29) + str r0, [r5, r2] + + ldr r2, =MMDC1_MPDGCTRL0 + ldr r0, [r5, r2] + bic r0, r0, #(1 << 29) + str r0, [r5, r2] + + /* force measure. */ + ldr r0, =0x00000800 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + + /* delay for while. */ + ldr r1, =4 +delay5: + ldr r2, =0 +cont5: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont5 + sub r1, r1, #1 + cmp r1, #0 + bgt delay5 + + /* disable dqs pull down in the IOMUX. */ + ldr r1, [r11] + add r11, r11, #8 +update_iomux1: + ldr r0, [r11, #0x0] + ldr r3, [r11, #0x4] + str r3, [r7, r0] + add r11, r11, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_iomux1 + + /* config MMDC timings to 528MHz. */ + ldr r9, [r8] + add r8, r8, #8 + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + + /* update MISC register: WALAT, RALAT */ + ldr r0, =0x00001740 + str r0, [r5, #MMDC0_MDMISC] + + /* configure ddr devices to dll on, odt. */ + ldr r0, =0x00048031 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x00048039 + 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, =0x09408030 + str r0, [r5, #MMDC0_MDSCR] + + ldr r0, =0x09408038 + 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 r3, [r5, r2] + + /* delay for while. */ + ldr r1, =40 +delay15: + ldr r2, =0 +cont15: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont15 + sub r1, r1, #1 + cmp r1, #0 + bgt delay15 + + /* MMDC0_MAPSR adopt power down enable. */ + ldr r0, [r5, #MMDC0_MAPSR] + bic r0, r0, #0x01 + str r0, [r5, #MMDC0_MAPSR] + + /* enable MMDC power down timer. */ + ldr r0, [r5, #MMDC0_MDPDC] + orr r0, r0, #(0x55 << 8) + str r0, [r5, #MMDC0_MDPDC] + + b update_calibration + +update_calibration_only: + ldr r1, [r8] + sub r1, r1, #7 + add r8, r8, #64 + b update_calib + +update_calibration: + /* write the new calibration values. */ + mov r1, r9 + sub r1, r1, #7 + +update_calib: + ldr r0, [r8, #0x0] + ldr r3, [r8, #0x4] + str r3, [r5, r0] + add r8, r8, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_calib + + /* perform a force measurement. */ + ldr r0, =0x800 + str r0, [r5, #MMDC0_MPMUR0] + ldr r2, =MMDC1_MPMUR0 + str r0, [r5, r2] + + /* clear SBS - unblock DDR accesses. */ + ldr r0, [r5, #MMDC0_MADPCR0] + bic r0, r0, #(1 << 8) + str r0, [r5, #MMDC0_MADPCR0] + + mov r0, #0x0 + str r0, [r5, #MMDC0_MDSCR] +poll_conreq_clear_2: + ldr r0, [r5, #MMDC0_MDSCR] + and r0, r0, #(0x4 << 12) + cmp r0, #(0x4 << 12) + beq poll_conreq_clear_2 + +done: + /* restore registers */ + + ldmfd sp!, {r4-r12} + mov pc, lr + + .type mx6_do_ddr3_freq_change, #object +ENTRY(mx6_do_ddr_freq_change) + .word mx6_ddr3_freq_change + .size mx6_ddr3_freq_change, . - mx6_ddr3_freq_change diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/Kconfig linux-4.1.13/arch/arm/mach-imx/Kconfig --- linux-4.1.13.orig/arch/arm/mach-imx/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/Kconfig 2015-11-30 17:56:13.532140921 +0100 @@ -8,6 +8,7 @@ select PM_OPP if PM select SOC_BUS select SRAM + select ZONE_DMA help Support for Freescale MXC/iMX-based family of processors diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/lpddr2_freq_imx6.S linux-4.1.13/arch/arm/mach-imx/lpddr2_freq_imx6.S --- linux-4.1.13.orig/arch/arm/mach-imx/lpddr2_freq_imx6.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/lpddr2_freq_imx6.S 2015-11-30 17:56:13.532140921 +0100 @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + + .macro mx6sl_switch_to_24MHz + + /* + * Set MMDC clock to be sourced from PLL3. + * Ensure first periph2_clk2 is sourced from PLL3. + * Set the PERIPH2_CLK2_PODF to divide by 2. + */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x7 + orr r6, r6, #0x1 + str r6, [r2, #0x14] + + /* Select PLL3 to source MMDC. */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* Swtich periph2_clk_sel to run from PLL3. */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch1: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch1 + + /* + * Need to clock gate the 528 PFDs before + * powering down PLL2. + * Only the PLL2_PFD2_400M should be ON + * at this time, so only clock gate that one. + */ + ldr r6, [r3, #0x100] + orr r6, r6, #0x800000 + str r6, [r3, #0x100] + + /* + * Set PLL2 to bypass state. We should be here + * only if MMDC is not sourced from PLL2. + */ + ldr r6, [r3, #0x30] + orr r6, r6, #0x10000 + str r6, [r3, #0x30] + + ldr r6, [r3, #0x30] + orr r6, r6, #0x1000 + str r6, [r3, #0x30] + + /* Ensure pre_periph2_clk_mux is set to pll2 */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x600000 + str r6, [r2, #0x18] + + /* Set MMDC clock to be sourced from the bypassed PLL2. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch2: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch2 + + /* + * Now move MMDC back to periph2_clk2 source. + * after selecting PLL2 as the option. + * Select PLL2 as the source. + */ + ldr r6, [r2, #0x18] + orr r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* set periph2_clk2_podf to divide by 1. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x7 + str r6, [r2, #0x14] + + /* Now move periph2_clk to periph2_clk2 source */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch3: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch3 + + /* Now set the MMDC PODF back to 1.*/ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + str r6, [r2, #0x14] + +mmdc_podf0: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf0 + + .endm + + .macro ddr_switch_400MHz + + /* Set MMDC divider first, in case PLL3 is at 480MHz. */ + ldr r6, [r3, #0x10] + and r6, r6, #0x10000 + cmp r6, #0x10000 + beq pll3_in_bypass + + /* Set MMDC divder to divide by 2. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, #0x8 + str r6, [r2, #0x14] + +mmdc_podf: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf + +pll3_in_bypass: + /* + * Check if we are switching between + * 400Mhz <-> 100MHz.If so, we should + * try to source MMDC from PLL2_200M. + */ + cmp r1, #0 + beq not_low_bus_freq + + /* Ensure that MMDC is sourced from PLL2 mux first. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch4: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch4 + +not_low_bus_freq: + /* Now ensure periph2_clk2_sel mux is set to PLL3 */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* Now switch MMDC to PLL3. */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch5: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch5 + + /* + * Check if PLL2 is already unlocked. + * If so do nothing with PLL2. + */ + cmp r1, #0 + beq pll2_already_on + + /* Now power up PLL2 and unbypass it. */ + ldr r6, [r3, #0x30] + bic r6, r6, #0x1000 + str r6, [r3, #0x30] + + /* Make sure PLL2 has locked.*/ +wait_for_pll_lock: + ldr r6, [r3, #0x30] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock + + ldr r6, [r3, #0x30] + bic r6, r6, #0x10000 + str r6, [r3, #0x30] + + /* + * Need to enable the 528 PFDs after + * powering up PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC. Rest should have + * been managed by clock code. + */ + ldr r6, [r3, #0x100] + bic r6, r6, #0x800000 + str r6, [r3, #0x100] + +pll2_already_on: + /* + * Now switch MMDC clk back to pll2_mux option. + * Ensure pre_periph2_clk2 is set to pll2_pfd_400M. + * If switching to audio DDR freq, set the + * pre_periph2_clk2 to PLL2_PFD_200M + */ + ldr r6, =400000000 + cmp r6, r0 + bne use_pll2_pfd_200M + + ldr r6, [r2, #0x18] + bic r6, r6, #0x600000 + orr r6, r6, #0x200000 + str r6, [r2, #0x18] + ldr r6, =400000000 + b cont2 + +use_pll2_pfd_200M: + ldr r6, [r2, #0x18] + orr r6, r6, #0x600000 + str r6, [r2, #0x18] + ldr r6, =200000000 + +cont2: + ldr r4, [r2, #0x14] + bic r4, r4, #0x4000000 + str r4, [r2, #0x14] + +periph2_clk_switch6: + ldr r4, [r2, #0x48] + cmp r4, #0 + bne periph2_clk_switch6 + +change_divider_only: + /* + * Calculate the MMDC divider + * based on the requested freq. + */ + ldr r4, =0 +Loop2: + sub r6, r6, r0 + cmp r6, r0 + blt Div_Found + add r4, r4, #1 + bgt Loop2 + + /* Shift divider into correct offset. */ + lsl r4, r4, #3 +Div_Found: + /* Set the MMDC PODF. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, r4 + str r6, [r2, #0x14] + +mmdc_podf1: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf1 + + .endm + + .macro mmdc_clk_lower_100MHz + + /* + * Prior to reducing the DDR frequency (at 528/400 MHz), + * read the Measure unit count bits (MU_UNIT_DEL_NUM) + */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + /* Original MU unit count */ + mov r6, r6, LSR #16 + ldr r4, =0x3FF + and r6, r6, r4 + /* Original MU unit count * 2 */ + mov r7, r6, LSL #1 + /* + * Bypass the automatic measure unit when below 100 MHz + * by setting the Measure unit bypass enable bit (MU_BYP_EN) + */ + ldr r6, [r8, r5] + orr r6, r6, #0x400 + str r6, [r8, r5] + /* + * Double the measure count value read in step 1 and program it in the + * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit + * Register for the reduced frequency operation below 100 MHz + */ + ldr r6, [r8, r5] + ldr r4, =0x3FF + bic r6, r6, r4 + orr r6, r6, r7 + str r6, [r8, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r8, r5] + orr r6, r6, #0x800 + str r6, [r8, r5] + /* Wait for FRC_MSR to clear. */ +force_measure: + ldr r6, [r8, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure + + .endm + + .macro mmdc_clk_above_100MHz + + /* Make sure that the PHY measurement unit is NOT in bypass mode */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + bic r6, r6, #0x400 + str r6, [r8, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r8, r5] + orr r6, r6, #0x800 + str r6, [r8, r5] + /* Wait for FRC_MSR to clear. */ +force_measure1: + ldr r6, [r8, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure1 + .endm + +/* + * mx6_lpddr2_freq_change + * + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + * r0 : DDR freq. + * r1: low_bus_freq_mode flag + * r2: Pointer to array containing addresses of registers. + */ + .align 3 +ENTRY(mx6_lpddr2_freq_change) + + push {r4-r10} + + mov r4, r2 + ldr r3, [r4] @ANATOP_BASE_ADDR + ldr r2, [r4, #0x4] @CCM_BASE_ADDR + ldr r8, [r4, #0x8] @MMDC_P0_BASE_ADDR + ldr r7, [r4, #0xC] @L2_BASE_ADDR + +lpddr2_freq_change: + adr r9, lpddr2_freq_change + + /* Prime all TLB entries. */ + ldr r6, [r9] + ldr r6, [r8] + ldr r6, [r3] + ldr r6, [r2] + + /* Drain all the L1 buffers. */ + dsb + +#ifdef CONFIG_CACHE_L2X0 + /* + * Need to make sure the buffers in L2 are drained. + * Performing a sync operation does this. + */ + mov r6, #0x0 + str r6, [r7, #0x730] +#endif + + /* + * The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb + + /* Disable Automatic power savings. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x01 + str r6, [r8, #0x404] + + /* MMDC0_MDPDC disable power down timer */ + ldr r6, [r8, #0x4] + bic r6, r6, #0xff00 + str r6, [r8, #0x4] + + /* Delay for a while */ + ldr r10, =10 +delay1: + ldr r7, =0 +cont1: + ldr r6, [r8, r7] + add r7, r7, #4 + cmp r7, #16 + bne cont1 + sub r10, r10, #1 + cmp r10, #0 + bgt delay1 + + /* Make the DDR explicitly enter self-refresh. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_set_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_1 + + /* set SBS step-by-step mode */ + ldr r6, [r8, #0x410] + orr r6, r6, #0x100 + str r6, [r8, #0x410] + + ldr r10, =100000000 + cmp r0, r10 + bgt set_ddr_mu_above_100 + mmdc_clk_lower_100MHz + +set_ddr_mu_above_100: + ldr r10, =24000000 + cmp r0, r10 + beq set_to_24MHz + + ddr_switch_400MHz + + ldr r10,=100000000 + cmp r0, r10 + blt done + mmdc_clk_above_100MHz + + b done + +set_to_24MHz: + mx6sl_switch_to_24MHz + +done: + /* clear DVFS - exit from self refresh mode */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_clear_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x01 + str r6, [r8, #0x404] + + ldr r10, =24000000 + cmp r0, r10 + beq skip_power_down + + /* Enable MMDC power down timer. */ + ldr r6, [r8, #0x4] + orr r6, r6, #0x5500 + str r6, [r8, #0x4] + +skip_power_down: + /* clear SBS - unblock DDR accesses */ + ldr r6, [r8, #0x410] + bic r6, r6, #0x100 + str r6, [r8, #0x410] + + pop {r4-r10} + + /* Restore registers */ + mov pc, lr + + .type mx6_lpddr2_do_iram, #object +ENTRY(mx6_lpddr2_do_iram) + .word mx6_lpddr2_freq_change + .size mx6_lpddr2_freq_change, . - mx6_lpddr2_freq_change diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/mach-imx6q.c linux-4.1.13/arch/arm/mach-imx/mach-imx6q.c --- linux-4.1.13.orig/arch/arm/mach-imx/mach-imx6q.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/mach-imx6q.c 2015-11-30 17:56:13.532140921 +0100 @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -39,6 +42,45 @@ #include "cpuidle.h" #include "hardware.h" +static struct fec_platform_data fec_pdata; + +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; +} + /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ static int ksz9021rn_phy_fixup(struct phy_device *phydev) { @@ -112,6 +154,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 +187,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 +202,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 = 0x1517; + phy_write(dev, 0xe, val); + return 0; } @@ -262,9 +328,24 @@ } } +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-fec", 0x02188000, NULL, &fec_pdata), + { /* sentinel */ } +}; + static void __init imx6q_init_machine(void) { struct device *parent; + void __iomem *p; imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", imx_get_soc_revision()); @@ -273,14 +354,19 @@ if (parent == NULL) pr_warn("failed to initialize soc device\n"); - imx6q_enet_phy_init(); - of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); + imx6q_enet_init(); imx_anatop_init(); cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); imx6q_1588_init(); imx6q_axi_init(); + + p = ioremap(0x21b0000, SZ_4K); + if (p) { + writel(0x7f, p + 0x40); + iounmap(p); + } } #define OCOTP_CFG3 0x440 @@ -330,6 +416,12 @@ if (dev_pm_opp_disable(cpu_dev, 852000000)) pr_warn("failed to disable 852 MHz OPP\n"); } + if (vpu352) { + if (dev_pm_opp_disable(cpu_dev, 396000000)) + pr_warn("VPU352: failed to disable 396MHz OPP\n"); + pr_info("VPU352: remove 396MHz OPP for VPU running at 352MHz!\n"); + } + iounmap(base); put_node: of_node_put(np); @@ -393,6 +485,7 @@ imx_init_l2cache(); imx_src_init(); irqchip_init(); + imx6_pm_ccm_init("fsl,imx6q-ccm"); } static const char * const imx6q_dt_compat[] __initconst = { diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/mach-imx6sl.c linux-4.1.13/arch/arm/mach-imx/mach-imx6sl.c --- linux-4.1.13.orig/arch/arm/mach-imx/mach-imx6sl.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/mach-imx6sl.c 2015-11-30 17:56:13.532140921 +0100 @@ -48,6 +48,8 @@ { struct device *parent; + mxc_arch_reset_init_dt(); + parent = imx_soc_device_init(); if (parent == NULL) pr_warn("failed to initialize soc device\n"); @@ -66,6 +68,7 @@ imx_init_l2cache(); imx_src_init(); irqchip_init(); + imx6_pm_ccm_init("fsl,imx6sl-ccm"); } static const char * const imx6sl_dt_compat[] __initconst = { @@ -78,4 +81,5 @@ .init_machine = imx6sl_init_machine, .init_late = imx6sl_init_late, .dt_compat = imx6sl_dt_compat, + .restart = mxc_restart, MACHINE_END diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/mach-imx6sx.c linux-4.1.13/arch/arm/mach-imx/mach-imx6sx.c --- linux-4.1.13.orig/arch/arm/mach-imx/mach-imx6sx.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/mach-imx6sx.c 2015-11-30 17:56:13.532140921 +0100 @@ -12,12 +12,135 @@ #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_stby_gpio; +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, 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 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; + bool canfd_en = false; + + 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 = imx6sx_arm2_flexcan0_switch; + flexcan_pdata[1].transceiver_switch = imx6sx_arm2_flexcan1_switch; + } + + /* + * 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; @@ -62,8 +185,18 @@ { 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 void __init imx6sx_init_machine(void) { struct device *parent; @@ -86,6 +219,7 @@ imx_init_l2cache(); imx_src_init(); irqchip_init(); + imx6_pm_ccm_init("fsl,imx6sx-ccm"); } static void __init imx6sx_init_late(void) diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/Makefile linux-4.1.13/arch/arm/mach-imx/Makefile --- linux-4.1.13.orig/arch/arm/mach-imx/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/Makefile 2015-11-30 17:56:13.532140921 +0100 @@ -28,6 +28,14 @@ obj-$(CONFIG_MXC_USE_EPIT) += epit.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o +obj-y += busfreq-imx6.o +ifdef CONFIG_ARM_IMX6Q_CPUFREQ +obj-$(CONFIG_SOC_IMX6Q) += ddr3_freq_imx6.o busfreq_ddr3.o +obj-$(CONFIG_SOC_IMX6SL) += lpddr2_freq_imx6.o busfreq_lpddr2.o +AFLAGS_ddr3_freq_imx6.o :=-Wa,-march=armv7-a +AFLAGS_lpddr2_freq_imx6.o :=-Wa,-march=armv7-a +endif + ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o @@ -87,9 +95,9 @@ obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o endif -obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o -obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o -obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.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 ifeq ($(CONFIG_SUSPEND),y) AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/pm-imx6.c linux-4.1.13/arch/arm/mach-imx/pm-imx6.c --- linux-4.1.13.orig/arch/arm/mach-imx/pm-imx6.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/pm-imx6.c 2015-11-30 17:56:13.532140921 +0100 @@ -89,6 +89,7 @@ struct imx6_pm_socdata { u32 ddr_type; + const char *ccm_compat; const char *mmdc_compat; const char *src_compat; const char *iomuxc_compat; @@ -138,6 +139,7 @@ }; static const struct imx6_pm_socdata imx6q_pm_data __initconst = { + .ccm_compat = "fsl,imx6q-ccm", .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6q-iomuxc", @@ -147,6 +149,7 @@ }; static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { + .ccm_compat = "fsl,imx6q-ccm", .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6dl-iomuxc", @@ -156,6 +159,7 @@ }; static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { + .ccm_compat = "fsl,imx6sl-ccm", .mmdc_compat = "fsl,imx6sl-mmdc", .src_compat = "fsl,imx6sl-src", .iomuxc_compat = "fsl,imx6sl-iomuxc", @@ -165,6 +169,7 @@ }; static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { + .ccm_compat = "fsl,imx6sx-ccm", .mmdc_compat = "fsl,imx6sx-mmdc", .src_compat = "fsl,imx6sx-src", .iomuxc_compat = "fsl,imx6sx-iomuxc", @@ -255,7 +260,7 @@ writel_relaxed(val, ccm_base + CCR); } -int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) { u32 val = readl_relaxed(ccm_base + CLPCR); @@ -340,7 +345,7 @@ { switch (state) { case PM_SUSPEND_STANDBY: - imx6q_set_lpm(STOP_POWER_ON); + imx6_set_lpm(STOP_POWER_ON); imx6q_set_int_mem_clk_lpm(true); imx_gpc_pre_suspend(false); if (cpu_is_imx6sl()) @@ -350,10 +355,10 @@ if (cpu_is_imx6sl()) imx6sl_set_wait_clk(false); imx_gpc_post_resume(); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); break; case PM_SUSPEND_MEM: - imx6q_set_lpm(STOP_POWER_OFF); + imx6_set_lpm(STOP_POWER_OFF); imx6q_set_int_mem_clk_lpm(false); imx6q_enable_wb(true); /* @@ -373,7 +378,7 @@ imx6_enable_rbc(false); imx6q_enable_wb(false); imx6q_set_int_mem_clk_lpm(true); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); break; default: return -EINVAL; @@ -392,11 +397,6 @@ .valid = imx6q_pm_valid, }; -void __init imx6q_pm_set_ccm_base(void __iomem *base) -{ - ccm_base = base; -} - static int __init imx6_pm_get_base(struct imx6_pm_base *base, const char *compat) { @@ -482,8 +482,7 @@ /* * ccm physical address is not used by asm code currently, - * so get ccm virtual address directly, as we already have - * it from ccm driver. + * so get ccm virtual address directly. */ pm_info->ccm_base.vbase = ccm_base; @@ -554,11 +553,16 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata *socdata) { + struct device_node *np; struct regmap *gpr; int ret; + np = of_find_compatible_node(NULL, NULL, socdata->ccm_compat); + ccm_base = of_iomap(np, 0); WARN_ON(!ccm_base); + imx6_set_lpm(WAIT_CLOCKED); + if (IS_ENABLED(CONFIG_SUSPEND)) { ret = imx6q_suspend_init(socdata); if (ret) @@ -568,7 +572,7 @@ /* * This is for SW workaround step #1 of ERR007265, see comments - * in imx6q_set_lpm for details of this errata. + * in imx6_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. @@ -579,6 +583,24 @@ IMX6Q_GPR1_GINT); } +void __init imx6_pm_ccm_init(const char *ccm_compat) +{ + struct device_node *np; + u32 val; + + np = of_find_compatible_node(NULL, NULL, ccm_compat); + ccm_base = of_iomap(np, 0); + BUG_ON(!ccm_base); + + /* + * Initialize CCM_CLPCR_LPM into RUN mode to avoid ARM core + * clock being shut down unexpectedly by WAIT mode. + */ + val = readl_relaxed(ccm_base + CLPCR); + val &= ~BM_CLPCR_LPM; + writel_relaxed(val, ccm_base + CLPCR); +} + void __init imx6q_pm_init(void) { imx6_pm_common_init(&imx6q_pm_data); diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/src.c linux-4.1.13/arch/arm/mach-imx/src.c --- linux-4.1.13.orig/arch/arm/mach-imx/src.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/src.c 2015-11-30 17:56:13.532140921 +0100 @@ -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-4.1.13.orig/arch/arm/mach-imx/system.c linux-4.1.13/arch/arm/mach-imx/system.c --- linux-4.1.13.orig/arch/arm/mach-imx/system.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/system.c 2015-11-30 17:56:13.532140921 +0100 @@ -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(). @@ -50,6 +51,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); @@ -89,6 +101,41 @@ clk_prepare(wdog_clk); } +void __init mxc_arch_reset_init_dt(void) +{ + struct device_node *np = NULL; + + if (cpu_is_imx6q() || cpu_is_imx6dl()) + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); + else if (cpu_is_imx6sl()) + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpc"); + + if (np) + of_property_read_u32(np, "fsl,wdog-reset", &wdog_source); + pr_info("Use WDOG%d as reset source\n", wdog_source); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx21-wdt"); + wdog_base = of_iomap(np, 0); + WARN_ON(!wdog_base); + + /* Some i.MX6 boards use WDOG2 to reset board in ldo-bypass mode */ + if (wdog_source == 2 && (cpu_is_imx6q() || cpu_is_imx6dl() || + cpu_is_imx6sl())) { + np = of_find_compatible_node(np, NULL, "fsl,imx21-wdt"); + wdog_base = of_iomap(np, 0); + WARN_ON(!wdog_base); + } + + wdog_clk = of_clk_get(np, 0); + if (IS_ERR(wdog_clk)) { + pr_warn("%s: failed to get wdog clock\n", __func__); + wdog_clk = NULL; + return; + } + + clk_prepare(wdog_clk); +} + #ifdef CONFIG_CACHE_L2X0 void __init imx_init_l2cache(void) { diff -Nur linux-4.1.13.orig/arch/arm/mach-imx/time.c linux-4.1.13/arch/arm/mach-imx/time.c --- linux-4.1.13.orig/arch/arm/mach-imx/time.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mach-imx/time.c 2015-11-30 17:56:13.532140921 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -38,9 +39,11 @@ #include "hardware.h" /* - * There are 2 versions of the timer hardware on Freescale MXC hardware. - * Version 1: MX1/MXL, MX21, MX27. - * Version 2: MX25, MX31, MX35, MX37, MX51 + * There are 4 versions of the timer hardware on Freescale MXC hardware. + * - MX1/MXL + * - MX21, MX27. + * - MX25, MX31, MX35, MX37, MX51, MX6Q(rev1.0) + * - MX6DL, MX6SX, MX6Q(rev1.1+) */ /* defines common for all i.MX */ @@ -82,6 +85,13 @@ static struct clock_event_device clockevent_mxc; static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED; +struct imx_timer { + void __iomem *base; + int irq; + struct clk *clk_per; + struct clk *clk_ipg; +}; + static void __iomem *timer_base; static inline void gpt_irq_disable(void) @@ -89,19 +99,19 @@ unsigned int tmp; if (timer_is_v2()) - __raw_writel(0, timer_base + V2_IR); + writel_relaxed(0, timer_base + V2_IR); else { - tmp = __raw_readl(timer_base + MXC_TCTL); - __raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL); + tmp = readl_relaxed(timer_base + MXC_TCTL); + writel_relaxed(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL); } } static inline void gpt_irq_enable(void) { if (timer_is_v2()) - __raw_writel(1<<0, timer_base + V2_IR); + writel_relaxed(1<<0, timer_base + V2_IR); else { - __raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN, + writel_relaxed(readl_relaxed(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL); } } @@ -110,32 +120,32 @@ { if (timer_is_v1()) { if (cpu_is_mx1()) - __raw_writel(0, timer_base + MX1_2_TSTAT); + writel_relaxed(0, timer_base + MX1_2_TSTAT); else - __raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, + writel_relaxed(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, timer_base + MX1_2_TSTAT); } else if (timer_is_v2()) - __raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT); + writel_relaxed(V2_TSTAT_OF1, timer_base + V2_TSTAT); } static void __iomem *sched_clock_reg; static u64 notrace mxc_read_sched_clock(void) { - return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0; + return sched_clock_reg ? readl_relaxed(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); + return readl_relaxed(sched_clock_reg); } -static int __init mxc_clocksource_init(struct clk *timer_clk) +static int __init mxc_clocksource_init(struct imx_timer *imxtm) { - unsigned int c = clk_get_rate(timer_clk); - void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN); + unsigned int c = clk_get_rate(imxtm->clk_per); + void __iomem *reg = imxtm->base + (timer_is_v2() ? V2_TCN : MX1_2_TCN); imx_delay_timer.read_current_timer = &imx_read_current_timer; imx_delay_timer.freq = c; @@ -155,11 +165,11 @@ { unsigned long tcmp; - tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt; + tcmp = readl_relaxed(timer_base + MX1_2_TCN) + evt; - __raw_writel(tcmp, timer_base + MX1_2_TCMP); + writel_relaxed(tcmp, timer_base + MX1_2_TCMP); - return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ? + return (int)(tcmp - readl_relaxed(timer_base + MX1_2_TCN)) < 0 ? -ETIME : 0; } @@ -168,12 +178,12 @@ { unsigned long tcmp; - tcmp = __raw_readl(timer_base + V2_TCN) + evt; + tcmp = readl_relaxed(timer_base + V2_TCN) + evt; - __raw_writel(tcmp, timer_base + V2_TCMP); + writel_relaxed(tcmp, timer_base + V2_TCMP); return evt < 0x7fffffff && - (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ? + (int)(tcmp - readl_relaxed(timer_base + V2_TCN)) < 0 ? -ETIME : 0; } @@ -204,10 +214,10 @@ if (mode != clockevent_mode) { /* Set event time into far-far future */ if (timer_is_v2()) - __raw_writel(__raw_readl(timer_base + V2_TCN) - 3, + writel_relaxed(readl_relaxed(timer_base + V2_TCN) - 3, timer_base + V2_TCMP); else - __raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3, + writel_relaxed(readl_relaxed(timer_base + MX1_2_TCN) - 3, timer_base + MX1_2_TCMP); /* Clear pending interrupt */ @@ -257,9 +267,9 @@ uint32_t tstat; if (timer_is_v2()) - tstat = __raw_readl(timer_base + V2_TSTAT); + tstat = readl_relaxed(timer_base + V2_TSTAT); else - tstat = __raw_readl(timer_base + MX1_2_TSTAT); + tstat = readl_relaxed(timer_base + MX1_2_TSTAT); gpt_irq_acknowledge(); @@ -282,49 +292,51 @@ .rating = 200, }; -static int __init mxc_clockevent_init(struct clk *timer_clk) +static int __init mxc_clockevent_init(struct imx_timer *imxtm) { if (timer_is_v2()) clockevent_mxc.set_next_event = v2_set_next_event; clockevent_mxc.cpumask = cpumask_of(0); clockevents_config_and_register(&clockevent_mxc, - clk_get_rate(timer_clk), + clk_get_rate(imxtm->clk_per), 0xff, 0xfffffffe); return 0; } -static void __init _mxc_timer_init(int irq, - struct clk *clk_per, struct clk *clk_ipg) +static void __init _mxc_timer_init(struct imx_timer *imxtm) { uint32_t tctl_val; - if (IS_ERR(clk_per)) { + /* Temporary */ + timer_base = imxtm->base; + + if (IS_ERR(imxtm->clk_per)) { pr_err("i.MX timer: unable to get clk\n"); return; } - if (!IS_ERR(clk_ipg)) - clk_prepare_enable(clk_ipg); + if (!IS_ERR(imxtm->clk_ipg)) + clk_prepare_enable(imxtm->clk_ipg); - clk_prepare_enable(clk_per); + clk_prepare_enable(imxtm->clk_per); /* * Initialise to a known state (all timers off, and timing reset) */ - __raw_writel(0, timer_base + MXC_TCTL); - __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */ + writel_relaxed(0, imxtm->base + MXC_TCTL); + writel_relaxed(0, imxtm->base + MXC_TPRER); /* see datasheet note */ if (timer_is_v2()) { tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN; - if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) { + if (clk_get_rate(imxtm->clk_per) == V2_TIMER_RATE_OSC_DIV8) { tctl_val |= V2_TCTL_CLK_OSC_DIV8; if (cpu_is_imx6dl() || cpu_is_imx6sx()) { /* 24 / 8 = 3 MHz */ - __raw_writel(7 << V2_TPRER_PRE24M, - timer_base + MXC_TPRER); + writel_relaxed(7 << V2_TPRER_PRE24M, + imxtm->base + MXC_TPRER); tctl_val |= V2_TCTL_24MEN; } } else { @@ -334,46 +346,58 @@ tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN; } - __raw_writel(tctl_val, timer_base + MXC_TCTL); + writel_relaxed(tctl_val, imxtm->base + MXC_TCTL); /* init and register the timer to the framework */ - mxc_clocksource_init(clk_per); - mxc_clockevent_init(clk_per); + mxc_clocksource_init(imxtm); + mxc_clockevent_init(imxtm); /* Make irqs happen */ - setup_irq(irq, &mxc_timer_irq); + setup_irq(imxtm->irq, &mxc_timer_irq); } -void __init mxc_timer_init(void __iomem *base, int irq) +void __init mxc_timer_init(unsigned long pbase, int irq) { - struct clk *clk_per = clk_get_sys("imx-gpt.0", "per"); - struct clk *clk_ipg = clk_get_sys("imx-gpt.0", "ipg"); + struct imx_timer *imxtm; + + imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL); + BUG_ON(!imxtm); - timer_base = base; + imxtm->clk_per = clk_get_sys("imx-gpt.0", "per"); + imxtm->clk_ipg = clk_get_sys("imx-gpt.0", "ipg"); - _mxc_timer_init(irq, clk_per, clk_ipg); + imxtm->base = ioremap(pbase, SZ_4K); + BUG_ON(!imxtm->base); + + _mxc_timer_init(imxtm); } static void __init mxc_timer_init_dt(struct device_node *np) { - struct clk *clk_per, *clk_ipg; - int irq; + struct imx_timer *imxtm; + static int initialized; - if (timer_base) + /* Support one instance only */ + if (initialized) return; - timer_base = of_iomap(np, 0); - WARN_ON(!timer_base); - irq = irq_of_parse_and_map(np, 0); + imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL); + BUG_ON(!imxtm); - clk_ipg = of_clk_get_by_name(np, "ipg"); + imxtm->base = of_iomap(np, 0); + WARN_ON(!imxtm->base); + imxtm->irq = irq_of_parse_and_map(np, 0); + + imxtm->clk_ipg = of_clk_get_by_name(np, "ipg"); /* Try osc_per first, and fall back to per otherwise */ - clk_per = of_clk_get_by_name(np, "osc_per"); - if (IS_ERR(clk_per)) - clk_per = of_clk_get_by_name(np, "per"); + imxtm->clk_per = of_clk_get_by_name(np, "osc_per"); + if (IS_ERR(imxtm->clk_per)) + imxtm->clk_per = of_clk_get_by_name(np, "per"); + + _mxc_timer_init(imxtm); - _mxc_timer_init(irq, clk_per, clk_ipg); + initialized = 1; } CLOCKSOURCE_OF_DECLARE(mx1_timer, "fsl,imx1-gpt", mxc_timer_init_dt); CLOCKSOURCE_OF_DECLARE(mx25_timer, "fsl,imx25-gpt", mxc_timer_init_dt); diff -Nur linux-4.1.13.orig/arch/arm/mm/cache-v7.S linux-4.1.13/arch/arm/mm/cache-v7.S --- linux-4.1.13.orig/arch/arm/mm/cache-v7.S 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/arch/arm/mm/cache-v7.S 2015-11-30 17:56:13.532140921 +0100 @@ -446,3 +446,5 @@ @ define struct cpu_cache_fns (see and proc-macros.S) define_cache_functions v7 + + .long v7_dma_flush_range diff -Nur linux-4.1.13.orig/block/bfq-cgroup.c linux-4.1.13/block/bfq-cgroup.c --- linux-4.1.13.orig/block/bfq-cgroup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/block/bfq-cgroup.c 2015-11-30 17:56:13.536140654 +0100 @@ -0,0 +1,936 @@ +/* + * 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_cgrp_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, 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, 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_cgrp_subsys = { + .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, + .legacy_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-4.1.13.orig/block/bfq.h linux-4.1.13/block/bfq.h --- linux-4.1.13.orig/block/bfq.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/block/bfq.h 2015-11-30 17:56:13.536140654 +0100 @@ -0,0 +1,811 @@ +/* + * BFQ-v7r7 for 4.0.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_quantum: max number of requests dispatched per dispatch round. + * @bfq_fifo_expire: timeout for async/sync requests; when it expires + * requests are served in fifo order. + * @bfq_back_penalty: weight of backward seeks wrt forward ones. + * @bfq_back_max: maximum allowed backward seek. + * @bfq_slice_idle: maximum idling time. + * @bfq_user_max_budget: user-configured max budget value + * (0 for auto-tuning). + * @bfq_max_budget_async_rq: maximum budget (in nr of requests) allotted to + * async queues. + * @bfq_timeout: timeout for bfq_queues to consume their budget; used to + * to prevent seeky queues to impose long latencies to well + * behaved ones (this also implies that seeky queues cannot + * receive guarantees in the service domain; after a timeout + * they are charged for the whole allocated budget, to try + * to preserve a behavior reasonably fair among them, but + * without service-domain guarantees). + * @bfq_coop_thresh: number of queue merges after which a @bfq_queue is + * no more granted any weight-raising. + * @bfq_failed_cooperations: number of consecutive failed cooperation + * chances after which weight-raising is restored + * to a queue subject to more than bfq_coop_thresh + * queue merges. + * @bfq_requests_within_timer: number of consecutive requests that must be + * issued within the idle time slice to set + * again idling to a queue which was marked as + * non-I/O-bound (see the definition of the + * IO_bound flag for further details). + * @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_quantum; + unsigned int bfq_fifo_expire[2]; + unsigned int bfq_back_penalty; + unsigned int bfq_back_max; + unsigned int bfq_slice_idle; + u64 bfq_class_idle_last_service; + + unsigned int bfq_user_max_budget; + unsigned int bfq_max_budget_async_rq; + unsigned int bfq_timeout[2]; + + unsigned int bfq_coop_thresh; + unsigned int bfq_failed_cooperations; + unsigned int bfq_requests_within_timer; + + 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_prio_changed, /* task priority has changed */ + BFQ_BFQQ_FLAG_sync, /* synchronous queue */ + BFQ_BFQQ_FLAG_budget_new, /* no completion with this budget */ + BFQ_BFQQ_FLAG_IO_bound, /* + * bfqq has timed-out at least once + * having consumed at most 2/10 of + * its budget + */ + BFQ_BFQQ_FLAG_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(prio_changed); +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_changed_ioprio(struct bfq_io_cq *bic); +static void bfq_put_queue(struct bfq_queue *bfqq); +static void bfq_dispatch_insert(struct request_queue *q, struct request *rq); +static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd, + struct bfq_group *bfqg, int is_sync, + struct bfq_io_cq *bic, gfp_t gfp_mask); +static void bfq_end_wr_async_queues(struct bfq_data *bfqd, + struct bfq_group *bfqg); +static void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg); +static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq); + +#endif /* _BFQ_H */ diff -Nur linux-4.1.13.orig/block/bfq-ioc.c linux-4.1.13/block/bfq-ioc.c --- linux-4.1.13.orig/block/bfq-ioc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/block/bfq-ioc.c 2015-11-30 17:56:13.536140654 +0100 @@ -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-4.1.13.orig/block/bfq-iosched.c linux-4.1.13/block/bfq-iosched.c --- linux-4.1.13.orig/block/bfq-iosched.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/block/bfq-iosched.c 2015-11-30 17:56:13.536140654 +0100 @@ -0,0 +1,4223 @@ +/* + * Budget Fair Queueing (BFQ) disk scheduler. + * + * Based on ideas and code from CFQ: + * Copyright (C) 2003 Jens Axboe + * + * Copyright (C) 2008 Fabio Checconi + * Paolo Valente + * + * Copyright (C) 2010 Paolo Valente + * + * Licensed under the GPL-2 as detailed in the accompanying COPYING.BFQ + * file. + * + * BFQ is a proportional-share storage-I/O scheduling algorithm based on + * the slice-by-slice service scheme of CFQ. But BFQ assigns budgets, + * measured in number of sectors, to processes instead of time slices. The + * device is not granted to the in-service process for a given time slice, + * but until it has exhausted its assigned budget. This change from the time + * to the service domain allows BFQ to distribute the device throughput + * among processes as desired, without any distortion due to ZBR, workload + * fluctuations or other factors. BFQ uses an ad hoc internal scheduler, + * called B-WF2Q+, to schedule processes according to their budgets. More + * precisely, BFQ schedules queues associated to processes. Thanks to the + * accurate policy of B-WF2Q+, BFQ can afford to assign high budgets to + * I/O-bound processes issuing sequential requests (to boost the + * throughput), and yet guarantee a low latency to interactive and soft + * real-time applications. + * + * BFQ is described in [1], where also a reference to the initial, more + * theoretical paper on BFQ can be found. The interested reader can find + * in the latter paper full details on the main algorithm, as well as + * formulas of the guarantees and formal proofs of all the properties. + * With respect to the version of BFQ presented in these papers, this + * implementation adds a few more heuristics, such as the one that + * guarantees a low latency to soft real-time applications, and a + * hierarchical extension based on H-WF2Q+. + * + * B-WF2Q+ is based on WF2Q+, that is described in [2], together with + * H-WF2Q+, while the augmented tree used to implement B-WF2Q+ with O(log N) + * complexity derives from the one introduced with EEVDF in [3]. + * + * [1] P. Valente and M. Andreolini, ``Improving Application Responsiveness + * with the BFQ Disk I/O Scheduler'', + * Proceedings of the 5th Annual International Systems and Storage + * Conference (SYSTOR '12), June 2012. + * + * http://algogroup.unimo.it/people/paolo/disk_sched/bf1-v1-suite-results.pdf + * + * [2] Jon C.R. Bennett and H. Zhang, ``Hierarchical Packet Fair Queueing + * Algorithms,'' IEEE/ACM Transactions on Networking, 5(5):675-689, + * Oct 1997. + * + * http://www.cs.cmu.edu/~hzhang/papers/TON-97-Oct.ps.gz + * + * [3] I. Stoica and H. Abdel-Wahab, ``Earliest Eligible Virtual Deadline + * First: A Flexible and Accurate Mechanism for Proportional Share + * Resource Allocation,'' technical report. + * + * http://www.cs.berkeley.edu/~istoica/papers/eevdf-tr-95.pdf + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bfq.h" +#include "blk.h" + +/* Max number of dispatches in one round of service. */ +static const int bfq_quantum = 4; + +/* Expiration time of sync (0) and async (1) requests, in jiffies. */ +static const int bfq_fifo_expire[2] = { HZ / 4, HZ / 8 }; + +/* Maximum backwards seek, in KiB. */ +static const int bfq_back_max = 16 * 1024; + +/* Penalty of a backwards seek, in number of sectors. */ +static const int bfq_back_penalty = 2; + +/* Idling period duration, in jiffies. */ +static int bfq_slice_idle = HZ / 125; + +/* Default maximum budget values, in sectors and number of requests. */ +static const int bfq_default_max_budget = 16 * 1024; +static const int bfq_max_budget_async_rq = 4; + +/* + * Async to sync throughput distribution is controlled as follows: + * when an async request is served, the entity is charged the number + * of sectors of the request, multiplied by the factor below + */ +static const int bfq_async_charge_factor = 10; + +/* Default timeout values, in jiffies, approximating CFQ defaults. */ +static const int bfq_timeout_sync = HZ / 8; +static int bfq_timeout_async = HZ / 25; + +struct kmem_cache *bfq_pool; + +/* Below this threshold (in ms), we consider thinktime immediate. */ +#define BFQ_MIN_TT 2 + +/* hw_tag detection: parallel requests threshold and min samples needed. */ +#define BFQ_HW_QUEUE_THRESHOLD 4 +#define BFQ_HW_QUEUE_SAMPLES 32 + +#define BFQQ_SEEK_THR (sector_t)(8 * 1024) +#define BFQQ_SEEKY(bfqq) ((bfqq)->seek_mean > BFQQ_SEEK_THR) + +/* Min samples used for peak rate estimation (for autotuning). */ +#define BFQ_PEAK_RATE_SAMPLES 32 + +/* Shift used for peak rate fixed precision calculations. */ +#define BFQ_RATE_SHIFT 16 + +/* + * By default, BFQ computes the duration of the weight raising for + * interactive applications automatically, using the following formula: + * duration = (R / r) * T, where r is the peak rate of the device, and + * R and T are two reference parameters. + * In particular, R is the peak rate of the reference device (see below), + * and T is a reference time: given the systems that are likely to be + * installed on the reference device according to its speed class, T is + * about the maximum time needed, under BFQ and while reading two files in + * parallel, to load typical large applications on these systems. + * In practice, the slower/faster the device at hand is, the more/less it + * takes to load applications with respect to the reference device. + * Accordingly, the longer/shorter BFQ grants weight raising to interactive + * applications. + * + * BFQ uses four different reference pairs (R, T), depending on: + * . whether the device is rotational or non-rotational; + * . whether the device is slow, such as old or portable HDDs, as well as + * SD cards, or fast, such as newer HDDs and SSDs. + * + * The device's speed class is dynamically (re)detected in + * bfq_update_peak_rate() every time the estimated peak rate is updated. + * + * In the following definitions, R_slow[0]/R_fast[0] and T_slow[0]/T_fast[0] + * are the reference values for a slow/fast rotational device, whereas + * R_slow[1]/R_fast[1] and T_slow[1]/T_fast[1] are the reference values for + * a slow/fast non-rotational device. Finally, device_speed_thresh are the + * thresholds used to switch between speed classes. + * Both the reference peak rates and the thresholds are measured in + * sectors/usec, left-shifted by BFQ_RATE_SHIFT. + */ +static int R_slow[2] = {1536, 10752}; +static int R_fast[2] = {17415, 34791}; +/* + * To improve readability, a conversion function is used to initialize the + * following arrays, which entails that they can be initialized only in a + * function. + */ +static int T_slow[2]; +static int T_fast[2]; +static int device_speed_thresh[2]; + +#define BFQ_SERVICE_TREE_INIT ((struct bfq_service_tree) \ + { RB_ROOT, RB_ROOT, NULL, NULL, 0, 0 }) + +#define RQ_BIC(rq) ((struct bfq_io_cq *) (rq)->elv.priv[0]) +#define RQ_BFQQ(rq) ((rq)->elv.priv[1]) + +static inline void bfq_schedule_dispatch(struct bfq_data *bfqd); + +#include "bfq-ioc.c" +#include "bfq-sched.c" +#include "bfq-cgroup.c" + +#define bfq_class_idle(bfqq) ((bfqq)->entity.ioprio_class ==\ + IOPRIO_CLASS_IDLE) +#define bfq_class_rt(bfqq) ((bfqq)->entity.ioprio_class ==\ + IOPRIO_CLASS_RT) + +#define bfq_sample_valid(samples) ((samples) > 80) + +/* + * We regard a request as SYNC, if either it's a read or has the SYNC bit + * set (in which case it could also be a direct WRITE). + */ +static inline int bfq_bio_sync(struct bio *bio) +{ + if (bio_data_dir(bio) == READ || (bio->bi_rw & REQ_SYNC)) + return 1; + + return 0; +} + +/* + * Scheduler run of queue, if there are requests pending and no one in the + * driver that will restart queueing. + */ +static inline void bfq_schedule_dispatch(struct bfq_data *bfqd) +{ + if (bfqd->queued != 0) { + bfq_log(bfqd, "schedule dispatch"); + kblockd_schedule_work(&bfqd->unplug_work); + } +} + +/* + * Lifted from AS - choose which of rq1 and rq2 that is best served now. + * We choose the request that is closesr to the head right now. Distance + * behind the head is penalized and only allowed to a certain extent. + */ +static struct request *bfq_choose_req(struct bfq_data *bfqd, + struct request *rq1, + struct request *rq2, + sector_t last) +{ + sector_t s1, s2, d1 = 0, d2 = 0; + unsigned long back_max; +#define BFQ_RQ1_WRAP 0x01 /* request 1 wraps */ +#define BFQ_RQ2_WRAP 0x02 /* request 2 wraps */ + unsigned wrap = 0; /* bit mask: requests behind the disk head? */ + + if (rq1 == NULL || rq1 == rq2) + return rq2; + if (rq2 == NULL) + return rq1; + + if (rq_is_sync(rq1) && !rq_is_sync(rq2)) + return rq1; + else if (rq_is_sync(rq2) && !rq_is_sync(rq1)) + return rq2; + if ((rq1->cmd_flags & REQ_META) && !(rq2->cmd_flags & REQ_META)) + return rq1; + else if ((rq2->cmd_flags & REQ_META) && !(rq1->cmd_flags & REQ_META)) + return rq2; + + s1 = blk_rq_pos(rq1); + s2 = blk_rq_pos(rq2); + + /* + * By definition, 1KiB is 2 sectors. + */ + back_max = bfqd->bfq_back_max * 2; + + /* + * Strict one way elevator _except_ in the case where we allow + * short backward seeks which are biased as twice the cost of a + * similar forward seek. + */ + if (s1 >= last) + d1 = s1 - last; + else if (s1 + back_max >= last) + d1 = (last - s1) * bfqd->bfq_back_penalty; + else + wrap |= BFQ_RQ1_WRAP; + + if (s2 >= last) + d2 = s2 - last; + else if (s2 + back_max >= last) + d2 = (last - s2) * bfqd->bfq_back_penalty; + else + wrap |= BFQ_RQ2_WRAP; + + /* Found required data */ + + /* + * By doing switch() on the bit mask "wrap" we avoid having to + * check two variables for all permutations: --> faster! + */ + switch (wrap) { + case 0: /* common case for CFQ: rq1 and rq2 not wrapped */ + if (d1 < d2) + return rq1; + else if (d2 < d1) + return rq2; + else { + if (s1 >= s2) + return rq1; + else + return rq2; + } + + case BFQ_RQ2_WRAP: + return rq1; + case BFQ_RQ1_WRAP: + return rq2; + case (BFQ_RQ1_WRAP|BFQ_RQ2_WRAP): /* both rqs wrapped */ + default: + /* + * Since both rqs are wrapped, + * start with the one that's further behind head + * (--> only *one* back seek required), + * since back seek takes more time than forward. + */ + if (s1 <= s2) + return rq1; + else + return rq2; + } +} + +static struct bfq_queue * +bfq_rq_pos_tree_lookup(struct bfq_data *bfqd, struct rb_root *root, + sector_t sector, struct rb_node **ret_parent, + struct rb_node ***rb_link) +{ + struct rb_node **p, *parent; + struct bfq_queue *bfqq = NULL; + + parent = NULL; + p = &root->rb_node; + while (*p) { + struct rb_node **n; + + parent = *p; + bfqq = rb_entry(parent, struct bfq_queue, pos_node); + + /* + * Sort strictly based on sector. Smallest to the left, + * largest to the right. + */ + if (sector > blk_rq_pos(bfqq->next_rq)) + n = &(*p)->rb_right; + else if (sector < blk_rq_pos(bfqq->next_rq)) + n = &(*p)->rb_left; + else + break; + p = n; + bfqq = NULL; + } + + *ret_parent = parent; + if (rb_link) + *rb_link = p; + + bfq_log(bfqd, "rq_pos_tree_lookup %llu: returning %d", + (long long unsigned)sector, + bfqq != NULL ? bfqq->pid : 0); + + return bfqq; +} + +static void bfq_rq_pos_tree_add(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + struct rb_node **p, *parent; + struct bfq_queue *__bfqq; + + if (bfqq->pos_root != NULL) { + rb_erase(&bfqq->pos_node, bfqq->pos_root); + bfqq->pos_root = NULL; + } + + if (bfq_class_idle(bfqq)) + return; + if (!bfqq->next_rq) + return; + + bfqq->pos_root = &bfqd->rq_pos_tree; + __bfqq = bfq_rq_pos_tree_lookup(bfqd, bfqq->pos_root, + blk_rq_pos(bfqq->next_rq), &parent, &p); + if (__bfqq == NULL) { + rb_link_node(&bfqq->pos_node, parent, p); + rb_insert_color(&bfqq->pos_node, bfqq->pos_root); + } else + bfqq->pos_root = NULL; +} + +/* + * Tell whether there are active queues or groups with differentiated weights. + */ +static inline bool bfq_differentiated_weights(struct bfq_data *bfqd) +{ + BUG_ON(!bfqd->hw_tag); + /* + * For weights to differ, at least one of the trees must contain + * at least two nodes. + */ + return (!RB_EMPTY_ROOT(&bfqd->queue_weights_tree) && + (bfqd->queue_weights_tree.rb_node->rb_left || + bfqd->queue_weights_tree.rb_node->rb_right) +#ifdef CONFIG_CGROUP_BFQIO + ) || + (!RB_EMPTY_ROOT(&bfqd->group_weights_tree) && + (bfqd->group_weights_tree.rb_node->rb_left || + bfqd->group_weights_tree.rb_node->rb_right) +#endif + ); +} + +/* + * If the weight-counter tree passed as input contains no counter for + * the weight of the input entity, then add that counter; otherwise just + * increment the existing counter. + * + * Note that weight-counter trees contain few nodes in mostly symmetric + * scenarios. For example, if all queues have the same weight, then the + * weight-counter tree for the queues may contain at most one node. + * This holds even if low_latency is on, because weight-raised queues + * are not inserted in the tree. + * In most scenarios, the rate at which nodes are created/destroyed + * should be low too. + */ +static void bfq_weights_tree_add(struct bfq_data *bfqd, + struct bfq_entity *entity, + struct rb_root *root) +{ + struct rb_node **new = &(root->rb_node), *parent = NULL; + + /* + * Do not insert if: + * - the device does not support queueing; + * - the entity is already associated with a counter, which happens if: + * 1) the entity is associated with a queue, 2) a request arrival + * has caused the queue to become both non-weight-raised, and hence + * change its weight, and backlogged; in this respect, each + * of the two events causes an invocation of this function, + * 3) this is the invocation of this function caused by the second + * event. This second invocation is actually useless, and we handle + * this fact by exiting immediately. More efficient or clearer + * solutions might possibly be adopted. + */ + if (!bfqd->hw_tag || entity->weight_counter) + return; + + while (*new) { + struct bfq_weight_counter *__counter = container_of(*new, + struct bfq_weight_counter, + weights_node); + parent = *new; + + if (entity->weight == __counter->weight) { + entity->weight_counter = __counter; + goto inc_counter; + } + if (entity->weight < __counter->weight) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); + } + + entity->weight_counter = kzalloc(sizeof(struct bfq_weight_counter), + GFP_ATOMIC); + entity->weight_counter->weight = entity->weight; + rb_link_node(&entity->weight_counter->weights_node, parent, new); + rb_insert_color(&entity->weight_counter->weights_node, root); + +inc_counter: + entity->weight_counter->num_active++; +} + +/* + * Decrement the weight counter associated with the entity, and, if the + * counter reaches 0, remove the counter from the tree. + * See the comments to the function bfq_weights_tree_add() for considerations + * about overhead. + */ +static void bfq_weights_tree_remove(struct bfq_data *bfqd, + struct bfq_entity *entity, + struct rb_root *root) +{ + /* + * Check whether the entity is actually associated with a counter. + * In fact, the device may not be considered NCQ-capable for a while, + * which implies that no insertion in the weight trees is performed, + * after which the device may start to be deemed NCQ-capable, and hence + * this function may start to be invoked. This may cause the function + * to be invoked for entities that are not associated with any counter. + */ + if (!entity->weight_counter) + return; + + BUG_ON(RB_EMPTY_ROOT(root)); + BUG_ON(entity->weight_counter->weight != entity->weight); + + BUG_ON(!entity->weight_counter->num_active); + entity->weight_counter->num_active--; + if (entity->weight_counter->num_active > 0) + goto reset_entity_pointer; + + rb_erase(&entity->weight_counter->weights_node, root); + kfree(entity->weight_counter); + +reset_entity_pointer: + entity->weight_counter = NULL; +} + +static struct request *bfq_find_next_rq(struct bfq_data *bfqd, + struct bfq_queue *bfqq, + struct request *last) +{ + struct rb_node *rbnext = rb_next(&last->rb_node); + struct rb_node *rbprev = rb_prev(&last->rb_node); + struct request *next = NULL, *prev = NULL; + + BUG_ON(RB_EMPTY_NODE(&last->rb_node)); + + if (rbprev != NULL) + prev = rb_entry_rq(rbprev); + + if (rbnext != NULL) + next = rb_entry_rq(rbnext); + else { + rbnext = rb_first(&bfqq->sort_list); + if (rbnext && rbnext != &last->rb_node) + next = rb_entry_rq(rbnext); + } + + return bfq_choose_req(bfqd, next, prev, blk_rq_pos(last)); +} + +/* see the definition of bfq_async_charge_factor for details */ +static inline unsigned long bfq_serv_to_charge(struct request *rq, + struct bfq_queue *bfqq) +{ + return blk_rq_sectors(rq) * + (1 + ((!bfq_bfqq_sync(bfqq)) * (bfqq->wr_coeff == 1) * + bfq_async_charge_factor)); +} + +/** + * bfq_updated_next_req - update the queue after a new next_rq selection. + * @bfqd: the device data the queue belongs to. + * @bfqq: the queue to update. + * + * If the first request of a queue changes we make sure that the queue + * has enough budget to serve at least its first request (if the + * request has grown). We do this because if the queue has not enough + * budget for its first request, it has to go through two dispatch + * rounds to actually get it dispatched. + */ +static void bfq_updated_next_req(struct bfq_data *bfqd, + struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + struct bfq_service_tree *st = bfq_entity_service_tree(entity); + struct request *next_rq = bfqq->next_rq; + unsigned long new_budget; + + if (next_rq == NULL) + return; + + if (bfqq == bfqd->in_service_queue) + /* + * In order not to break guarantees, budgets cannot be + * changed after an entity has been selected. + */ + return; + + BUG_ON(entity->tree != &st->active); + BUG_ON(entity == entity->sched_data->in_service_entity); + + new_budget = max_t(unsigned long, bfqq->max_budget, + bfq_serv_to_charge(next_rq, bfqq)); + if (entity->budget != new_budget) { + entity->budget = new_budget; + bfq_log_bfqq(bfqd, bfqq, "updated next rq: new budget %lu", + new_budget); + bfq_activate_bfqq(bfqd, bfqq); + } +} + +static inline unsigned int bfq_wr_duration(struct bfq_data *bfqd) +{ + u64 dur; + + if (bfqd->bfq_wr_max_time > 0) + return bfqd->bfq_wr_max_time; + + dur = bfqd->RT_prod; + do_div(dur, bfqd->peak_rate); + + return dur; +} + +static inline unsigned +bfq_bfqq_cooperations(struct bfq_queue *bfqq) +{ + return bfqq->bic ? bfqq->bic->cooperations : 0; +} + +static inline void +bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic) +{ + if (bic->saved_idle_window) + bfq_mark_bfqq_idle_window(bfqq); + else + bfq_clear_bfqq_idle_window(bfqq); + if (bic->saved_IO_bound) + bfq_mark_bfqq_IO_bound(bfqq); + else + bfq_clear_bfqq_IO_bound(bfqq); + /* 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); + } + + list_del_init(&rq->queuelist); + BUG_ON(bfqq->queued[sync] == 0); + bfqq->queued[sync]--; + bfqd->queued--; + elv_rb_del(&bfqq->sort_list, rq); + + if (RB_EMPTY_ROOT(&bfqq->sort_list)) { + if (bfq_bfqq_busy(bfqq) && bfqq != bfqd->in_service_queue) + bfq_del_bfqq_busy(bfqd, bfqq, 1); + /* + * Remove queue from request-position tree as it is empty. + */ + if (bfqq->pos_root != NULL) { + rb_erase(&bfqq->pos_node, bfqq->pos_root); + bfqq->pos_root = NULL; + } + } + + if (rq->cmd_flags & REQ_META) { + BUG_ON(bfqq->meta_pending == 0); + bfqq->meta_pending--; + } +} + +static int bfq_merge(struct request_queue *q, struct request **req, + struct bio *bio) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct request *__rq; + + __rq = bfq_find_rq_fmerge(bfqd, bio); + if (__rq != NULL && elv_rq_merge_ok(__rq, bio)) { + *req = __rq; + return ELEVATOR_FRONT_MERGE; + } + + return ELEVATOR_NO_MERGE; +} + +static void bfq_merged_request(struct request_queue *q, struct request *req, + int type) +{ + if (type == ELEVATOR_FRONT_MERGE && + rb_prev(&req->rb_node) && + blk_rq_pos(req) < + blk_rq_pos(container_of(rb_prev(&req->rb_node), + struct request, rb_node))) { + struct bfq_queue *bfqq = RQ_BFQQ(req); + struct bfq_data *bfqd = bfqq->bfqd; + struct request *prev, *next_rq; + + /* Reposition request in its sort_list */ + elv_rb_del(&bfqq->sort_list, req); + elv_rb_add(&bfqq->sort_list, req); + /* Choose next request to be served for bfqq */ + prev = bfqq->next_rq; + next_rq = bfq_choose_req(bfqd, bfqq->next_rq, req, + bfqd->last_position); + BUG_ON(next_rq == NULL); + bfqq->next_rq = next_rq; + /* + * If next_rq changes, update both the queue's budget to + * fit the new request and the queue's position in its + * rq_pos_tree. + */ + if (prev != bfqq->next_rq) { + bfq_updated_next_req(bfqd, bfqq); + bfq_rq_pos_tree_add(bfqd, bfqq); + } + } +} + +static void bfq_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq); + + /* + * Reposition in fifo if next is older than rq. + */ + if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) && + time_before(next->fifo_time, rq->fifo_time)) { + list_move(&rq->queuelist, &next->queuelist); + rq->fifo_time = next->fifo_time; + } + + 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, grant only minimum idle + * time if the queue either has been seeky for long enough or has + * already proved to be constantly seeky. + */ + if (bfq_sample_valid(bfqq->seek_samples) && + ((BFQQ_SEEKY(bfqq) && bfqq->entity.service > + bfq_max_budget(bfqq->bfqd) / 8) || + bfq_bfqq_constantly_seeky(bfqq)) && bfqq->wr_coeff == 1) + sl = min(sl, msecs_to_jiffies(BFQ_MIN_TT)); + else if (bfqq->wr_coeff > 1) + sl = sl * 3; + bfqd->last_idling_start = ktime_get(); + mod_timer(&bfqd->idle_slice_timer, jiffies + sl); + bfq_log(bfqd, "arm idle: %u/%u ms", + jiffies_to_msecs(sl), jiffies_to_msecs(bfqd->bfq_slice_idle)); +} + +/* + * Set the maximum time for the in-service queue to consume its + * budget. This prevents seeky processes from lowering the disk + * throughput (always guaranteed with a time slice scheme as in CFQ). + */ +static void bfq_set_budget_timeout(struct bfq_data *bfqd) +{ + struct bfq_queue *bfqq = bfqd->in_service_queue; + unsigned int timeout_coeff; + if (bfqq->wr_cur_max_time == bfqd->bfq_wr_rt_max_time) + timeout_coeff = 1; + else + timeout_coeff = bfqq->entity.weight / bfqq->entity.orig_weight; + + bfqd->last_budget_start = ktime_get(); + + bfq_clear_bfqq_budget_new(bfqq); + bfqq->budget_timeout = jiffies + + bfqd->bfq_timeout[bfq_bfqq_sync(bfqq)] * timeout_coeff; + + bfq_log_bfqq(bfqd, bfqq, "set budget_timeout %u", + jiffies_to_msecs(bfqd->bfq_timeout[bfq_bfqq_sync(bfqq)] * + timeout_coeff)); +} + +/* + * Move request from internal lists to the request queue dispatch list. + */ +static void bfq_dispatch_insert(struct request_queue *q, struct request *rq) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct bfq_queue *bfqq = RQ_BFQQ(rq); + + /* + * For consistency, the next instruction should have been executed + * after removing the request from the queue and dispatching it. + * We execute instead this instruction before bfq_remove_request() + * (and hence introduce a temporary inconsistency), for efficiency. + * In fact, in a forced_dispatch, this prevents two counters related + * to bfqq->dispatched to risk to be uselessly decremented if bfqq + * is not in service, and then to be incremented again after + * incrementing bfqq->dispatched. + */ + bfqq->dispatched++; + bfq_remove_request(rq); + elv_dispatch_sort(q, rq); + + if (bfq_bfqq_sync(bfqq)) + bfqd->sync_flight++; +} + +/* + * Return expired entry, or NULL to just start from scratch in rbtree. + */ +static struct request *bfq_check_fifo(struct bfq_queue *bfqq) +{ + struct request *rq = NULL; + + if (bfq_bfqq_fifo_expire(bfqq)) + return NULL; + + bfq_mark_bfqq_fifo_expire(bfqq); + + if (list_empty(&bfqq->fifo)) + return NULL; + + rq = rq_entry_fifo(bfqq->fifo.next); + + if (time_before(jiffies, rq->fifo_time)) + 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; +#ifdef CONFIG_CGROUP_BFQIO +#define symmetric_scenario (!bfqd->active_numerous_groups && \ + !bfq_differentiated_weights(bfqd)) +#else +#define symmetric_scenario (!bfq_differentiated_weights(bfqd)) +#endif +#define cond_for_seeky_on_ncq_hdd (bfq_bfqq_constantly_seeky(bfqq) && \ + bfqd->busy_in_flight_queues == \ + bfqd->const_seeky_busy_in_flight_queues) + +#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 || \ + (symmetric_scenario && \ + (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 || + (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. If the in-service queue still has requests + * in flight (possibly waiting for a completion) or is idling for a + * new request, then keep it. + */ + if (timer_pending(&bfqd->idle_slice_timer) || + (bfqq->dispatched != 0 && bfq_bfqq_must_not_expire(bfqq))) { + bfqq = NULL; + goto keep_queue; + } + + reason = BFQ_BFQQ_NO_MORE_REQUESTS; +expire: + bfq_bfqq_expire(bfqd, bfqq, 0, reason); +new_queue: + bfqq = bfq_set_in_service_queue(bfqd); + bfq_log(bfqd, "select_queue: new queue %d returned", + bfqq != NULL ? bfqq->pid : 0); +keep_queue: + return bfqq; +} + +static void bfq_update_wr_data(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + if (bfqq->wr_coeff > 1) { /* queue is being weight-raised */ + bfq_log_bfqq(bfqd, bfqq, + "raising period dur %u/%u msec, old coeff %u, w %d(%d)", + jiffies_to_msecs(jiffies - bfqq->last_wr_start_finish), + jiffies_to_msecs(bfqq->wr_cur_max_time), + bfqq->wr_coeff, + bfqq->entity.weight, bfqq->entity.orig_weight); + + BUG_ON(bfqq != bfqd->in_service_queue && entity->weight != + entity->orig_weight * bfqq->wr_coeff); + if (entity->ioprio_changed) + bfq_log_bfqq(bfqd, bfqq, "WARN: pending prio change"); + + /* + * If 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; + + max_dispatch = bfqd->bfq_quantum; + if (bfq_class_idle(bfqq)) + max_dispatch = 1; + + if (!bfq_bfqq_sync(bfqq)) + max_dispatch = bfqd->bfq_max_budget_async_rq; + + if (bfqq->dispatched >= max_dispatch) { + if (bfqd->busy_queues > 1) + return 0; + if (bfqq->dispatched >= 4 * max_dispatch) + return 0; + } + + if (bfqd->sync_flight != 0 && !bfq_bfqq_sync(bfqq)) + return 0; + + bfq_clear_bfqq_wait_request(bfqq); + BUG_ON(timer_pending(&bfqd->idle_slice_timer)); + + if (!bfq_dispatch_request(bfqd, bfqq)) + return 0; + + bfq_log_bfqq(bfqd, bfqq, "dispatched one request of %d (max_disp %d)", + bfqq->pid, max_dispatch); + + return 1; +} + +/* + * Task holds one reference to the queue, dropped when task exits. Each rq + * in-flight on this queue also holds a reference, dropped when rq is freed. + * + * Queue lock must be held here. + */ +static void bfq_put_queue(struct bfq_queue *bfqq) +{ + struct bfq_data *bfqd = bfqq->bfqd; + + BUG_ON(atomic_read(&bfqq->ref) <= 0); + + bfq_log_bfqq(bfqd, bfqq, "put_queue: %p %d", bfqq, + atomic_read(&bfqq->ref)); + if (!atomic_dec_and_test(&bfqq->ref)) + return; + + BUG_ON(rb_first(&bfqq->sort_list) != NULL); + BUG_ON(bfqq->allocated[READ] + bfqq->allocated[WRITE] != 0); + BUG_ON(bfqq->entity.tree != NULL); + BUG_ON(bfq_bfqq_busy(bfqq)); + BUG_ON(bfqd->in_service_queue == bfqq); + + 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_init_prio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic) +{ + struct task_struct *tsk = current; + int ioprio_class; + + if (!bfq_bfqq_prio_changed(bfqq)) + return; + + ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio); + switch (ioprio_class) { + default: + dev_err(bfqq->bfqd->queue->backing_dev_info.dev, + "bfq: bad prio 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_init_prio_data: new_ioprio %d\n", + bfqq->entity.new_ioprio); + BUG(); + } + + bfqq->entity.ioprio_changed = 1; + + bfq_clear_bfqq_prio_changed(bfqq); +} + +static void bfq_changed_ioprio(struct bfq_io_cq *bic) +{ + struct bfq_data *bfqd; + struct bfq_queue *bfqq, *new_bfqq; + struct bfq_group *bfqg; + unsigned long uninitialized_var(flags); + int ioprio = bic->icq.ioc->ioprio; + + bfqd = bfq_get_bfqd_locked(&(bic->icq.q->elevator->elevator_data), + &flags); + /* + * This condition may trigger on a newly created bic, be sure to + * drop the lock before returning. + */ + if (unlikely(bfqd == NULL) || likely(bic->ioprio == ioprio)) + goto out; + + bfqq = bic->bfqq[BLK_RW_ASYNC]; + if (bfqq != NULL) { + bfqg = container_of(bfqq->entity.sched_data, struct bfq_group, + sched_data); + new_bfqq = bfq_get_queue(bfqd, bfqg, BLK_RW_ASYNC, bic, + GFP_ATOMIC); + if (new_bfqq != NULL) { + bic->bfqq[BLK_RW_ASYNC] = new_bfqq; + bfq_log_bfqq(bfqd, bfqq, + "changed_ioprio: bfqq %p %d", + bfqq, atomic_read(&bfqq->ref)); + bfq_put_queue(bfqq); + } + } + + bfqq = bic->bfqq[BLK_RW_SYNC]; + if (bfqq != NULL) + bfq_mark_bfqq_prio_changed(bfqq); + + bic->ioprio = ioprio; + +out: + bfq_put_bfqd_unlock(bfqd, &flags); +} + +static void bfq_init_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, + pid_t pid, int is_sync) +{ + RB_CLEAR_NODE(&bfqq->entity.rb_node); + INIT_LIST_HEAD(&bfqq->fifo); + INIT_HLIST_NODE(&bfqq->burst_list_node); + + atomic_set(&bfqq->ref, 0); + bfqq->bfqd = bfqd; + + bfq_mark_bfqq_prio_changed(bfqq); + + if (is_sync) { + if (!bfq_class_idle(bfqq)) + bfq_mark_bfqq_idle_window(bfqq); + bfq_mark_bfqq_sync(bfqq); + } + bfq_mark_bfqq_IO_bound(bfqq); + + /* Tentative initial value to trade off between thr and lat */ + bfqq->max_budget = (2 * bfq_max_budget(bfqd)) / 3; + bfqq->pid = pid; + + bfqq->wr_coeff = 1; + bfqq->last_wr_start_finish = 0; + /* + * Set to the value for which bfqq will not be deemed as + * soft rt when it becomes backlogged. + */ + bfqq->soft_rt_next_start = bfq_infinity_from_now(jiffies); +} + +static struct bfq_queue *bfq_find_alloc_queue(struct bfq_data *bfqd, + struct bfq_group *bfqg, + int is_sync, + struct bfq_io_cq *bic, + gfp_t gfp_mask) +{ + struct bfq_queue *bfqq, *new_bfqq = NULL; + +retry: + /* bic always exists here */ + bfqq = bic_to_bfqq(bic, is_sync); + + /* + * Always try a new alloc if we fall back to the OOM bfqq + * originally, since it should just be a temporary situation. + */ + if (bfqq == NULL || bfqq == &bfqd->oom_bfqq) { + bfqq = NULL; + if (new_bfqq != NULL) { + bfqq = new_bfqq; + new_bfqq = NULL; + } else if (gfp_mask & __GFP_WAIT) { + spin_unlock_irq(bfqd->queue->queue_lock); + new_bfqq = kmem_cache_alloc_node(bfq_pool, + gfp_mask | __GFP_ZERO, + bfqd->queue->node); + spin_lock_irq(bfqd->queue->queue_lock); + if (new_bfqq != NULL) + goto retry; + } else { + bfqq = kmem_cache_alloc_node(bfq_pool, + gfp_mask | __GFP_ZERO, + bfqd->queue->node); + } + + if (bfqq != NULL) { + bfq_init_bfqq(bfqd, bfqq, current->pid, is_sync); + bfq_init_prio_data(bfqq, bic); + 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_init_prio_data(bfqq, RQ_BIC(rq)); + + bfq_add_request(rq); + + /* + * Here a newly-created bfq_queue has already started a weight-raising + * period: clear raising_time_left to prevent bfq_bfqq_save_state() + * from assigning it a full weight-raising period. See the detailed + * comments about this field in bfq_init_icq(). + */ + if (bfqq->bic != NULL) + bfqq->bic->wr_time_left = 0; + rq->fifo_time = jiffies + bfqd->bfq_fifo_expire[rq_is_sync(rq)]; + list_add_tail(&rq->queuelist, &bfqq->fifo); + + bfq_rq_enqueued(bfqd, bfqq, rq); +} + +static void bfq_update_hw_tag(struct bfq_data *bfqd) +{ + bfqd->max_rq_in_driver = max(bfqd->max_rq_in_driver, + bfqd->rq_in_driver); + + if (bfqd->hw_tag == 1) + return; + + /* + * This sample is valid if the number of outstanding requests + * is large enough to allow a queueing behavior. Note that the + * sum is not exact, as it's not taking into account deactivated + * requests. + */ + if (bfqd->rq_in_driver + bfqd->queued < BFQ_HW_QUEUE_THRESHOLD) + return; + + if (bfqd->hw_tag_samples++ < BFQ_HW_QUEUE_SAMPLES) + return; + + bfqd->hw_tag = bfqd->max_rq_in_driver > BFQ_HW_QUEUE_THRESHOLD; + bfqd->max_rq_in_driver = 0; + bfqd->hw_tag_samples = 0; +} + +static void bfq_completed_request(struct request_queue *q, struct request *rq) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq); + struct bfq_data *bfqd = bfqq->bfqd; + bool sync = bfq_bfqq_sync(bfqq); + + bfq_log_bfqq(bfqd, bfqq, "completed one req with %u sects left (%d)", + blk_rq_sectors(rq), sync); + + bfq_update_hw_tag(bfqd); + + BUG_ON(!bfqd->rq_in_driver); + BUG_ON(!bfqq->dispatched); + bfqd->rq_in_driver--; + bfqq->dispatched--; + + if (!bfqq->dispatched && !bfq_bfqq_busy(bfqq)) { + bfq_weights_tree_remove(bfqd, &bfqq->entity, + &bfqd->queue_weights_tree); + if (!blk_queue_nonrot(bfqd->queue)) { + BUG_ON(!bfqd->busy_in_flight_queues); + bfqd->busy_in_flight_queues--; + if (bfq_bfqq_constantly_seeky(bfqq)) { + BUG_ON(!bfqd-> + const_seeky_busy_in_flight_queues); + bfqd->const_seeky_busy_in_flight_queues--; + } + } + } + + if (sync) { + bfqd->sync_flight--; + RQ_BIC(rq)->ttime.last_end_request = jiffies; + } + + /* + * If we are waiting to discover whether the request pattern of the + * task associated with the queue is actually isochronous, and + * both requisites for this condition to hold are satisfied, then + * compute soft_rt_next_start (see the comments to the function + * bfq_bfqq_softrt_next_start()). + */ + if (bfq_bfqq_softrt_update(bfqq) && bfqq->dispatched == 0 && + RB_EMPTY_ROOT(&bfqq->sort_list)) + bfqq->soft_rt_next_start = + bfq_bfqq_softrt_next_start(bfqd, bfqq); + + /* + * If this is the in-service queue, check if it needs to be expired, + * or if we want to idle in case it has no pending requests. + */ + if (bfqd->in_service_queue == bfqq) { + if (bfq_bfqq_budget_new(bfqq)) + bfq_set_budget_timeout(bfqd); + + if (bfq_bfqq_must_idle(bfqq)) { + bfq_arm_slice_timer(bfqd); + goto out; + } else if (bfq_may_expire_for_budg_timeout(bfqq)) + bfq_bfqq_expire(bfqd, bfqq, 0, BFQ_BFQQ_BUDGET_TIMEOUT); + else if (RB_EMPTY_ROOT(&bfqq->sort_list) && + (bfqq->dispatched == 0 || + !bfq_bfqq_must_not_expire(bfqq))) + bfq_bfqq_expire(bfqd, bfqq, 0, + BFQ_BFQQ_NO_MORE_REQUESTS); + } + + if (!bfqd->rq_in_driver) + bfq_schedule_dispatch(bfqd); + +out: + return; +} + +static inline int __bfq_may_queue(struct bfq_queue *bfqq) +{ + if (bfq_bfqq_wait_request(bfqq) && bfq_bfqq_must_alloc(bfqq)) { + bfq_clear_bfqq_must_alloc(bfqq); + return ELV_MQUEUE_MUST; + } + + return ELV_MQUEUE_MAY; +} + +static int bfq_may_queue(struct request_queue *q, int rw) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct task_struct *tsk = current; + struct bfq_io_cq *bic; + struct bfq_queue *bfqq; + + /* + * Don't force setup of a queue from here, as a call to may_queue + * does not necessarily imply that a request actually will be + * queued. So just lookup a possibly existing queue, or return + * 'may queue' if that fails. + */ + bic = bfq_bic_lookup(bfqd, tsk->io_context); + if (bic == NULL) + return ELV_MQUEUE_MAY; + + bfqq = bic_to_bfqq(bic, rw_is_sync(rw)); + if (bfqq != NULL) { + bfq_init_prio_data(bfqq, bic); + + return __bfq_may_queue(bfqq); + } + + return ELV_MQUEUE_MAY; +} + +/* + * Queue lock held here. + */ +static void bfq_put_request(struct request *rq) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq); + + if (bfqq != NULL) { + const int rw = rq_data_dir(rq); + + BUG_ON(!bfqq->allocated[rw]); + bfqq->allocated[rw]--; + + rq->elv.priv[0] = NULL; + rq->elv.priv[1] = NULL; + + bfq_log_bfqq(bfqq->bfqd, bfqq, "put_request %p, %d", + bfqq, atomic_read(&bfqq->ref)); + bfq_put_queue(bfqq); + } +} + +/* + * Returns NULL if a new bfqq should be allocated, or the old bfqq if this + * was the last process referring to said bfqq. + */ +static struct bfq_queue * +bfq_split_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq) +{ + bfq_log_bfqq(bfqq->bfqd, bfqq, "splitting queue"); + + put_io_context(bic->icq.ioc); + + if (bfqq_process_refs(bfqq) == 1) { + bfqq->pid = current->pid; + bfq_clear_bfqq_coop(bfqq); + bfq_clear_bfqq_split_coop(bfqq); + return bfqq; + } + + bic_set_bfqq(bic, NULL, 1); + + bfq_put_cooperator(bfqq); + + bfq_put_queue(bfqq); + return NULL; +} + +/* + * Allocate bfq data structures associated with this request. + */ +static int bfq_set_request(struct request_queue *q, struct request *rq, + struct bio *bio, gfp_t gfp_mask) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct bfq_io_cq *bic = icq_to_bic(rq->elv.icq); + const int rw = rq_data_dir(rq); + const int is_sync = rq_is_sync(rq); + struct bfq_queue *bfqq; + struct bfq_group *bfqg; + unsigned long flags; + bool split = false; + + might_sleep_if(gfp_mask & __GFP_WAIT); + + bfq_changed_ioprio(bic); + + spin_lock_irqsave(q->queue_lock, flags); + + if (bic == NULL) + goto queue_fail; + + bfqg = bfq_bic_update_cgroup(bic); + +new_queue: + bfqq = bic_to_bfqq(bic, is_sync); + if (bfqq == NULL || bfqq == &bfqd->oom_bfqq) { + bfqq = bfq_get_queue(bfqd, bfqg, is_sync, bic, gfp_mask); + bic_set_bfqq(bic, bfqq, is_sync); + 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, 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; + /* + * 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_quantum = bfq_quantum; + bfqd->bfq_fifo_expire[0] = bfq_fifo_expire[0]; + bfqd->bfq_fifo_expire[1] = bfq_fifo_expire[1]; + bfqd->bfq_back_max = bfq_back_max; + bfqd->bfq_back_penalty = bfq_back_penalty; + bfqd->bfq_slice_idle = bfq_slice_idle; + bfqd->bfq_class_idle_last_service = 0; + bfqd->bfq_max_budget_async_rq = bfq_max_budget_async_rq; + bfqd->bfq_timeout[BLK_RW_ASYNC] = bfq_timeout_async; + bfqd->bfq_timeout[BLK_RW_SYNC] = bfq_timeout_sync; + + bfqd->bfq_coop_thresh = 2; + bfqd->bfq_failed_cooperations = 7000; + bfqd->bfq_requests_within_timer = 120; + + bfqd->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_quantum_show, bfqd->bfq_quantum, 0); +SHOW_FUNCTION(bfq_fifo_expire_sync_show, bfqd->bfq_fifo_expire[1], 1); +SHOW_FUNCTION(bfq_fifo_expire_async_show, bfqd->bfq_fifo_expire[0], 1); +SHOW_FUNCTION(bfq_back_seek_max_show, bfqd->bfq_back_max, 0); +SHOW_FUNCTION(bfq_back_seek_penalty_show, bfqd->bfq_back_penalty, 0); +SHOW_FUNCTION(bfq_slice_idle_show, bfqd->bfq_slice_idle, 1); +SHOW_FUNCTION(bfq_max_budget_show, bfqd->bfq_user_max_budget, 0); +SHOW_FUNCTION(bfq_max_budget_async_rq_show, + bfqd->bfq_max_budget_async_rq, 0); +SHOW_FUNCTION(bfq_timeout_sync_show, bfqd->bfq_timeout[BLK_RW_SYNC], 1); +SHOW_FUNCTION(bfq_timeout_async_show, bfqd->bfq_timeout[BLK_RW_ASYNC], 1); +SHOW_FUNCTION(bfq_low_latency_show, bfqd->low_latency, 0); +SHOW_FUNCTION(bfq_wr_coeff_show, bfqd->bfq_wr_coeff, 0); +SHOW_FUNCTION(bfq_wr_rt_max_time_show, bfqd->bfq_wr_rt_max_time, 1); +SHOW_FUNCTION(bfq_wr_min_idle_time_show, bfqd->bfq_wr_min_idle_time, 1); +SHOW_FUNCTION(bfq_wr_min_inter_arr_async_show, bfqd->bfq_wr_min_inter_arr_async, + 1); +SHOW_FUNCTION(bfq_wr_max_softrt_rate_show, bfqd->bfq_wr_max_softrt_rate, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +static ssize_t \ +__FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ + struct bfq_data *bfqd = e->elevator_data; \ + unsigned long uninitialized_var(__data); \ + int ret = bfq_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + if (__CONV) \ + *(__PTR) = msecs_to_jiffies(__data); \ + else \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(bfq_quantum_store, &bfqd->bfq_quantum, 1, INT_MAX, 0); +STORE_FUNCTION(bfq_fifo_expire_sync_store, &bfqd->bfq_fifo_expire[1], 1, + INT_MAX, 1); +STORE_FUNCTION(bfq_fifo_expire_async_store, &bfqd->bfq_fifo_expire[0], 1, + INT_MAX, 1); +STORE_FUNCTION(bfq_back_seek_max_store, &bfqd->bfq_back_max, 0, INT_MAX, 0); +STORE_FUNCTION(bfq_back_seek_penalty_store, &bfqd->bfq_back_penalty, 1, + INT_MAX, 0); +STORE_FUNCTION(bfq_slice_idle_store, &bfqd->bfq_slice_idle, 0, INT_MAX, 1); +STORE_FUNCTION(bfq_max_budget_async_rq_store, &bfqd->bfq_max_budget_async_rq, + 1, INT_MAX, 0); +STORE_FUNCTION(bfq_timeout_async_store, &bfqd->bfq_timeout[BLK_RW_ASYNC], 0, + INT_MAX, 1); +STORE_FUNCTION(bfq_wr_coeff_store, &bfqd->bfq_wr_coeff, 1, INT_MAX, 0); +STORE_FUNCTION(bfq_wr_max_time_store, &bfqd->bfq_wr_max_time, 0, INT_MAX, 1); +STORE_FUNCTION(bfq_wr_rt_max_time_store, &bfqd->bfq_wr_rt_max_time, 0, INT_MAX, + 1); +STORE_FUNCTION(bfq_wr_min_idle_time_store, &bfqd->bfq_wr_min_idle_time, 0, + INT_MAX, 1); +STORE_FUNCTION(bfq_wr_min_inter_arr_async_store, + &bfqd->bfq_wr_min_inter_arr_async, 0, INT_MAX, 1); +STORE_FUNCTION(bfq_wr_max_softrt_rate_store, &bfqd->bfq_wr_max_softrt_rate, 0, + INT_MAX, 0); +#undef STORE_FUNCTION + +/* do nothing for the moment */ +static ssize_t bfq_weights_store(struct elevator_queue *e, + const char *page, size_t count) +{ + return count; +} + +static inline unsigned long bfq_estimated_max_budget(struct bfq_data *bfqd) +{ + u64 timeout = jiffies_to_msecs(bfqd->bfq_timeout[BLK_RW_SYNC]); + + if (bfqd->peak_rate_samples >= BFQ_PEAK_RATE_SAMPLES) + return bfq_calc_max_budget(bfqd->peak_rate, timeout); + else + return bfq_default_max_budget; +} + +static ssize_t bfq_max_budget_store(struct elevator_queue *e, + const char *page, size_t count) +{ + struct bfq_data *bfqd = e->elevator_data; + unsigned long uninitialized_var(__data); + int ret = bfq_var_store(&__data, (page), count); + + if (__data == 0) + bfqd->bfq_max_budget = bfq_estimated_max_budget(bfqd); + else { + if (__data > INT_MAX) + __data = INT_MAX; + bfqd->bfq_max_budget = __data; + } + + bfqd->bfq_user_max_budget = __data; + + return ret; +} + +static ssize_t bfq_timeout_sync_store(struct elevator_queue *e, + const char *page, size_t count) +{ + struct bfq_data *bfqd = e->elevator_data; + unsigned long uninitialized_var(__data); + int ret = bfq_var_store(&__data, (page), count); + + if (__data < 1) + __data = 1; + else if (__data > INT_MAX) + __data = INT_MAX; + + bfqd->bfq_timeout[BLK_RW_SYNC] = msecs_to_jiffies(__data); + if (bfqd->bfq_user_max_budget == 0) + bfqd->bfq_max_budget = bfq_estimated_max_budget(bfqd); + + return ret; +} + +static ssize_t bfq_low_latency_store(struct elevator_queue *e, + const char *page, size_t count) +{ + struct bfq_data *bfqd = e->elevator_data; + unsigned long uninitialized_var(__data); + int ret = bfq_var_store(&__data, (page), count); + + if (__data > 1) + __data = 1; + if (__data == 0 && bfqd->low_latency != 0) + bfq_end_wr(bfqd); + bfqd->low_latency = __data; + + return ret; +} + +#define BFQ_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, bfq_##name##_show, bfq_##name##_store) + +static struct elv_fs_entry bfq_attrs[] = { + BFQ_ATTR(quantum), + BFQ_ATTR(fifo_expire_sync), + BFQ_ATTR(fifo_expire_async), + BFQ_ATTR(back_seek_max), + BFQ_ATTR(back_seek_penalty), + BFQ_ATTR(slice_idle), + BFQ_ATTR(max_budget), + BFQ_ATTR(max_budget_async_rq), + BFQ_ATTR(timeout_sync), + BFQ_ATTR(timeout_async), + BFQ_ATTR(low_latency), + BFQ_ATTR(wr_coeff), + BFQ_ATTR(wr_max_time), + BFQ_ATTR(wr_rt_max_time), + BFQ_ATTR(wr_min_idle_time), + BFQ_ATTR(wr_min_inter_arr_async), + BFQ_ATTR(wr_max_softrt_rate), + BFQ_ATTR(weights), + __ATTR_NULL +}; + +static struct elevator_type iosched_bfq = { + .ops = { + .elevator_merge_fn = bfq_merge, + .elevator_merged_fn = bfq_merged_request, + .elevator_merge_req_fn = bfq_merged_requests, + .elevator_allow_merge_fn = bfq_allow_merge, + .elevator_dispatch_fn = bfq_dispatch_requests, + .elevator_add_req_fn = bfq_insert_request, + .elevator_activate_req_fn = bfq_activate_request, + .elevator_deactivate_req_fn = bfq_deactivate_request, + .elevator_completed_req_fn = bfq_completed_request, + .elevator_former_req_fn = elv_rb_former_request, + .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_init_icq_fn = bfq_init_icq, + .elevator_exit_icq_fn = bfq_exit_icq, + .elevator_set_req_fn = bfq_set_request, + .elevator_put_req_fn = bfq_put_request, + .elevator_may_queue_fn = bfq_may_queue, + .elevator_init_fn = bfq_init_queue, + .elevator_exit_fn = bfq_exit_queue, + }, + .icq_size = sizeof(struct bfq_io_cq), + .icq_align = __alignof__(struct bfq_io_cq), + .elevator_attrs = bfq_attrs, + .elevator_name = "bfq", + .elevator_owner = THIS_MODULE, +}; + +static int __init bfq_init(void) +{ + /* + * Can be 0 on HZ < 1000 setups. + */ + if (bfq_slice_idle == 0) + bfq_slice_idle = 1; + + if (bfq_timeout_async == 0) + bfq_timeout_async = 1; + + if (bfq_slab_setup()) + return -ENOMEM; + + /* + * Times to load large popular applications for the typical systems + * installed on the reference devices (see the comments before the + * definitions of the two arrays). + */ + T_slow[0] = msecs_to_jiffies(2600); + T_slow[1] = msecs_to_jiffies(1000); + T_fast[0] = msecs_to_jiffies(5500); + T_fast[1] = msecs_to_jiffies(2000); + + /* + * Thresholds that determine the switch between speed classes (see + * the comments before the definition of the array). + */ + device_speed_thresh[0] = (R_fast[0] + R_slow[0]) / 2; + device_speed_thresh[1] = (R_fast[1] + R_slow[1]) / 2; + + elv_register(&iosched_bfq); + pr_info("BFQ I/O-scheduler version: v7r7"); + + 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-4.1.13.orig/block/bfq-sched.c linux-4.1.13/block/bfq-sched.c --- linux-4.1.13.orig/block/bfq-sched.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/block/bfq-sched.c 2015-11-30 17:56:13.536140654 +0100 @@ -0,0 +1,1186 @@ +/* + * 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); + } else if (entity->new_ioprio != entity->ioprio) { + entity->ioprio = entity->new_ioprio; + entity->orig_weight = + bfq_ioprio_to_weight(entity->ioprio); + } else + entity->new_weight = entity->orig_weight = + bfq_ioprio_to_weight(entity->ioprio); + + entity->ioprio_class = entity->new_ioprio_class; + entity->ioprio_changed = 0; + + /* + * NOTE: here we may be changing the weight too early, + * this will cause unfairness. The correct approach + * would have required additional complexity to defer + * weight changes to the proper time instants (i.e., + * when entity->finish <= old_st->vtime). + */ + new_st = bfq_entity_service_tree(entity); + + prev_weight = entity->weight; + new_weight = entity->orig_weight * + (bfqq != NULL ? bfqq->wr_coeff : 1); + /* + * If the weight of the entity changes, remove the entity + * from its old weight counter (if there is a counter + * associated with the entity), and add it to the counter + * associated with its new weight. + */ + if (prev_weight != new_weight) { + root = bfqq ? &bfqd->queue_weights_tree : + &bfqd->group_weights_tree; + bfq_weights_tree_remove(bfqd, entity, root); + } + entity->weight = new_weight; + /* + * Add the entity to its weights tree only if it is + * not associated with a weight-raised queue. + */ + if (prev_weight != new_weight && + (bfqq ? bfqq->wr_coeff == 1 : 1)) + /* If we get here, root has been initialized. */ + bfq_weights_tree_add(bfqd, entity, root); + + new_st->wsum += entity->weight; + + if (new_st != old_st) + entity->start = new_st->vtime; + } + + return new_st; +} + +/** + * bfq_bfqq_served - update the scheduler status after selection for + * service. + * @bfqq: the queue being served. + * @served: bytes to transfer. + * + * NOTE: this can be optimized, as the timestamps of upper level entities + * are synchronized every time a new bfqq is selected for service. By now, + * we keep it to better check consistency. + */ +static void bfq_bfqq_served(struct bfq_queue *bfqq, unsigned long served) +{ + struct bfq_entity *entity = &bfqq->entity; + struct bfq_service_tree *st; + + for_each_entity(entity) { + st = bfq_entity_service_tree(entity); + + entity->service += served; + BUG_ON(entity->service > entity->budget); + BUG_ON(st->wsum == 0); + + st->vtime += bfq_delta(served, st->wsum); + bfq_forget_idle(st); + } + bfq_log_bfqq(bfqq->bfqd, bfqq, "bfqq_served %lu secs", served); +} + +/** + * bfq_bfqq_charge_full_budget - set the service to the entity budget. + * @bfqq: the queue that needs a service update. + * + * When it's not possible to be fair in the service domain, because + * a queue is not consuming its budget fast enough (the meaning of + * fast depends on the timeout parameter), we charge it a full + * budget. In this way we should obtain a sort of time-domain + * fairness among all the seeky/slow queues. + */ +static inline void bfq_bfqq_charge_full_budget(struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + + bfq_log_bfqq(bfqq->bfqd, bfqq, "charge_full_budget"); + + bfq_bfqq_served(bfqq, entity->budget - entity->service); +} + +/** + * __bfq_activate_entity - activate an entity. + * @entity: the entity being activated. + * + * Called whenever an entity is activated, i.e., it is not active and one + * of its children receives a new request, or has to be reactivated due to + * budget exhaustion. It uses the current budget of the entity (and the + * service received if @entity is active) of the queue to calculate its + * timestamps. + */ +static void __bfq_activate_entity(struct bfq_entity *entity) +{ + struct bfq_sched_data *sd = entity->sched_data; + struct bfq_service_tree *st = bfq_entity_service_tree(entity); + + if (entity == sd->in_service_entity) { + BUG_ON(entity->tree != NULL); + /* + * If we are requeueing the current entity we have + * to take care of not charging to it service it has + * not received. + */ + bfq_calc_finish(entity, entity->service); + entity->start = entity->finish; + sd->in_service_entity = NULL; + } else if (entity->tree == &st->active) { + /* + * Requeueing an entity due to a change of some + * next_in_service entity below it. We reuse the + * old start time. + */ + bfq_active_extract(st, entity); + } else if (entity->tree == &st->idle) { + /* + * Must be on the idle tree, bfq_idle_extract() will + * check for that. + */ + bfq_idle_extract(st, entity); + entity->start = bfq_gt(st->vtime, entity->finish) ? + st->vtime : entity->finish; + } else { + /* + * The finish time of the entity may be invalid, and + * it is in the past for sure, otherwise the queue + * would have been on the idle tree. + */ + entity->start = st->vtime; + st->wsum += entity->weight; + bfq_get_entity(entity); + + BUG_ON(entity->on_st); + entity->on_st = 1; + } + + st = __bfq_entity_update_weight_prio(st, entity); + bfq_calc_finish(entity, entity->budget); + bfq_active_insert(st, entity); +} + +/** + * bfq_activate_entity - activate an entity and its ancestors if necessary. + * @entity: the entity to activate. + * + * Activate @entity and all the entities on the path from it to the root. + */ +static void bfq_activate_entity(struct bfq_entity *entity) +{ + struct bfq_sched_data *sd; + + for_each_entity(entity) { + __bfq_activate_entity(entity); + + sd = entity->sched_data; + if (!bfq_update_next_in_service(sd)) + /* + * No need to propagate the activation to the + * upper entities, as they will be updated when + * the in-service entity is rescheduled. + */ + break; + } +} + +/** + * __bfq_deactivate_entity - deactivate an entity from its service tree. + * @entity: the entity to deactivate. + * @requeue: if false, the entity will not be put into the idle tree. + * + * Deactivate an entity, independently from its previous state. If the + * entity was not on a service tree just return, otherwise if it is on + * any scheduler tree, extract it from that tree, and if necessary + * and if the caller did not specify @requeue, put it on the idle tree. + * + * Return %1 if the caller should update the entity hierarchy, i.e., + * if the entity was in service or if it was the next_in_service for + * its sched_data; return %0 otherwise. + */ +static int __bfq_deactivate_entity(struct bfq_entity *entity, int requeue) +{ + struct bfq_sched_data *sd = entity->sched_data; + struct bfq_service_tree *st = bfq_entity_service_tree(entity); + int was_in_service = entity == sd->in_service_entity; + int ret = 0; + + if (!entity->on_st) + return 0; + + BUG_ON(was_in_service && entity->tree != NULL); + + if (was_in_service) { + bfq_calc_finish(entity, entity->service); + sd->in_service_entity = NULL; + } else if (entity->tree == &st->active) + bfq_active_extract(st, entity); + else if (entity->tree == &st->idle) + bfq_idle_extract(st, entity); + else if (entity->tree != NULL) + BUG(); + + if (was_in_service || sd->next_in_service == entity) + ret = bfq_update_next_in_service(sd); + + if (!requeue || !bfq_gt(entity->finish, st->vtime)) + bfq_forget_entity(st, entity); + else + bfq_idle_insert(st, entity); + + BUG_ON(sd->in_service_entity == entity); + BUG_ON(sd->next_in_service == entity); + + return ret; +} + +/** + * bfq_deactivate_entity - deactivate an entity. + * @entity: the entity to deactivate. + * @requeue: true if the entity can be put on the idle tree + */ +static void bfq_deactivate_entity(struct bfq_entity *entity, int requeue) +{ + struct bfq_sched_data *sd; + struct bfq_entity *parent; + + for_each_entity_safe(entity, parent) { + sd = entity->sched_data; + + if (!__bfq_deactivate_entity(entity, requeue)) + /* + * The parent entity is still backlogged, and + * we don't need to update it as it is still + * in service. + */ + break; + + if (sd->next_in_service != NULL) + /* + * The parent entity is still backlogged and + * the budgets on the path towards the root + * need to be updated. + */ + goto update; + + /* + * If we reach there the parent is no more backlogged and + * we want to propagate the dequeue upwards. + */ + requeue = 1; + } + + return; + +update: + entity = parent; + for_each_entity(entity) { + __bfq_activate_entity(entity); + + sd = entity->sched_data; + if (!bfq_update_next_in_service(sd)) + break; + } +} + +/** + * bfq_update_vtime - update vtime if necessary. + * @st: the service tree to act upon. + * + * If necessary update the service tree vtime to have at least one + * eligible entity, skipping to its start time. Assumes that the + * active tree of the device is not empty. + * + * NOTE: this hierarchical implementation updates vtimes quite often, + * we may end up with reactivated processes getting timestamps after a + * vtime skip done because we needed a ->first_active entity on some + * intermediate node. + */ +static void bfq_update_vtime(struct bfq_service_tree *st) +{ + struct bfq_entity *entry; + struct rb_node *node = st->active.rb_node; + + entry = rb_entry(node, struct bfq_entity, rb_node); + if (bfq_gt(entry->min_start, st->vtime)) { + st->vtime = entry->min_start; + bfq_forget_idle(st); + } +} + +/** + * bfq_first_active_entity - find the eligible entity with + * the smallest finish time + * @st: the service tree to select from. + * + * This function searches the first schedulable entity, starting from the + * root of the tree and going on the left every time on this side there is + * a subtree with at least one eligible (start >= vtime) entity. The path on + * the right is followed only if a) the left subtree contains no eligible + * entities and b) no eligible entity has been found yet. + */ +static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st) +{ + struct bfq_entity *entry, *first = NULL; + struct rb_node *node = st->active.rb_node; + + while (node != NULL) { + entry = rb_entry(node, struct bfq_entity, rb_node); +left: + if (!bfq_gt(entry->start, st->vtime)) + first = entry; + + BUG_ON(bfq_gt(entry->min_start, st->vtime)); + + if (node->rb_left != NULL) { + entry = rb_entry(node->rb_left, + struct bfq_entity, rb_node); + if (!bfq_gt(entry->min_start, st->vtime)) { + node = node->rb_left; + goto left; + } + } + if (first != NULL) + break; + node = node->rb_right; + } + + BUG_ON(first == NULL && !RB_EMPTY_ROOT(&st->active)); + return first; +} + +/** + * __bfq_lookup_next_entity - return the first eligible entity in @st. + * @st: the service tree. + * + * Update the virtual time in @st and return the first eligible entity + * it contains. + */ +static struct bfq_entity *__bfq_lookup_next_entity(struct bfq_service_tree *st, + bool force) +{ + struct bfq_entity *entity, *new_next_in_service = NULL; + + if (RB_EMPTY_ROOT(&st->active)) + return NULL; + + bfq_update_vtime(st); + entity = bfq_first_active_entity(st); + BUG_ON(bfq_gt(entity->start, st->vtime)); + + /* + * If the chosen entity does not match with the sched_data's + * next_in_service and we are forcedly serving the IDLE priority + * class tree, bubble up budget update. + */ + if (unlikely(force && entity != entity->sched_data->next_in_service)) { + new_next_in_service = entity; + for_each_entity(new_next_in_service) + bfq_update_budget(new_next_in_service); + } + + return entity; +} + +/** + * bfq_lookup_next_entity - return the first eligible entity in @sd. + * @sd: the sched_data. + * @extract: if true the returned entity will be also extracted from @sd. + * + * NOTE: since we cache the next_in_service entity at each level of the + * hierarchy, the complexity of the lookup can be decreased with + * absolutely no effort just returning the cached next_in_service value; + * we prefer to do full lookups to test the consistency of * the data + * structures. + */ +static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd, + int extract, + struct bfq_data *bfqd) +{ + struct bfq_service_tree *st = sd->service_tree; + struct bfq_entity *entity; + int i = 0; + + BUG_ON(sd->in_service_entity != NULL); + + if (bfqd != NULL && + jiffies - bfqd->bfq_class_idle_last_service > BFQ_CL_IDLE_TIMEOUT) { + entity = __bfq_lookup_next_entity(st + BFQ_IOPRIO_CLASSES - 1, + true); + if (entity != NULL) { + i = BFQ_IOPRIO_CLASSES - 1; + bfqd->bfq_class_idle_last_service = jiffies; + sd->next_in_service = entity; + } + } + for (; i < BFQ_IOPRIO_CLASSES; i++) { + entity = __bfq_lookup_next_entity(st + i, false); + if (entity != NULL) { + if (extract) { + bfq_check_next_in_service(sd, entity); + bfq_active_extract(st + i, entity); + sd->in_service_entity = entity; + sd->next_in_service = NULL; + } + break; + } + } + + return entity; +} + +/* + * Get next queue for service. + */ +static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd) +{ + struct bfq_entity *entity = NULL; + struct bfq_sched_data *sd; + struct bfq_queue *bfqq; + + BUG_ON(bfqd->in_service_queue != NULL); + + if (bfqd->busy_queues == 0) + return NULL; + + sd = &bfqd->root_group->sched_data; + for (; sd != NULL; sd = entity->my_sched_data) { + entity = bfq_lookup_next_entity(sd, 1, bfqd); + BUG_ON(entity == NULL); + entity->service = 0; + } + + bfqq = bfq_entity_to_bfqq(entity); + BUG_ON(bfqq == NULL); + + return bfqq; +} + +static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd) +{ + if (bfqd->in_service_bic != NULL) { + put_io_context(bfqd->in_service_bic->icq.ioc); + bfqd->in_service_bic = NULL; + } + + bfqd->in_service_queue = NULL; + del_timer(&bfqd->idle_slice_timer); +} + +static void bfq_deactivate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, + int requeue) +{ + struct bfq_entity *entity = &bfqq->entity; + + if (bfqq == bfqd->in_service_queue) + __bfq_bfqd_reset_in_service(bfqd); + + bfq_deactivate_entity(entity, requeue); +} + +static void bfq_activate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + + bfq_activate_entity(entity); +} + +/* + * Called when the bfqq no longer has requests pending, remove it from + * the service tree. + */ +static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq, + int requeue) +{ + BUG_ON(!bfq_bfqq_busy(bfqq)); + BUG_ON(!RB_EMPTY_ROOT(&bfqq->sort_list)); + + bfq_log_bfqq(bfqd, bfqq, "del from busy"); + + bfq_clear_bfqq_busy(bfqq); + + BUG_ON(bfqd->busy_queues == 0); + bfqd->busy_queues--; + + if (!bfqq->dispatched) { + bfq_weights_tree_remove(bfqd, &bfqq->entity, + &bfqd->queue_weights_tree); + if (!blk_queue_nonrot(bfqd->queue)) { + BUG_ON(!bfqd->busy_in_flight_queues); + bfqd->busy_in_flight_queues--; + if (bfq_bfqq_constantly_seeky(bfqq)) { + BUG_ON(!bfqd-> + const_seeky_busy_in_flight_queues); + bfqd->const_seeky_busy_in_flight_queues--; + } + } + } + if (bfqq->wr_coeff > 1) + bfqd->wr_busy_queues--; + + bfq_deactivate_bfqq(bfqd, bfqq, requeue); +} + +/* + * Called when an inactive queue receives a new request. + */ +static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + BUG_ON(bfq_bfqq_busy(bfqq)); + BUG_ON(bfqq == bfqd->in_service_queue); + + bfq_log_bfqq(bfqd, bfqq, "add to busy"); + + bfq_activate_bfqq(bfqd, bfqq); + + bfq_mark_bfqq_busy(bfqq); + bfqd->busy_queues++; + + if (!bfqq->dispatched) { + if (bfqq->wr_coeff == 1) + bfq_weights_tree_add(bfqd, &bfqq->entity, + &bfqd->queue_weights_tree); + if (!blk_queue_nonrot(bfqd->queue)) { + bfqd->busy_in_flight_queues++; + if (bfq_bfqq_constantly_seeky(bfqq)) + bfqd->const_seeky_busy_in_flight_queues++; + } + } + if (bfqq->wr_coeff > 1) + bfqd->wr_busy_queues++; +} diff -Nur linux-4.1.13.orig/block/Kconfig.iosched linux-4.1.13/block/Kconfig.iosched --- linux-4.1.13.orig/block/Kconfig.iosched 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/block/Kconfig.iosched 2015-11-30 17:56:13.536140654 +0100 @@ -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-4.1.13.orig/block/Makefile linux-4.1.13/block/Makefile --- linux-4.1.13.orig/block/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/block/Makefile 2015-11-30 17:56:13.536140654 +0100 @@ -18,6 +18,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_CMDLINE_PARSER) += cmdline-parser.o diff -Nur linux-4.1.13.orig/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt linux-4.1.13/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt --- linux-4.1.13.orig/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 2015-11-30 17:56:13.540140388 +0100 @@ -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-4.1.13.orig/Documentation/devicetree/bindings/regulator/ltc3676.txt linux-4.1.13/Documentation/devicetree/bindings/regulator/ltc3676.txt --- linux-4.1.13.orig/Documentation/devicetree/bindings/regulator/ltc3676.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/Documentation/devicetree/bindings/regulator/ltc3676.txt 2015-11-30 17:56:13.540140388 +0100 @@ -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-4.1.13.orig/Documentation/devicetree/bindings/vendor-prefixes.txt linux-4.1.13/Documentation/devicetree/bindings/vendor-prefixes.txt --- linux-4.1.13.orig/Documentation/devicetree/bindings/vendor-prefixes.txt 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/Documentation/devicetree/bindings/vendor-prefixes.txt 2015-11-30 17:56:13.540140388 +0100 @@ -201,6 +201,7 @@ variscite Variscite Ltd. via VIA Technologies, Inc. virtio Virtual I/O Device Specification, developed by the OASIS consortium +vivante Vivante Corporation voipac Voipac Technologies s.r.o. winbond Winbond Electronics corp. wlf Wolfson Microelectronics diff -Nur linux-4.1.13.orig/Documentation/tda1997x linux-4.1.13/Documentation/tda1997x --- linux-4.1.13.orig/Documentation/tda1997x 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/Documentation/tda1997x 2015-11-30 17:56:13.540140388 +0100 @@ -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-4.1.13.orig/drivers/bluetooth/bt3c_cs.c linux-4.1.13/drivers/bluetooth/bt3c_cs.c --- linux-4.1.13.orig/drivers/bluetooth/bt3c_cs.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/bt3c_cs.c 2015-11-30 17:56:13.540140388 +0100 @@ -202,9 +202,8 @@ /* Send frame */ len = bt3c_write(iobase, 256, skb->data, skb->len); - if (len != skb->len) { + if (len != skb->len) BT_ERR("Very strange"); - } kfree_skb(skb); diff -Nur linux-4.1.13.orig/drivers/bluetooth/btbcm.c linux-4.1.13/drivers/bluetooth/btbcm.c --- linux-4.1.13.orig/drivers/bluetooth/btbcm.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btbcm.c 2015-11-30 17:56:13.540140388 +0100 @@ -33,6 +33,7 @@ #define VERSION "0.1" #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) +#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) int btbcm_check_bdaddr(struct hci_dev *hdev) { @@ -55,17 +56,19 @@ } bda = (struct hci_rp_read_bd_addr *)skb->data; - if (bda->status) { - BT_ERR("%s: BCM: Device address result failed (%02x)", - hdev->name, bda->status); - kfree_skb(skb); - return -bt_to_errno(bda->status); - } - /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller + /* Check if the address indicates a controller with either an + * invalid or default address. In both cases the device needs + * to be marked as not having a valid address. + * + * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller * with no configured address. + * + * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller + * with waiting for configuration state. */ - if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) { + if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || + !bacmp(&bda->bdaddr, BDADDR_BCM4324B3)) { BT_INFO("%s: BCM: Using default device address (%pMR)", hdev->name, &bda->bdaddr); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); @@ -95,21 +98,14 @@ } EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); -int btbcm_patchram(struct hci_dev *hdev, const char *firmware) +int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw) { const struct hci_command_hdr *cmd; - const struct firmware *fw; const u8 *fw_ptr; size_t fw_size; struct sk_buff *skb; u16 opcode; - int err; - - err = request_firmware(&fw, firmware, &hdev->dev); - if (err < 0) { - BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware); - return err; - } + int err = 0; /* Start Download */ skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); @@ -135,8 +131,7 @@ fw_size -= sizeof(*cmd); if (fw_size < cmd->plen) { - BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name, - firmware); + BT_ERR("%s: BCM: Patch is corrupted", hdev->name); err = -EINVAL; goto done; } @@ -162,7 +157,6 @@ msleep(250); done: - release_firmware(fw); return err; } EXPORT_SYMBOL(btbcm_patchram); @@ -248,9 +242,101 @@ const char *name; } bcm_uart_subver_table[] = { { 0x410e, "BCM43341B0" }, /* 002.001.014 */ + { 0x4406, "BCM4324B3" }, /* 002.004.006 */ + { 0x610c, "BCM4354" }, /* 003.001.012 */ { } }; +int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len) +{ + u16 subver, rev; + const char *hw_name = NULL; + struct sk_buff *skb; + struct hci_rp_read_local_version *ver; + int i, err; + + /* Reset */ + err = btbcm_reset(hdev); + if (err) + return err; + + /* Read Local Version Info */ + skb = btbcm_read_local_version(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ver = (struct hci_rp_read_local_version *)skb->data; + rev = le16_to_cpu(ver->hci_rev); + subver = le16_to_cpu(ver->lmp_subver); + kfree_skb(skb); + + /* Read Verbose Config Version Info */ + skb = btbcm_read_verbose_config(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]); + kfree_skb(skb); + + switch ((rev & 0xf000) >> 12) { + case 0: + case 1: + case 3: + for (i = 0; bcm_uart_subver_table[i].name; i++) { + if (subver == bcm_uart_subver_table[i].subver) { + hw_name = bcm_uart_subver_table[i].name; + break; + } + } + + snprintf(fw_name, len, "brcm/%s.hcd", hw_name ? : "BCM"); + break; + default: + return 0; + } + + BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name, + hw_name ? : "BCM", (subver & 0x7000) >> 13, + (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_initialize); + +int btbcm_finalize(struct hci_dev *hdev) +{ + struct sk_buff *skb; + struct hci_rp_read_local_version *ver; + u16 subver, rev; + int err; + + /* Reset */ + err = btbcm_reset(hdev); + if (err) + return err; + + /* Read Local Version Info */ + skb = btbcm_read_local_version(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ver = (struct hci_rp_read_local_version *)skb->data; + rev = le16_to_cpu(ver->hci_rev); + subver = le16_to_cpu(ver->lmp_subver); + kfree_skb(skb); + + BT_INFO("%s: BCM (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name, + (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8, + (subver & 0x00ff), rev & 0x0fff); + + btbcm_check_bdaddr(hdev); + + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_finalize); + static const struct { u16 subver; const char *name; @@ -271,6 +357,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev) { char fw_name[64]; + const struct firmware *fw; u16 subver, rev, pid, vid; const char *hw_name = NULL; struct sk_buff *skb; @@ -302,6 +389,7 @@ switch ((rev & 0xf000) >> 12) { case 0: + case 3: for (i = 0; bcm_uart_subver_table[i].name; i++) { if (subver == bcm_uart_subver_table[i].subver) { hw_name = bcm_uart_subver_table[i].name; @@ -341,9 +429,15 @@ hw_name ? : "BCM", (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); - err = btbcm_patchram(hdev, fw_name); - if (err == -ENOENT) + err = request_firmware(&fw, fw_name, &hdev->dev); + if (err < 0) { + BT_INFO("%s: BCM: Patch %s not found", hdev->name, fw_name); return 0; + } + + btbcm_patchram(hdev, fw); + + release_firmware(fw); /* Reset */ err = btbcm_reset(hdev); diff -Nur linux-4.1.13.orig/drivers/bluetooth/btbcm.h linux-4.1.13/drivers/bluetooth/btbcm.h --- linux-4.1.13.orig/drivers/bluetooth/btbcm.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btbcm.h 2015-11-30 17:56:13.540140388 +0100 @@ -21,15 +21,61 @@ * */ +#define BCM_UART_CLOCK_48MHZ 0x01 +#define BCM_UART_CLOCK_24MHZ 0x02 + +struct bcm_update_uart_baud_rate { + __le16 zero; + __le32 baud_rate; +} __packed; + +struct bcm_write_uart_clock_setting { + __u8 type; +} __packed; + +struct bcm_set_sleep_mode { + __u8 sleep_mode; + __u8 idle_host; + __u8 idle_dev; + __u8 bt_wake_active; + __u8 host_wake_active; + __u8 allow_host_sleep; + __u8 combine_modes; + __u8 tristate_control; + __u8 usb_auto_sleep; + __u8 usb_resume_timeout; + __u8 pulsed_host_wake; + __u8 break_to_host; +} __packed; + +struct bcm_set_pcm_int_params { + __u8 routing; + __u8 rate; + __u8 frame_sync; + __u8 sync_mode; + __u8 clock_mode; +} __packed; + +struct bcm_set_pcm_format_params { + __u8 lsb_first; + __u8 fill_value; + __u8 fill_method; + __u8 fill_num; + __u8 right_justify; +} __packed; + #if IS_ENABLED(CONFIG_BT_BCM) int btbcm_check_bdaddr(struct hci_dev *hdev); int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); -int btbcm_patchram(struct hci_dev *hdev, const char *firmware); +int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw); int btbcm_setup_patchram(struct hci_dev *hdev); int btbcm_setup_apple(struct hci_dev *hdev); +int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len); +int btbcm_finalize(struct hci_dev *hdev); + #else static inline int btbcm_check_bdaddr(struct hci_dev *hdev) @@ -42,7 +88,7 @@ return -EOPNOTSUPP; } -static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware) +static inline int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw) { return -EOPNOTSUPP; } @@ -56,5 +102,16 @@ { return 0; } + +static inline int btbcm_initialize(struct hci_dev *hdev, char *fw_name, + size_t len) +{ + return 0; +} + +static inline int btbcm_finalize(struct hci_dev *hdev) +{ + return 0; +} #endif diff -Nur linux-4.1.13.orig/drivers/bluetooth/btintel.c linux-4.1.13/drivers/bluetooth/btintel.c --- linux-4.1.13.orig/drivers/bluetooth/btintel.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btintel.c 2015-11-30 17:56:13.540140388 +0100 @@ -53,12 +53,6 @@ } bda = (struct hci_rp_read_bd_addr *)skb->data; - if (bda->status) { - BT_ERR("%s: Intel device address result failed (%02x)", - hdev->name, bda->status); - kfree_skb(skb); - return -bt_to_errno(bda->status); - } /* For some Intel based controllers, the default Bluetooth device * address 00:03:19:9E:8B:00 can be found. These controllers are diff -Nur linux-4.1.13.orig/drivers/bluetooth/btmrvl_sdio.c linux-4.1.13/drivers/bluetooth/btmrvl_sdio.c --- linux-4.1.13.orig/drivers/bluetooth/btmrvl_sdio.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btmrvl_sdio.c 2015-11-30 17:56:13.540140388 +0100 @@ -1217,7 +1217,7 @@ unsigned int reg, reg_start, reg_end; enum rdwr_status stat; u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr; - u8 dump_num, idx, i, read_reg, doneflag = 0; + u8 dump_num = 0, idx, i, read_reg, doneflag = 0; u32 memory_size, fw_dump_len = 0; /* dump sdio register first */ diff -Nur linux-4.1.13.orig/drivers/bluetooth/btrtl.c linux-4.1.13/drivers/bluetooth/btrtl.c --- linux-4.1.13.orig/drivers/bluetooth/btrtl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btrtl.c 2015-11-30 17:56:13.540140388 +0100 @@ -0,0 +1,390 @@ +/* + * Bluetooth support for Realtek devices + * + * Copyright (C) 2015 Endless Mobile, 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. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "btrtl.h" + +#define VERSION "0.1" + +#define RTL_EPATCH_SIGNATURE "Realtech" +#define RTL_ROM_LMP_3499 0x3499 +#define RTL_ROM_LMP_8723A 0x1200 +#define RTL_ROM_LMP_8723B 0x8723 +#define RTL_ROM_LMP_8821A 0x8821 +#define RTL_ROM_LMP_8761A 0x8761 + +static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) +{ + struct rtl_rom_version_evt *rom_version; + struct sk_buff *skb; + + /* Read RTL ROM version command */ + skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Read ROM version failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*rom_version)) { + BT_ERR("%s: RTL version event length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + rom_version = (struct rtl_rom_version_evt *)skb->data; + BT_INFO("%s: rom_version status=%x version=%x", + hdev->name, rom_version->status, rom_version->version); + + *version = rom_version->version; + + kfree_skb(skb); + return 0; +} + +static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, + const struct firmware *fw, + unsigned char **_buf) +{ + const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; + struct rtl_epatch_header *epatch_info; + unsigned char *buf; + int i, ret, len; + size_t min_size; + u8 opcode, length, data, rom_version = 0; + int project_id = -1; + const unsigned char *fwptr, *chip_id_base; + const unsigned char *patch_length_base, *patch_offset_base; + u32 patch_offset = 0; + u16 patch_length, num_patches; + const u16 project_id_to_lmp_subver[] = { + RTL_ROM_LMP_8723A, + RTL_ROM_LMP_8723B, + RTL_ROM_LMP_8821A, + RTL_ROM_LMP_8761A + }; + + ret = rtl_read_rom_version(hdev, &rom_version); + if (ret) + return ret; + + min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; + if (fw->size < min_size) + return -EINVAL; + + fwptr = fw->data + fw->size - sizeof(extension_sig); + if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { + BT_ERR("%s: extension section signature mismatch", hdev->name); + return -EINVAL; + } + + /* Loop from the end of the firmware parsing instructions, until + * we find an instruction that identifies the "project ID" for the + * hardware supported by this firwmare file. + * Once we have that, we double-check that that project_id is suitable + * for the hardware we are working with. + */ + while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { + opcode = *--fwptr; + length = *--fwptr; + data = *--fwptr; + + BT_DBG("check op=%x len=%x data=%x", opcode, length, data); + + if (opcode == 0xff) /* EOF */ + break; + + if (length == 0) { + BT_ERR("%s: found instruction with length 0", + hdev->name); + return -EINVAL; + } + + if (opcode == 0 && length == 1) { + project_id = data; + break; + } + + fwptr -= length; + } + + if (project_id < 0) { + BT_ERR("%s: failed to find version instruction", hdev->name); + return -EINVAL; + } + + if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { + BT_ERR("%s: unknown project id %d", hdev->name, project_id); + return -EINVAL; + } + + if (lmp_subver != project_id_to_lmp_subver[project_id]) { + BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, + project_id_to_lmp_subver[project_id], lmp_subver); + return -EINVAL; + } + + epatch_info = (struct rtl_epatch_header *)fw->data; + if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { + BT_ERR("%s: bad EPATCH signature", hdev->name); + return -EINVAL; + } + + num_patches = le16_to_cpu(epatch_info->num_patches); + BT_DBG("fw_version=%x, num_patches=%d", + le32_to_cpu(epatch_info->fw_version), num_patches); + + /* After the rtl_epatch_header there is a funky patch metadata section. + * Assuming 2 patches, the layout is: + * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2 + * + * Find the right patch for this chip. + */ + min_size += 8 * num_patches; + if (fw->size < min_size) + return -EINVAL; + + chip_id_base = fw->data + sizeof(struct rtl_epatch_header); + patch_length_base = chip_id_base + (sizeof(u16) * num_patches); + patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); + for (i = 0; i < num_patches; i++) { + u16 chip_id = get_unaligned_le16(chip_id_base + + (i * sizeof(u16))); + if (chip_id == rom_version + 1) { + patch_length = get_unaligned_le16(patch_length_base + + (i * sizeof(u16))); + patch_offset = get_unaligned_le32(patch_offset_base + + (i * sizeof(u32))); + break; + } + } + + if (!patch_offset) { + BT_ERR("%s: didn't find patch for chip id %d", + hdev->name, rom_version); + return -EINVAL; + } + + BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); + min_size = patch_offset + patch_length; + if (fw->size < min_size) + return -EINVAL; + + /* Copy the firmware into a new buffer and write the version at + * the end. + */ + len = patch_length; + buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4); + + *_buf = buf; + return len; +} + +static int rtl_download_firmware(struct hci_dev *hdev, + const unsigned char *data, int fw_len) +{ + struct rtl_download_cmd *dl_cmd; + int frag_num = fw_len / RTL_FRAG_LEN + 1; + int frag_len = RTL_FRAG_LEN; + int ret = 0; + int i; + + dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); + if (!dl_cmd) + return -ENOMEM; + + for (i = 0; i < frag_num; i++) { + struct sk_buff *skb; + + BT_DBG("download fw (%d/%d)", i, frag_num); + + dl_cmd->index = i; + if (i == (frag_num - 1)) { + dl_cmd->index |= 0x80; /* data end */ + frag_len = fw_len % RTL_FRAG_LEN; + } + memcpy(dl_cmd->data, data, frag_len); + + /* Send download command */ + skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: download fw command failed (%ld)", + hdev->name, PTR_ERR(skb)); + ret = -PTR_ERR(skb); + goto out; + } + + if (skb->len != sizeof(struct rtl_download_response)) { + BT_ERR("%s: download fw event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto out; + } + + kfree_skb(skb); + data += RTL_FRAG_LEN; + } + +out: + kfree(dl_cmd); + return ret; +} + +static int btrtl_setup_rtl8723a(struct hci_dev *hdev) +{ + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name); + ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); + return ret; + } + + if (fw->size < 8) { + ret = -EINVAL; + goto out; + } + + /* Check that the firmware doesn't have the epatch signature + * (which is only for RTL8723B and newer). + */ + if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { + BT_ERR("%s: unexpected EPATCH signature!", hdev->name); + ret = -EINVAL; + goto out; + } + + ret = rtl_download_firmware(hdev, fw->data, fw->size); + +out: + release_firmware(fw); + return ret; +} + +static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, + const char *fw_name) +{ + unsigned char *fw_data = NULL; + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); + ret = request_firmware(&fw, fw_name, &hdev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load %s", hdev->name, fw_name); + return ret; + } + + ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); + if (ret < 0) + goto out; + + ret = rtl_download_firmware(hdev, fw_data, ret); + kfree(fw_data); + if (ret < 0) + goto out; + +out: + release_firmware(fw); + return ret; +} + +static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != sizeof(struct hci_rp_read_local_version)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", + hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + +int btrtl_setup_realtek(struct hci_dev *hdev) +{ + struct sk_buff *skb; + struct hci_rp_read_local_version *resp; + u16 lmp_subver; + + skb = btrtl_read_local_version(hdev); + if (IS_ERR(skb)) + return -PTR_ERR(skb); + + resp = (struct hci_rp_read_local_version *)skb->data; + BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x " + "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev, + resp->lmp_ver, resp->lmp_subver); + + lmp_subver = le16_to_cpu(resp->lmp_subver); + kfree_skb(skb); + + /* Match a set of subver values that correspond to stock firmware, + * which is not compatible with standard btusb. + * If matched, upload an alternative firmware that does conform to + * standard btusb. Once that firmware is uploaded, the subver changes + * to a different value. + */ + switch (lmp_subver) { + case RTL_ROM_LMP_8723A: + case RTL_ROM_LMP_3499: + return btrtl_setup_rtl8723a(hdev); + case RTL_ROM_LMP_8723B: + return btrtl_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8723b_fw.bin"); + case RTL_ROM_LMP_8821A: + return btrtl_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8821a_fw.bin"); + case RTL_ROM_LMP_8761A: + return btrtl_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8761a_fw.bin"); + default: + BT_INFO("rtl: assuming no firmware upload needed."); + return 0; + } +} +EXPORT_SYMBOL_GPL(btrtl_setup_realtek); + +MODULE_AUTHOR("Daniel Drake "); +MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff -Nur linux-4.1.13.orig/drivers/bluetooth/btrtl.h linux-4.1.13/drivers/bluetooth/btrtl.h --- linux-4.1.13.orig/drivers/bluetooth/btrtl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btrtl.h 2015-11-30 17:56:13.540140388 +0100 @@ -0,0 +1,52 @@ +/* + * Bluetooth support for Realtek devices + * + * Copyright (C) 2015 Endless Mobile, 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. + * + */ + +#define RTL_FRAG_LEN 252 + +struct rtl_download_cmd { + __u8 index; + __u8 data[RTL_FRAG_LEN]; +} __packed; + +struct rtl_download_response { + __u8 status; + __u8 index; +} __packed; + +struct rtl_rom_version_evt { + __u8 status; + __u8 version; +} __packed; + +struct rtl_epatch_header { + __u8 signature[8]; + __le32 fw_version; + __le16 num_patches; +} __packed; + +#if IS_ENABLED(CONFIG_BT_RTL) + +int btrtl_setup_realtek(struct hci_dev *hdev); + +#else + +static inline int btrtl_setup_realtek(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + +#endif diff -Nur linux-4.1.13.orig/drivers/bluetooth/btusb.c linux-4.1.13/drivers/bluetooth/btusb.c --- linux-4.1.13.orig/drivers/bluetooth/btusb.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btusb.c 2015-11-30 17:56:13.540140388 +0100 @@ -31,13 +31,14 @@ #include "btintel.h" #include "btbcm.h" +#include "btrtl.h" #define VERSION "0.8" static bool disable_scofix; static bool force_scofix; -static bool reset = 1; +static bool reset = true; static struct usb_driver btusb_driver; @@ -333,6 +334,7 @@ #define BTUSB_FIRMWARE_LOADED 7 #define BTUSB_FIRMWARE_FAILED 8 #define BTUSB_BOOTING 9 +#define BTUSB_RESET_RESUME 10 struct btusb_data { struct hci_dev *hdev; @@ -1301,28 +1303,6 @@ usb_autopm_put_interface(data->intf); } -static struct sk_buff *btusb_read_local_version(struct hci_dev *hdev) -{ - struct sk_buff *skb; - - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, PTR_ERR(skb)); - return skb; - } - - if (skb->len != sizeof(struct hci_rp_read_local_version)) { - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); - kfree_skb(skb); - return ERR_PTR(-EIO); - } - - return skb; -} - static int btusb_setup_bcm92035(struct hci_dev *hdev) { struct sk_buff *skb; @@ -1343,408 +1323,40 @@ { struct hci_rp_read_local_version *rp; struct sk_buff *skb; - int ret; BT_DBG("%s", hdev->name); - skb = btusb_read_local_version(hdev); - if (IS_ERR(skb)) - return -PTR_ERR(skb); - - rp = (struct hci_rp_read_local_version *)skb->data; - - if (!rp->status) { - if (le16_to_cpu(rp->manufacturer) != 10) { - /* Clear the reset quirk since this is not an actual - * early Bluetooth 1.1 device from CSR. - */ - clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); - - /* These fake CSR controllers have all a broken - * stored link key handling and so just disable it. - */ - set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, - &hdev->quirks); - } - } - - ret = -bt_to_errno(rp->status); - - kfree_skb(skb); - - return ret; -} - -#define RTL_FRAG_LEN 252 - -struct rtl_download_cmd { - __u8 index; - __u8 data[RTL_FRAG_LEN]; -} __packed; - -struct rtl_download_response { - __u8 status; - __u8 index; -} __packed; - -struct rtl_rom_version_evt { - __u8 status; - __u8 version; -} __packed; - -struct rtl_epatch_header { - __u8 signature[8]; - __le32 fw_version; - __le16 num_patches; -} __packed; - -#define RTL_EPATCH_SIGNATURE "Realtech" -#define RTL_ROM_LMP_3499 0x3499 -#define RTL_ROM_LMP_8723A 0x1200 -#define RTL_ROM_LMP_8723B 0x8723 -#define RTL_ROM_LMP_8821A 0x8821 -#define RTL_ROM_LMP_8761A 0x8761 - -static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) -{ - struct rtl_rom_version_evt *rom_version; - struct sk_buff *skb; - int ret; - - /* Read RTL ROM version command */ - skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { - BT_ERR("%s: Read ROM version failed (%ld)", - hdev->name, PTR_ERR(skb)); - return PTR_ERR(skb); + int err = PTR_ERR(skb); + BT_ERR("%s: CSR: Local version failed (%d)", hdev->name, err); + return err; } - if (skb->len != sizeof(*rom_version)) { - BT_ERR("%s: RTL version event length mismatch", hdev->name); + if (skb->len != sizeof(struct hci_rp_read_local_version)) { + BT_ERR("%s: CSR: Local version length mismatch", hdev->name); kfree_skb(skb); return -EIO; } - rom_version = (struct rtl_rom_version_evt *)skb->data; - BT_INFO("%s: rom_version status=%x version=%x", - hdev->name, rom_version->status, rom_version->version); - - ret = rom_version->status; - if (ret == 0) - *version = rom_version->version; - - kfree_skb(skb); - return ret; -} - -static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, - const struct firmware *fw, - unsigned char **_buf) -{ - const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; - struct rtl_epatch_header *epatch_info; - unsigned char *buf; - int i, ret, len; - size_t min_size; - u8 opcode, length, data, rom_version = 0; - int project_id = -1; - const unsigned char *fwptr, *chip_id_base; - const unsigned char *patch_length_base, *patch_offset_base; - u32 patch_offset = 0; - u16 patch_length, num_patches; - const u16 project_id_to_lmp_subver[] = { - RTL_ROM_LMP_8723A, - RTL_ROM_LMP_8723B, - RTL_ROM_LMP_8821A, - RTL_ROM_LMP_8761A - }; - - ret = rtl_read_rom_version(hdev, &rom_version); - if (ret) - return -bt_to_errno(ret); - - min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; - if (fw->size < min_size) - return -EINVAL; - - fwptr = fw->data + fw->size - sizeof(extension_sig); - if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { - BT_ERR("%s: extension section signature mismatch", hdev->name); - return -EINVAL; - } - - /* Loop from the end of the firmware parsing instructions, until - * we find an instruction that identifies the "project ID" for the - * hardware supported by this firwmare file. - * Once we have that, we double-check that that project_id is suitable - * for the hardware we are working with. - */ - while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { - opcode = *--fwptr; - length = *--fwptr; - data = *--fwptr; - - BT_DBG("check op=%x len=%x data=%x", opcode, length, data); - - if (opcode == 0xff) /* EOF */ - break; - - if (length == 0) { - BT_ERR("%s: found instruction with length 0", - hdev->name); - return -EINVAL; - } - - if (opcode == 0 && length == 1) { - project_id = data; - break; - } - - fwptr -= length; - } - - if (project_id < 0) { - BT_ERR("%s: failed to find version instruction", hdev->name); - return -EINVAL; - } - - if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { - BT_ERR("%s: unknown project id %d", hdev->name, project_id); - return -EINVAL; - } - - if (lmp_subver != project_id_to_lmp_subver[project_id]) { - BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, - project_id_to_lmp_subver[project_id], lmp_subver); - return -EINVAL; - } - - epatch_info = (struct rtl_epatch_header *)fw->data; - if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { - BT_ERR("%s: bad EPATCH signature", hdev->name); - return -EINVAL; - } - - num_patches = le16_to_cpu(epatch_info->num_patches); - BT_DBG("fw_version=%x, num_patches=%d", - le32_to_cpu(epatch_info->fw_version), num_patches); - - /* After the rtl_epatch_header there is a funky patch metadata section. - * Assuming 2 patches, the layout is: - * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2 - * - * Find the right patch for this chip. - */ - min_size += 8 * num_patches; - if (fw->size < min_size) - return -EINVAL; - - chip_id_base = fw->data + sizeof(struct rtl_epatch_header); - patch_length_base = chip_id_base + (sizeof(u16) * num_patches); - patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); - for (i = 0; i < num_patches; i++) { - u16 chip_id = get_unaligned_le16(chip_id_base + - (i * sizeof(u16))); - if (chip_id == rom_version + 1) { - patch_length = get_unaligned_le16(patch_length_base + - (i * sizeof(u16))); - patch_offset = get_unaligned_le32(patch_offset_base + - (i * sizeof(u32))); - break; - } - } - - if (!patch_offset) { - BT_ERR("%s: didn't find patch for chip id %d", - hdev->name, rom_version); - return -EINVAL; - } - - BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); - min_size = patch_offset + patch_length; - if (fw->size < min_size) - return -EINVAL; - - /* Copy the firmware into a new buffer and write the version at - * the end. - */ - len = patch_length; - buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4); - - *_buf = buf; - return len; -} - -static int rtl_download_firmware(struct hci_dev *hdev, - const unsigned char *data, int fw_len) -{ - struct rtl_download_cmd *dl_cmd; - int frag_num = fw_len / RTL_FRAG_LEN + 1; - int frag_len = RTL_FRAG_LEN; - int ret = 0; - int i; - - dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); - if (!dl_cmd) - return -ENOMEM; - - for (i = 0; i < frag_num; i++) { - struct rtl_download_response *dl_resp; - struct sk_buff *skb; - - BT_DBG("download fw (%d/%d)", i, frag_num); - - dl_cmd->index = i; - if (i == (frag_num - 1)) { - dl_cmd->index |= 0x80; /* data end */ - frag_len = fw_len % RTL_FRAG_LEN; - } - memcpy(dl_cmd->data, data, frag_len); - - /* Send download command */ - skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: download fw command failed (%ld)", - hdev->name, PTR_ERR(skb)); - ret = -PTR_ERR(skb); - goto out; - } - - if (skb->len != sizeof(*dl_resp)) { - BT_ERR("%s: download fw event length mismatch", - hdev->name); - kfree_skb(skb); - ret = -EIO; - goto out; - } - - dl_resp = (struct rtl_download_response *)skb->data; - if (dl_resp->status != 0) { - kfree_skb(skb); - ret = bt_to_errno(dl_resp->status); - goto out; - } - - kfree_skb(skb); - data += RTL_FRAG_LEN; - } - -out: - kfree(dl_cmd); - return ret; -} - -static int btusb_setup_rtl8723a(struct hci_dev *hdev) -{ - struct btusb_data *data = dev_get_drvdata(&hdev->dev); - struct usb_device *udev = interface_to_usbdev(data->intf); - const struct firmware *fw; - int ret; - - BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name); - ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &udev->dev); - if (ret < 0) { - BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); - return ret; - } - - if (fw->size < 8) { - ret = -EINVAL; - goto out; - } - - /* Check that the firmware doesn't have the epatch signature - * (which is only for RTL8723B and newer). - */ - if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { - BT_ERR("%s: unexpected EPATCH signature!", hdev->name); - ret = -EINVAL; - goto out; - } - - ret = rtl_download_firmware(hdev, fw->data, fw->size); - -out: - release_firmware(fw); - return ret; -} + rp = (struct hci_rp_read_local_version *)skb->data; -static int btusb_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, - const char *fw_name) -{ - struct btusb_data *data = dev_get_drvdata(&hdev->dev); - struct usb_device *udev = interface_to_usbdev(data->intf); - unsigned char *fw_data = NULL; - const struct firmware *fw; - int ret; + if (le16_to_cpu(rp->manufacturer) != 10) { + /* Clear the reset quirk since this is not an actual + * early Bluetooth 1.1 device from CSR. + */ + clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); - BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); - ret = request_firmware(&fw, fw_name, &udev->dev); - if (ret < 0) { - BT_ERR("%s: Failed to load %s", hdev->name, fw_name); - return ret; + /* These fake CSR controllers have all a broken + * stored link key handling and so just disable it. + */ + set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks); } - ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); - if (ret < 0) - goto out; - - ret = rtl_download_firmware(hdev, fw_data, ret); - kfree(fw_data); - if (ret < 0) - goto out; - -out: - release_firmware(fw); - return ret; -} - -static int btusb_setup_realtek(struct hci_dev *hdev) -{ - struct sk_buff *skb; - struct hci_rp_read_local_version *resp; - u16 lmp_subver; - - skb = btusb_read_local_version(hdev); - if (IS_ERR(skb)) - return -PTR_ERR(skb); - - resp = (struct hci_rp_read_local_version *)skb->data; - BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x " - "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev, - resp->lmp_ver, resp->lmp_subver); - - lmp_subver = le16_to_cpu(resp->lmp_subver); kfree_skb(skb); - /* Match a set of subver values that correspond to stock firmware, - * which is not compatible with standard btusb. - * If matched, upload an alternative firmware that does conform to - * standard btusb. Once that firmware is uploaded, the subver changes - * to a different value. - */ - switch (lmp_subver) { - case RTL_ROM_LMP_8723A: - case RTL_ROM_LMP_3499: - return btusb_setup_rtl8723a(hdev); - case RTL_ROM_LMP_8723B: - return btusb_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8723b_fw.bin"); - case RTL_ROM_LMP_8821A: - return btusb_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8821a_fw.bin"); - case RTL_ROM_LMP_8761A: - return btusb_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8761a_fw.bin"); - default: - BT_INFO("rtl: assuming no firmware upload needed."); - return 0; - } + return 0; } static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, @@ -1954,12 +1566,6 @@ } ver = (struct intel_version *)skb->data; - if (ver->status) { - BT_ERR("%s Intel fw version event failed (%02x)", hdev->name, - ver->status); - kfree_skb(skb); - return -bt_to_errno(ver->status); - } BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x", hdev->name, ver->hw_platform, ver->hw_variant, @@ -2009,15 +1615,6 @@ return PTR_ERR(skb); } - if (skb->data[0]) { - u8 evt_status = skb->data[0]; - - BT_ERR("%s enable Intel manufacturer mode event failed (%02x)", - hdev->name, evt_status); - kfree_skb(skb); - release_firmware(fw); - return -bt_to_errno(evt_status); - } kfree_skb(skb); disable_patch = 1; @@ -2364,13 +1961,6 @@ } ver = (struct intel_version *)skb->data; - if (ver->status) { - BT_ERR("%s: Intel version command failure (%02x)", - hdev->name, ver->status); - err = -bt_to_errno(ver->status); - kfree_skb(skb); - return err; - } /* The hardware platform number has a fixed value of 0x37 and * for now only accept this single value. @@ -2445,13 +2035,6 @@ } params = (struct intel_boot_params *)skb->data; - if (params->status) { - BT_ERR("%s: Intel boot parameters command failure (%02x)", - hdev->name, params->status); - err = -bt_to_errno(params->status); - kfree_skb(skb); - return err; - } BT_INFO("%s: Device revision is %u", hdev->name, le16_to_cpu(params->dev_revid)); @@ -2501,6 +2084,12 @@ BT_INFO("%s: Found device firmware: %s", hdev->name, fwname); + /* Save the DDC file name for later use to apply once the firmware + * downloading is done. + */ + snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc", + le16_to_cpu(params->dev_revid)); + kfree_skb(skb); if (fw->size < 644) { @@ -2662,6 +2251,43 @@ clear_bit(BTUSB_BOOTLOADER, &data->flags); + /* Once the device is running in operational mode, it needs to apply + * the device configuration (DDC) parameters. + * + * The device can work without DDC parameters, so even if it fails + * to load the file, no need to fail the setup. + */ + err = request_firmware_direct(&fw, fwname, &hdev->dev); + if (err < 0) + return 0; + + BT_INFO("%s: Found Intel DDC parameters: %s", hdev->name, fwname); + + fw_ptr = fw->data; + + /* DDC file contains one or more DDC structure which has + * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). + */ + while (fw->size > fw_ptr - fw->data) { + u8 cmd_plen = fw_ptr[0] + sizeof(u8); + + skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Failed to send Intel_Write_DDC (%ld)", + hdev->name, PTR_ERR(skb)); + release_firmware(fw); + return PTR_ERR(skb); + } + + fw_ptr += cmd_plen; + kfree_skb(skb); + } + + release_firmware(fw); + + BT_INFO("%s: Applying Intel DDC parameters completed", hdev->name); + return 0; } @@ -2693,13 +2319,6 @@ return; } - if (skb->data[0] != 0x00) { - BT_ERR("%s: Exception info command failure (%02x)", - hdev->name, skb->data[0]); - kfree_skb(skb); - return; - } - BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); kfree_skb(skb); @@ -2807,6 +2426,7 @@ static const struct qca_device_info qca_devices_table[] = { { 0x00000100, 20, 4, 10 }, /* Rome 1.0 */ { 0x00000101, 20, 4, 10 }, /* Rome 1.1 */ + { 0x00000200, 28, 4, 18 }, /* Rome 2.0 */ { 0x00000201, 28, 4, 18 }, /* Rome 2.1 */ { 0x00000300, 28, 4, 18 }, /* Rome 3.0 */ { 0x00000302, 28, 4, 18 }, /* Rome 3.2 */ @@ -3190,8 +2810,17 @@ hdev->set_bdaddr = btusb_set_bdaddr_ath3012; } - if (id->driver_info & BTUSB_REALTEK) - hdev->setup = btusb_setup_realtek; +#ifdef CONFIG_BT_HCIBTUSB_RTL + if (id->driver_info & BTUSB_REALTEK) { + hdev->setup = btrtl_setup_realtek; + + /* Realtek devices lose their updated firmware over suspend, + * but the USB hub doesn't notice any status change. + * Explicitly request a device reset on resume. + */ + set_bit(BTUSB_RESET_RESUME, &data->flags); + } +#endif if (id->driver_info & BTUSB_AMP) { /* AMP controllers do not support SCO packets */ @@ -3323,6 +2952,14 @@ btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); + /* Optionally request a device reset on resume, but only when + * wakeups are disabled. If wakeups are enabled we assume the + * device will stay powered up throughout suspend. + */ + if (test_bit(BTUSB_RESET_RESUME, &data->flags) && + !device_may_wakeup(&data->udev->dev)) + data->udev->reset_resume = 1; + return 0; } diff -Nur linux-4.1.13.orig/drivers/bluetooth/btwilink.c linux-4.1.13/drivers/bluetooth/btwilink.c --- linux-4.1.13.orig/drivers/bluetooth/btwilink.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/btwilink.c 2015-11-30 17:56:13.540140388 +0100 @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#define DEBUG + #include #include #include diff -Nur linux-4.1.13.orig/drivers/bluetooth/hci_ath.c linux-4.1.13/drivers/bluetooth/hci_ath.c --- linux-4.1.13.orig/drivers/bluetooth/hci_ath.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/hci_ath.c 2015-11-30 17:56:13.540140388 +0100 @@ -192,6 +192,7 @@ if (IS_ERR(ath->rx_skb)) { int err = PTR_ERR(ath->rx_skb); BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + ath->rx_skb = NULL; return err; } diff -Nur linux-4.1.13.orig/drivers/bluetooth/hci_bcm.c linux-4.1.13/drivers/bluetooth/hci_bcm.c --- linux-4.1.13.orig/drivers/bluetooth/hci_bcm.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/hci_bcm.c 2015-11-30 17:56:13.540140388 +0100 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,55 @@ struct sk_buff_head txq; }; +static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) +{ + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + struct bcm_update_uart_baud_rate param; + + if (speed > 3000000) { + struct bcm_write_uart_clock_setting clock; + + clock.type = BCM_UART_CLOCK_48MHZ; + + BT_DBG("%s: Set Controller clock (%d)", hdev->name, clock.type); + + /* This Broadcom specific command changes the UART's controller + * clock for baud rate > 3000000. + */ + skb = __hci_cmd_sync(hdev, 0xfc45, 1, &clock, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + int err = PTR_ERR(skb); + BT_ERR("%s: BCM: failed to write clock command (%d)", + hdev->name, err); + return err; + } + + kfree_skb(skb); + } + + BT_DBG("%s: Set Controller UART speed to %d bit/s", hdev->name, speed); + + param.zero = cpu_to_le16(0); + param.baud_rate = cpu_to_le32(speed); + + /* This Broadcom specific command changes the UART's controller baud + * rate. + */ + skb = __hci_cmd_sync(hdev, 0xfc18, sizeof(param), ¶m, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + int err = PTR_ERR(skb); + BT_ERR("%s: BCM: failed to write update baudrate command (%d)", + hdev->name, err); + return err; + } + + kfree_skb(skb); + + return 0; +} + static int bcm_open(struct hci_uart *hu) { struct bcm_data *bcm; @@ -79,11 +129,62 @@ static int bcm_setup(struct hci_uart *hu) { + char fw_name[64]; + const struct firmware *fw; + unsigned int speed; + int err; + BT_DBG("hu %p", hu); hu->hdev->set_bdaddr = btbcm_set_bdaddr; - return btbcm_setup_patchram(hu->hdev); + err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name)); + if (err) + return err; + + err = request_firmware(&fw, fw_name, &hu->hdev->dev); + if (err < 0) { + BT_INFO("%s: BCM: Patch %s not found", hu->hdev->name, fw_name); + return 0; + } + + err = btbcm_patchram(hu->hdev, fw); + if (err) { + BT_INFO("%s: BCM: Patch failed (%d)", hu->hdev->name, err); + goto finalize; + } + + /* Init speed if any */ + if (hu->init_speed) + speed = hu->init_speed; + else if (hu->proto->init_speed) + speed = hu->proto->init_speed; + else + speed = 0; + + if (speed) + hci_uart_set_baudrate(hu, speed); + + /* Operational speed if any */ + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + else + speed = 0; + + if (speed) { + err = bcm_set_baudrate(hu, speed); + if (!err) + hci_uart_set_baudrate(hu, speed); + } + +finalize: + release_firmware(fw); + + err = btbcm_finalize(hu->hdev); + + return err; } static const struct h4_recv_pkt bcm_recv_pkts[] = { @@ -104,6 +205,7 @@ if (IS_ERR(bcm->rx_skb)) { int err = PTR_ERR(bcm->rx_skb); BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + bcm->rx_skb = NULL; return err; } @@ -133,10 +235,13 @@ static const struct hci_uart_proto bcm_proto = { .id = HCI_UART_BCM, .name = "BCM", + .init_speed = 115200, + .oper_speed = 4000000, .open = bcm_open, .close = bcm_close, .flush = bcm_flush, .setup = bcm_setup, + .set_baudrate = bcm_set_baudrate, .recv = bcm_recv, .enqueue = bcm_enqueue, .dequeue = bcm_dequeue, diff -Nur linux-4.1.13.orig/drivers/bluetooth/hci_bcsp.c linux-4.1.13/drivers/bluetooth/hci_bcsp.c --- linux-4.1.13.orig/drivers/bluetooth/hci_bcsp.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/hci_bcsp.c 2015-11-30 17:56:13.540140388 +0100 @@ -47,8 +47,8 @@ #include "hci_uart.h" -static bool txcrc = 1; -static bool hciextn = 1; +static bool txcrc = true; +static bool hciextn = true; #define BCSP_TXWINSIZE 4 @@ -436,7 +436,7 @@ break; default: memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1); - if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && + if ((bcsp->rx_skb->data[0] & 0x40) != 0 && bcsp->rx_state != BCSP_W4_CRC) bcsp_crc_update(&bcsp->message_crc, byte); bcsp->rx_count--; @@ -447,24 +447,24 @@ switch (byte) { case 0xdc: memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1); - if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && + if ((bcsp->rx_skb->data[0] & 0x40) != 0 && bcsp->rx_state != BCSP_W4_CRC) - bcsp_crc_update(&bcsp-> message_crc, 0xc0); + bcsp_crc_update(&bcsp->message_crc, 0xc0); bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; bcsp->rx_count--; break; case 0xdd: memcpy(skb_put(bcsp->rx_skb, 1), &db, 1); - if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && + if ((bcsp->rx_skb->data[0] & 0x40) != 0 && bcsp->rx_state != BCSP_W4_CRC) - bcsp_crc_update(&bcsp-> message_crc, 0xdb); + bcsp_crc_update(&bcsp->message_crc, 0xdb); bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; bcsp->rx_count--; break; default: - BT_ERR ("Invalid byte %02x after esc byte", byte); + BT_ERR("Invalid byte %02x after esc byte", byte); kfree_skb(bcsp->rx_skb); bcsp->rx_skb = NULL; bcsp->rx_state = BCSP_W4_PKT_DELIMITER; @@ -527,7 +527,7 @@ hci_recv_frame(hu->hdev, bcsp->rx_skb); } else { - BT_ERR ("Packet for unknown channel (%u %s)", + BT_ERR("Packet for unknown channel (%u %s)", bcsp->rx_skb->data[1] & 0x0f, bcsp->rx_skb->data[0] & 0x80 ? "reliable" : "unreliable"); @@ -587,7 +587,7 @@ } if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */ && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) { - BT_ERR ("Out-of-order packet arrived, got %u expected %u", + BT_ERR("Out-of-order packet arrived, got %u expected %u", bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack); kfree_skb(bcsp->rx_skb); diff -Nur linux-4.1.13.orig/drivers/bluetooth/hci_h4.c linux-4.1.13/drivers/bluetooth/hci_h4.c --- linux-4.1.13.orig/drivers/bluetooth/hci_h4.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/hci_h4.c 2015-11-30 17:56:13.540140388 +0100 @@ -133,6 +133,7 @@ if (IS_ERR(h4->rx_skb)) { int err = PTR_ERR(h4->rx_skb); BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + h4->rx_skb = NULL; return err; } diff -Nur linux-4.1.13.orig/drivers/bluetooth/hci_ldisc.c linux-4.1.13/drivers/bluetooth/hci_ldisc.c --- linux-4.1.13.orig/drivers/bluetooth/hci_ldisc.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/hci_ldisc.c 2015-11-30 17:56:13.540140388 +0100 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -265,11 +266,133 @@ return 0; } +/* Flow control or un-flow control the device */ +void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) +{ + struct tty_struct *tty = hu->tty; + struct ktermios ktermios; + int status; + unsigned int set = 0; + unsigned int clear = 0; + + if (enable) { + /* Disable hardware flow control */ + ktermios = tty->termios; + ktermios.c_cflag &= ~CRTSCTS; + status = tty_set_termios(tty, &ktermios); + BT_DBG("Disabling hardware flow control: %s", + status ? "failed" : "success"); + + /* Clear RTS to prevent the device from sending */ + /* Most UARTs need OUT2 to enable interrupts */ + status = tty->driver->ops->tiocmget(tty); + BT_DBG("Current tiocm 0x%x", status); + + set &= ~(TIOCM_OUT2 | TIOCM_RTS); + clear = ~set; + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + status = tty->driver->ops->tiocmset(tty, set, clear); + BT_DBG("Clearing RTS: %s", status ? "failed" : "success"); + } else { + /* Set RTS to allow the device to send again */ + status = tty->driver->ops->tiocmget(tty); + BT_DBG("Current tiocm 0x%x", status); + + set |= (TIOCM_OUT2 | TIOCM_RTS); + clear = ~set; + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + status = tty->driver->ops->tiocmset(tty, set, clear); + BT_DBG("Setting RTS: %s", status ? "failed" : "success"); + + /* Re-enable hardware flow control */ + ktermios = tty->termios; + ktermios.c_cflag |= CRTSCTS; + status = tty_set_termios(tty, &ktermios); + BT_DBG("Enabling hardware flow control: %s", + status ? "failed" : "success"); + } +} + +void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, + unsigned int oper_speed) +{ + hu->init_speed = init_speed; + hu->oper_speed = oper_speed; +} + +void hci_uart_init_tty(struct hci_uart *hu) +{ + struct tty_struct *tty = hu->tty; + struct ktermios ktermios; + + /* Bring the UART into a known 8 bits no parity hw fc state */ + ktermios = tty->termios; + ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | + INLCR | IGNCR | ICRNL | IXON); + ktermios.c_oflag &= ~OPOST; + ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ktermios.c_cflag &= ~(CSIZE | PARENB); + ktermios.c_cflag |= CS8; + ktermios.c_cflag |= CRTSCTS; + + /* tty_set_termios() return not checked as it is always 0 */ + tty_set_termios(tty, &ktermios); +} + +void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed) +{ + struct tty_struct *tty = hu->tty; + struct ktermios ktermios; + + ktermios = tty->termios; + ktermios.c_cflag &= ~CBAUD; + tty_termios_encode_baud_rate(&ktermios, speed, speed); + + /* tty_set_termios() return not checked as it is always 0 */ + tty_set_termios(tty, &ktermios); + + BT_DBG("%s: New tty speeds: %d/%d", hu->hdev->name, + tty->termios.c_ispeed, tty->termios.c_ospeed); +} + static int hci_uart_setup(struct hci_dev *hdev) { struct hci_uart *hu = hci_get_drvdata(hdev); struct hci_rp_read_local_version *ver; struct sk_buff *skb; + unsigned int speed; + int err; + + /* Init speed if any */ + if (hu->init_speed) + speed = hu->init_speed; + else if (hu->proto->init_speed) + speed = hu->proto->init_speed; + else + speed = 0; + + if (speed) + hci_uart_set_baudrate(hu, speed); + + /* Operational speed if any */ + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + else + speed = 0; + + if (hu->proto->set_baudrate && speed) { + err = hu->proto->set_baudrate(hu, speed); + if (!err) + hci_uart_set_baudrate(hu, speed); + } if (hu->proto->setup) return hu->proto->setup(hu); diff -Nur linux-4.1.13.orig/drivers/bluetooth/hci_uart.h linux-4.1.13/drivers/bluetooth/hci_uart.h --- linux-4.1.13.orig/drivers/bluetooth/hci_uart.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/hci_uart.h 2015-11-30 17:56:13.540140388 +0100 @@ -58,10 +58,13 @@ struct hci_uart_proto { unsigned int id; const char *name; + unsigned int init_speed; + unsigned int oper_speed; int (*open)(struct hci_uart *hu); int (*close)(struct hci_uart *hu); int (*flush)(struct hci_uart *hu); int (*setup)(struct hci_uart *hu); + int (*set_baudrate)(struct hci_uart *hu, unsigned int speed); int (*recv)(struct hci_uart *hu, const void *data, int len); int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); struct sk_buff *(*dequeue)(struct hci_uart *hu); @@ -82,6 +85,9 @@ struct sk_buff *tx_skb; unsigned long tx_state; spinlock_t rx_lock; + + unsigned int init_speed; + unsigned int oper_speed; }; /* HCI_UART proto flag bits */ @@ -96,6 +102,11 @@ int hci_uart_unregister_proto(const struct hci_uart_proto *p); int hci_uart_tx_wakeup(struct hci_uart *hu); int hci_uart_init_ready(struct hci_uart *hu); +void hci_uart_init_tty(struct hci_uart *hu); +void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed); +void hci_uart_set_flow_control(struct hci_uart *hu, bool enable); +void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, + unsigned int oper_speed); #ifdef CONFIG_BT_HCIUART_H4 int h4_init(void); diff -Nur linux-4.1.13.orig/drivers/bluetooth/hci_vhci.c linux-4.1.13/drivers/bluetooth/hci_vhci.c --- linux-4.1.13.orig/drivers/bluetooth/hci_vhci.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/hci_vhci.c 2015-11-30 17:56:13.540140388 +0100 @@ -366,7 +366,7 @@ .llseek = no_llseek, }; -static struct miscdevice vhci_miscdev= { +static struct miscdevice vhci_miscdev = { .name = "vhci", .fops = &vhci_fops, .minor = VHCI_MINOR, diff -Nur linux-4.1.13.orig/drivers/bluetooth/Kconfig linux-4.1.13/drivers/bluetooth/Kconfig --- linux-4.1.13.orig/drivers/bluetooth/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/Kconfig 2015-11-30 17:56:13.544140122 +0100 @@ -9,6 +9,10 @@ tristate select FW_LOADER +config BT_RTL + tristate + select FW_LOADER + config BT_HCIBTUSB tristate "HCI USB driver" depends on USB @@ -32,6 +36,17 @@ Say Y here to compile support for Broadcom protocol. +config BT_HCIBTUSB_RTL + bool "Realtek protocol support" + depends on BT_HCIBTUSB + select BT_RTL + default y + help + The Realtek protocol support enables firmware and configuration + download support for Realtek Bluetooth controllers. + + Say Y here to compile support for Realtek protocol. + config BT_HCIBTSDIO tristate "HCI SDIO driver" depends on MMC diff -Nur linux-4.1.13.orig/drivers/bluetooth/Makefile linux-4.1.13/drivers/bluetooth/Makefile --- linux-4.1.13.orig/drivers/bluetooth/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/bluetooth/Makefile 2015-11-30 17:56:13.544140122 +0100 @@ -21,6 +21,7 @@ obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o obj-$(CONFIG_BT_WILINK) += btwilink.o obj-$(CONFIG_BT_BCM) += btbcm.o +obj-$(CONFIG_BT_RTL) += btrtl.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o diff -Nur linux-4.1.13.orig/drivers/char/frandom.c linux-4.1.13/drivers/char/frandom.c --- linux-4.1.13.orig/drivers/char/frandom.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/char/frandom.c 2015-11-30 17:56:13.544140122 +0100 @@ -0,0 +1,415 @@ +/* +** frandom.c +** Fast pseudo-random generator +** +** (c) Copyright 2003-2011 Eli Billauer +** http://www.billauer.co.il +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define INTERNAL_SEED 0 +#define EXTERNAL_SEED 1 + +#define FRANDOM_MAJOR 235 +#define FRANDOM_MINOR 11 +#define ERANDOM_MINOR 12 + +static struct file_operations frandom_fops; /* Values assigned below */ + +static int erandom_seeded = 0; /* Internal flag */ + +static int frandom_major = FRANDOM_MAJOR; +static int frandom_minor = FRANDOM_MINOR; +static int erandom_minor = ERANDOM_MINOR; +static int frandom_bufsize = 256; +static int frandom_chunklimit = 0; /* =0 means unlimited */ + +static struct cdev frandom_cdev; +static struct cdev erandom_cdev; +static struct class *frandom_class; +struct device *frandom_device; +struct device *erandom_device; + +MODULE_DESCRIPTION("Fast pseudo-random number generator"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eli Billauer"); +module_param(frandom_major, int, 0); +module_param(frandom_minor, int, 0); +module_param(erandom_minor, int, 0); +module_param(frandom_bufsize, int, 0); +module_param(frandom_chunklimit, int, 0); + +MODULE_PARM_DESC(frandom_major,"Major number of /dev/frandom and /dev/erandom"); +MODULE_PARM_DESC(frandom_minor,"Minor number of /dev/frandom"); +MODULE_PARM_DESC(erandom_minor,"Minor number of /dev/erandom"); +MODULE_PARM_DESC(frandom_bufsize,"Internal buffer size in bytes. Default is 256. Must be >= 256"); +MODULE_PARM_DESC(frandom_chunklimit,"Limit for read() blocks size. 0 (default) is unlimited, otherwise must be >= 256"); + +struct frandom_state +{ + struct semaphore sem; /* Semaphore on the state structure */ + + u8 S[256]; /* The state array */ + u8 i; + u8 j; + + char *buf; +}; + +static struct frandom_state *erandom_state; + +static inline void swap_byte(u8 *a, u8 *b) +{ + u8 swapByte; + + swapByte = *a; + *a = *b; + *b = swapByte; +} + +static void init_rand_state(struct frandom_state *state, int seedflag); + +void erandom_get_random_bytes(char *buf, size_t count) +{ + struct frandom_state *state = erandom_state; + int k; + + unsigned int i; + unsigned int j; + u8 *S; + + /* If we fail to get the semaphore, we revert to external random data. + Since semaphore blocking is expected to be very rare, and interrupts + during these rare and very short periods of time even less frequent, + we take the better-safe-than-sorry approach, and fill the buffer + some expensive random data, in case the caller wasn't aware of this + possibility, and expects random data anyhow. + */ + + if (down_interruptible(&state->sem)) { + get_random_bytes(buf, count); + return; + } + + /* We seed erandom as late as possible, hoping that the kernel's main + RNG is already restored in the boot sequence (not critical, but + better. + */ + + if (!erandom_seeded) { + erandom_seeded = 1; + init_rand_state(state, EXTERNAL_SEED); + printk(KERN_INFO "frandom: Seeded global generator now (used by erandom)\n"); + } + + i = state->i; + j = state->j; + S = state->S; + + for (k=0; ki = i; + state->j = j; + + up(&state->sem); +} + +static void init_rand_state(struct frandom_state *state, int seedflag) +{ + unsigned int i, j, k; + u8 *S; + u8 *seed = state->buf; + + if (seedflag == INTERNAL_SEED) + erandom_get_random_bytes(seed, 256); + else + get_random_bytes(seed, 256); + + S = state->S; + for (i=0; i<256; i++) + *S++=i; + + j=0; + S = state->S; + + for (i=0; i<256; i++) { + j = (j + S[i] + *seed++) & 0xff; + swap_byte(&S[i], &S[j]); + } + + /* It's considered good practice to discard the first 256 bytes + generated. So we do it: + */ + + i=0; j=0; + for (k=0; k<256; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + swap_byte(&S[i], &S[j]); + } + + state->i = i; /* Save state */ + state->j = j; +} + +static int frandom_open(struct inode *inode, struct file *filp) +{ + + struct frandom_state *state; + + int num = iminor(inode); + + /* This should never happen, now when the minors are regsitered + * explicitly + */ + if ((num != frandom_minor) && (num != erandom_minor)) return -ENODEV; + + state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->buf = kmalloc(frandom_bufsize, GFP_KERNEL); + if (!state->buf) { + kfree(state); + return -ENOMEM; + } + + sema_init(&state->sem, 1); /* Init semaphore as a mutex */ + + if (num == frandom_minor) + init_rand_state(state, EXTERNAL_SEED); + else + init_rand_state(state, INTERNAL_SEED); + + filp->private_data = state; + + return 0; /* Success */ +} + +static int frandom_release(struct inode *inode, struct file *filp) +{ + + struct frandom_state *state = filp->private_data; + + kfree(state->buf); + kfree(state); + + return 0; +} + +static ssize_t frandom_read(struct file *filp, char *buf, size_t count, + loff_t *f_pos) +{ + struct frandom_state *state = filp->private_data; + ssize_t ret; + int dobytes, k; + char *localbuf; + + unsigned int i; + unsigned int j; + u8 *S; + + if (down_interruptible(&state->sem)) + return -ERESTARTSYS; + + if ((frandom_chunklimit > 0) && (count > frandom_chunklimit)) + count = frandom_chunklimit; + + ret = count; /* It's either everything or an error... */ + + i = state->i; + j = state->j; + S = state->S; + + while (count) { + if (count > frandom_bufsize) + dobytes = frandom_bufsize; + else + dobytes = count; + + localbuf = state->buf; + + for (k=0; kbuf, dobytes)) { + ret = -EFAULT; + goto out; + } + + buf += dobytes; + count -= dobytes; + } + + out: + state->i = i; + state->j = j; + + up(&state->sem); + return ret; +} + +static struct file_operations frandom_fops = { + read: frandom_read, + open: frandom_open, + release: frandom_release, +}; + +static void frandom_cleanup_module(void) { + unregister_chrdev_region(MKDEV(frandom_major, erandom_minor), 1); + cdev_del(&erandom_cdev); + device_destroy(frandom_class, MKDEV(frandom_major, erandom_minor)); + + unregister_chrdev_region(MKDEV(frandom_major, frandom_minor), 1); + cdev_del(&frandom_cdev); + device_destroy(frandom_class, MKDEV(frandom_major, frandom_minor)); + class_destroy(frandom_class); + + kfree(erandom_state->buf); + kfree(erandom_state); +} + + +static int frandom_init_module(void) +{ + int result; + + /* The buffer size MUST be at least 256 bytes, because we assume that + minimal length in init_rand_state(). + */ + if (frandom_bufsize < 256) { + printk(KERN_ERR "frandom: Refused to load because frandom_bufsize=%d < 256\n",frandom_bufsize); + return -EINVAL; + } + if ((frandom_chunklimit != 0) && (frandom_chunklimit < 256)) { + printk(KERN_ERR "frandom: Refused to load because frandom_chunklimit=%d < 256 and != 0\n",frandom_chunklimit); + return -EINVAL; + } + + erandom_state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL); + if (!erandom_state) + return -ENOMEM; + + /* This specific buffer is only used for seeding, so we need + 256 bytes exactly */ + erandom_state->buf = kmalloc(256, GFP_KERNEL); + if (!erandom_state->buf) { + kfree(erandom_state); + return -ENOMEM; + } + + sema_init(&erandom_state->sem, 1); /* Init semaphore as a mutex */ + + erandom_seeded = 0; + + frandom_class = class_create(THIS_MODULE, "fastrng"); + if (IS_ERR(frandom_class)) { + result = PTR_ERR(frandom_class); + printk(KERN_WARNING "frandom: Failed to register class fastrng\n"); + goto error0; + } + + /* + * Register your major, and accept a dynamic number. This is the + * first thing to do, in order to avoid releasing other module's + * fops in frandom_cleanup_module() + */ + + cdev_init(&frandom_cdev, &frandom_fops); + frandom_cdev.owner = THIS_MODULE; + result = cdev_add(&frandom_cdev, MKDEV(frandom_major, frandom_minor), 1); + if (result) { + printk(KERN_WARNING "frandom: Failed to add cdev for /dev/frandom\n"); + goto error1; + } + + result = register_chrdev_region(MKDEV(frandom_major, frandom_minor), 1, "/dev/frandom"); + if (result < 0) { + printk(KERN_WARNING "frandom: can't get major/minor %d/%d\n", frandom_major, frandom_minor); + goto error2; + } + + frandom_device = device_create(frandom_class, NULL, MKDEV(frandom_major, frandom_minor), NULL, "frandom"); + + if (IS_ERR(frandom_device)) { + printk(KERN_WARNING "frandom: Failed to create frandom device\n"); + goto error3; + } + + cdev_init(&erandom_cdev, &frandom_fops); + erandom_cdev.owner = THIS_MODULE; + result = cdev_add(&erandom_cdev, MKDEV(frandom_major, erandom_minor), 1); + if (result) { + printk(KERN_WARNING "frandom: Failed to add cdev for /dev/erandom\n"); + goto error4; + } + + result = register_chrdev_region(MKDEV(frandom_major, erandom_minor), 1, "/dev/erandom"); + if (result < 0) { + printk(KERN_WARNING "frandom: can't get major/minor %d/%d\n", frandom_major, erandom_minor); + goto error5; + } + + erandom_device = device_create(frandom_class, NULL, MKDEV(frandom_major, erandom_minor), NULL, "erandom"); + + if (IS_ERR(erandom_device)) { + printk(KERN_WARNING "frandom: Failed to create erandom device\n"); + goto error6; + } + return 0; /* succeed */ + + error6: + unregister_chrdev_region(MKDEV(frandom_major, erandom_minor), 1); + error5: + cdev_del(&erandom_cdev); + error4: + device_destroy(frandom_class, MKDEV(frandom_major, frandom_minor)); + error3: + unregister_chrdev_region(MKDEV(frandom_major, frandom_minor), 1); + error2: + cdev_del(&frandom_cdev); + error1: + class_destroy(frandom_class); + error0: + kfree(erandom_state->buf); + kfree(erandom_state); + + return result; +} + +module_init(frandom_init_module); +module_exit(frandom_cleanup_module); + +EXPORT_SYMBOL(erandom_get_random_bytes); diff -Nur linux-4.1.13.orig/drivers/char/Makefile linux-4.1.13/drivers/char/Makefile --- linux-4.1.13.orig/drivers/char/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/char/Makefile 2015-11-30 17:56:13.544140122 +0100 @@ -2,6 +2,7 @@ # Makefile for the kernel character device drivers. # +obj-m += frandom.o obj-y += mem.o random.o obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o obj-y += misc.o diff -Nur linux-4.1.13.orig/drivers/cpufreq/imx6q-cpufreq.c linux-4.1.13/drivers/cpufreq/imx6q-cpufreq.c --- linux-4.1.13.orig/drivers/cpufreq/imx6q-cpufreq.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/cpufreq/imx6q-cpufreq.c 2015-11-30 17:56:13.544140122 +0100 @@ -20,6 +20,8 @@ #define PU_SOC_VOLTAGE_HIGH 1275000 #define FREQ_1P2_GHZ 1200000000 +extern int vpu352; + static struct regulator *arm_reg; static struct regulator *pu_reg; static struct regulator *soc_reg; @@ -44,6 +46,7 @@ unsigned long freq_hz, volt, volt_old; unsigned int old_freq, new_freq; int ret; + int tol = 25000; /* 25mv tollerance */ new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; @@ -61,25 +64,25 @@ 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); /* scaling up? scale voltage before frequency */ if (new_freq > old_freq) { if (!IS_ERR(pu_reg)) { - ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); + 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); 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); 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); @@ -107,25 +110,25 @@ 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); 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; } if (!IS_ERR(pu_reg)) { - ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); + 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; @@ -251,6 +254,10 @@ unsigned long volt = be32_to_cpup(val++); if (freq_table[j].frequency == freq) { imx6_soc_volt[soc_opp_count++] = volt; + if (vpu352 && freq == 792000) { + pr_info("VPU352: increase SOC/PU voltage for VPU352MHz\n"); + imx6_soc_volt[soc_opp_count-1] = 1250000; + } break; } } diff -Nur linux-4.1.13.orig/drivers/crypto/caam/caamalg.c linux-4.1.13/drivers/crypto/caam/caamalg.c --- linux-4.1.13.orig/drivers/crypto/caam/caamalg.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/caamalg.c 2015-11-30 17:56:13.544140122 +0100 @@ -1,7 +1,7 @@ /* * caam - Freescale FSL CAAM support for crypto API * - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. * * Based on talitos crypto API driver. * @@ -53,6 +53,7 @@ #include "error.h" #include "sg_sw_sec4.h" #include "key_gen.h" +#include /* * crypto alg @@ -60,68 +61,42 @@ #define CAAM_CRA_PRIORITY 3000 /* max key is sum of AES_MAX_KEY_SIZE, max split key size */ #define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \ - CTR_RFC3686_NONCE_SIZE + \ SHA512_DIGEST_SIZE * 2) /* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ #define CAAM_MAX_IV_LENGTH 16 /* length of descriptors text */ +#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3) + #define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) -#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) -#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 18 * CAAM_CMD_SZ) +#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 16 * CAAM_CMD_SZ) +#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 21 * CAAM_CMD_SZ) #define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) -/* Note: Nonce is counted in enckeylen */ -#define DESC_AEAD_CTR_RFC3686_LEN (6 * CAAM_CMD_SZ) - -#define DESC_AEAD_NULL_BASE (3 * CAAM_CMD_SZ) -#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 14 * CAAM_CMD_SZ) -#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 17 * CAAM_CMD_SZ) - -#define DESC_GCM_BASE (3 * CAAM_CMD_SZ) -#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 23 * CAAM_CMD_SZ) -#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 19 * CAAM_CMD_SZ) - -#define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) -#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 15 * CAAM_CMD_SZ) -#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 14 * CAAM_CMD_SZ) -#define DESC_RFC4106_GIVENC_LEN (DESC_RFC4106_BASE + 21 * CAAM_CMD_SZ) - -#define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ) -#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 25 * CAAM_CMD_SZ) -#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 27 * CAAM_CMD_SZ) -#define DESC_RFC4543_GIVENC_LEN (DESC_RFC4543_BASE + 30 * CAAM_CMD_SZ) - #define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ) #define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \ 20 * CAAM_CMD_SZ) #define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \ 15 * CAAM_CMD_SZ) -#define DESC_MAX_USED_BYTES (DESC_RFC4543_GIVENC_LEN + \ +#define DESC_MAX_USED_BYTES (DESC_AEAD_GIVENC_LEN + \ CAAM_MAX_KEY_SIZE) #define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ) #ifdef DEBUG /* for print_hex_dumps with line references */ +#define xstr(s) str(s) +#define str(s) #s #define debug(format, arg...) printk(format, arg) #else #define debug(format, arg...) #endif -static struct list_head alg_list; /* Set DK bit in class 1 operation if shared */ static inline void append_dec_op1(u32 *desc, u32 type) { u32 *jump_cmd, *uncond_jump_cmd; - /* DK bit is valid only for AES */ - if ((type & OP_ALG_ALGSEL_MASK) != OP_ALG_ALGSEL_AES) { - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT); - return; - } - jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); append_operation(desc, type | OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); @@ -133,26 +108,37 @@ } /* + * Wait for completion of class 1 key loading before allowing + * error propagation + */ +static inline void append_dec_shr_done(u32 *desc) +{ + u32 *jump_cmd; + + jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TEST_ALL); + set_jump_tgt_here(desc, jump_cmd); + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); +} + +/* * For aead functions, read payload and write payload, * both of which are specified in req->src and req->dst */ static inline void aead_append_src_dst(u32 *desc, u32 msg_type) { - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH); + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); } /* * For aead encrypt and decrypt, read iv for both classes */ -static inline void aead_append_ld_iv(u32 *desc, int ivsize, int ivoffset) +static inline void aead_append_ld_iv(u32 *desc, int ivsize) { - append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - (ivoffset << LDST_OFFSET_SHIFT)); - append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | - (ivoffset << MOVE_OFFSET_SHIFT) | ivsize); + append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | ivsize); + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ivsize); } /* @@ -198,309 +184,68 @@ }; static void append_key_aead(u32 *desc, struct caam_ctx *ctx, - int keys_fit_inline, bool is_rfc3686) + int keys_fit_inline) { - u32 *nonce; - unsigned int enckeylen = ctx->enckeylen; - - /* - * RFC3686 specific: - * | ctx->key = {AUTH_KEY, ENC_KEY, NONCE} - * | enckeylen = encryption key size + nonce size - */ - if (is_rfc3686) - enckeylen -= CTR_RFC3686_NONCE_SIZE; - if (keys_fit_inline) { append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, ctx->split_key_len, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); append_key_as_imm(desc, (void *)ctx->key + - ctx->split_key_pad_len, enckeylen, - enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + ctx->split_key_pad_len, ctx->enckeylen, + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); } else { append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); append_key(desc, ctx->key_dma + ctx->split_key_pad_len, - enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - } - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) { - nonce = (u32 *)((void *)ctx->key + ctx->split_key_pad_len + - enckeylen); - append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); } } static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, - int keys_fit_inline, bool is_rfc3686) + int keys_fit_inline) { u32 *key_jump_cmd; - /* Note: Context registers are saved. */ - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - append_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); - - set_jump_tgt_here(desc, key_jump_cmd); -} - -static int aead_null_set_sh_desc(struct crypto_aead *aead) -{ - struct aead_tfm *tfm = &aead->base.crt_aead; - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; - u32 *key_jump_cmd, *jump_cmd, *read_move_cmd, *write_move_cmd; - u32 *desc; - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - if (DESC_AEAD_NULL_ENC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - /* aead_encrypt shared descriptor */ - desc = ctx->sh_desc_enc; - init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - set_jump_tgt_here(desc, key_jump_cmd); - - /* cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* - * NULL encryption; IV is zero - * assoclen = (assoclen + cryptlen) - cryptlen - */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - - /* Prepare to read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | - MOVE_DEST_MATH3 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | - MOVE_DEST_DESCBUF | - MOVE_WAITCOMP | - (0x8 << MOVE_LEN_SHIFT)); - - /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* Read and write cryptlen bytes */ - aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | - MOVE_AUX_LS); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "aead null enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - keys_fit_inline = false; - if (DESC_AEAD_NULL_DEC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - desc = ctx->sh_desc_dec; - /* aead_decrypt shared descriptor */ - init_sh_desc(desc, HDR_SHARE_SERIAL); + append_key_aead(desc, ctx, keys_fit_inline); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); set_jump_tgt_here(desc, key_jump_cmd); - /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* assoclen + cryptlen = seqinlen - ivsize - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, - ctx->authsize + tfm->ivsize); - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - - /* Prepare to read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | - MOVE_DEST_MATH2 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH2 | - MOVE_DEST_DESCBUF | - MOVE_WAITCOMP | - (0x8 << MOVE_LEN_SHIFT)); - - /* Read and write cryptlen bytes */ - aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - /* - * Insert a NOP here, since we need at least 4 instructions between - * code patching the descriptor buffer and the location being patched. - */ - jump_cmd = append_jump(desc, JUMP_TEST_ALL); - set_jump_tgt_here(desc, jump_cmd); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | - MOVE_AUX_LS); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Load ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 | - FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); - - ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "aead null dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - return 0; + /* Propagate errors from shared to job descriptor */ + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); } static int aead_set_sh_desc(struct crypto_aead *aead) { struct aead_tfm *tfm = &aead->base.crt_aead; struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct crypto_tfm *ctfm = crypto_aead_tfm(aead); - const char *alg_name = crypto_tfm_alg_name(ctfm); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline; + bool keys_fit_inline = false; + u32 *key_jump_cmd, *jump_cmd; u32 geniv, moveiv; - u32 ctx1_iv_off = 0; u32 *desc; - const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == - OP_ALG_AAI_CTR_MOD128); - const bool is_rfc3686 = (ctr_mode && - (strstr(alg_name, "rfc3686") != NULL)); - if (!ctx->authsize) + if (!ctx->enckeylen || !ctx->authsize) return 0; - /* NULL encryption / decryption */ - if (!ctx->enckeylen) - return aead_null_set_sh_desc(aead); - - /* - * AES-CTR needs to load IV in CONTEXT1 reg - * at an offset of 128bits (16bytes) - * CONTEXT1[255:128] = IV - */ - if (ctr_mode) - ctx1_iv_off = 16; - - /* - * RFC3686 specific: - * CONTEXT1[255:128] = {NONCE, IV, COUNTER} - */ - if (is_rfc3686) - ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; - /* * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_AEAD_ENC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen + - (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) keys_fit_inline = true; /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); + init_sh_desc_key_aead(desc, ctx, keys_fit_inline); /* Class 2 operation */ append_operation(desc, ctx->class2_alg_type | @@ -512,21 +257,13 @@ /* assoclen + cryptlen = seqinlen - ivsize */ append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize); - /* assoclen = (assoclen + cryptlen) - cryptlen */ + /* assoclen + cryptlen = (assoclen + cryptlen) - cryptlen */ append_math_sub(desc, VARSEQINLEN, REG2, REG3, CAAM_CMD_SZ); /* read assoc before reading payload */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | KEY_VLF); - aead_append_ld_iv(desc, tfm->ivsize, ctx1_iv_off); - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM | - LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); + aead_append_ld_iv(desc, tfm->ivsize); /* Class 1 operation */ append_operation(desc, ctx->class1_alg_type | @@ -549,35 +286,46 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, "aead enc shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "aead enc shdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, 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 */ - keys_fit_inline = false; if (DESC_AEAD_DEC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen + - (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) keys_fit_inline = true; - /* aead_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); + /* aead_decrypt shared descriptor */ + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + append_key_aead(desc, ctx, keys_fit_inline); + + /* Only propagate error immediately if shared */ + jump_cmd = append_jump(desc, JUMP_TEST_ALL); + set_jump_tgt_here(desc, key_jump_cmd); + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + set_jump_tgt_here(desc, jump_cmd); /* Class 2 operation */ append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - /* assoclen + cryptlen = seqinlen - ivsize - authsize */ + /* assoclen + cryptlen = seqinlen - ivsize */ append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, - ctx->authsize + tfm->ivsize); + ctx->authsize + tfm->ivsize) /* assoclen = (assoclen + cryptlen) - cryptlen */ append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ); @@ -586,22 +334,9 @@ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | KEY_VLF); - aead_append_ld_iv(desc, tfm->ivsize, ctx1_iv_off); + aead_append_ld_iv(desc, tfm->ivsize); - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM | - LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - /* Choose operation */ - if (ctr_mode) - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); - else - append_dec_op1(desc, ctx->class1_alg_type); + append_dec_op1(desc, ctx->class1_alg_type); /* Read and write cryptlen bytes */ append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); @@ -611,6 +346,7 @@ /* Load ICV */ append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); + append_dec_shr_done(desc); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), @@ -620,27 +356,26 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, "aead dec shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "aead dec shdesc@"xstr(__LINE__)": ", 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 * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_AEAD_GIVENC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen + - (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) keys_fit_inline = true; /* aead_givencrypt shared descriptor */ desc = ctx->sh_desc_givenc; - /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); + init_sh_desc_key_aead(desc, ctx, keys_fit_inline); /* Generate IV */ geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | @@ -649,16 +384,13 @@ append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | - (ctx1_iv_off << MOVE_OFFSET_SHIFT) | - (tfm->ivsize << MOVE_LEN_SHIFT)); + append_move(desc, MOVE_SRC_INFIFO | + MOVE_DEST_CLASS1CTX | (tfm->ivsize << MOVE_LEN_SHIFT)); append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); /* Copy IV to class 1 context */ - append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | - (ctx1_iv_off << MOVE_OFFSET_SHIFT) | - (tfm->ivsize << MOVE_LEN_SHIFT)); + append_move(desc, MOVE_SRC_CLASS1CTX | + MOVE_DEST_OUTFIFO | (tfm->ivsize << MOVE_LEN_SHIFT)); /* Return to encryption */ append_operation(desc, ctx->class2_alg_type | @@ -674,7 +406,7 @@ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | KEY_VLF); - /* Copy iv from outfifo to class 2 fifo */ + /* Copy iv from class 1 ctx to class 2 fifo*/ moveiv = NFIFOENTRY_STYPE_OFIFO | NFIFOENTRY_DEST_CLASS2 | NFIFOENTRY_DTYPE_MSG | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT); append_load_imm_u32(desc, moveiv, LDST_CLASS_IND_CCB | @@ -682,14 +414,6 @@ append_load_imm_u32(desc, tfm->ivsize, LDST_CLASS_2_CCB | LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM); - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM | - LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - /* Class 1 operation */ append_operation(desc, ctx->class1_alg_type | OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); @@ -717,10 +441,12 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, "aead givenc shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "aead givenc shdesc@"xstr(__LINE__)": ", 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; } @@ -736,977 +462,84 @@ return 0; } -static int gcm_set_sh_desc(struct crypto_aead *aead) +static u32 gen_split_aead_key(struct caam_ctx *ctx, const u8 *key_in, + u32 authkeylen) { - struct aead_tfm *tfm = &aead->base.crt_aead; + return gen_split_key(ctx->jrdev, ctx->key, ctx->split_key_len, + ctx->split_key_pad_len, key_in, authkeylen, + ctx->alg_op); +} + +static int aead_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) +{ + /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ + static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; - u32 *key_jump_cmd, *zero_payload_jump_cmd, - *zero_assoc_jump_cmd1, *zero_assoc_jump_cmd2; - u32 *desc; - - if (!ctx->enckeylen || !ctx->authsize) - return 0; - - /* - * AES GCM encrypt shared descriptor - * Job Descriptor and Shared Descriptor - * must fit into the 64-word Descriptor h/w Buffer - */ - if (DESC_GCM_ENC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + struct rtattr *rta = (void *)key; + struct crypto_authenc_key_param *param; + unsigned int authkeylen; + unsigned int enckeylen; + int ret = 0; - desc = ctx->sh_desc_enc; + param = RTA_DATA(rta); + enckeylen = be32_to_cpu(param->enckeylen); - init_sh_desc(desc, HDR_SHARE_SERIAL); + key += RTA_ALIGN(rta->rta_len); + keylen -= RTA_ALIGN(rta->rta_len); - /* skip key loading if they are loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD | JUMP_COND_SELF); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); + if (keylen < enckeylen) + goto badkey; - /* class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + authkeylen = keylen - enckeylen; - /* cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); + if (keylen > CAAM_MAX_KEY_SIZE) + goto badkey; - /* assoclen + cryptlen = seqinlen - ivsize */ - append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize); + /* Pick class 2 key length from algorithm submask */ + ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT] * 2; + ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, REG1, REG2, REG3, CAAM_CMD_SZ); +#ifdef DEBUG + printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", + keylen, enckeylen, authkeylen); + printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", + ctx->split_key_len, ctx->split_key_pad_len); + print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); +#endif - /* if cryptlen is ZERO jump to zero-payload commands */ - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - /* read IV */ - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); - - /* if assoclen is ZERO, skip reading the assoc data */ - append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ); - zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - - /* read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - set_jump_tgt_here(desc, zero_assoc_jump_cmd1); + ret = gen_split_aead_key(ctx, key, authkeylen); + if (ret) { + goto badkey; + } - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + /* postpend encryption key to auth split key */ + memcpy(ctx->key + ctx->split_key_pad_len, key + authkeylen, enckeylen); - /* write encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + + enckeylen, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->key_dma)) { + dev_err(jrdev, "unable to map key i/o memory\n"); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len + enckeylen, 1); +#endif + dma_sync_single_for_device(jrdev, ctx->key_dma, + ctx->split_key_pad_len + enckeylen, + DMA_TO_DEVICE); - /* read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); - - /* jump the zero-payload commands */ - append_jump(desc, JUMP_TEST_ALL | 7); - - /* zero-payload commands */ - set_jump_tgt_here(desc, zero_payload_jump_cmd); - - /* if assoclen is ZERO, jump to IV reading - is the only input data */ - append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ); - zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - /* read IV */ - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); - - /* read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1); - - /* jump to ICV writing */ - append_jump(desc, JUMP_TEST_ALL | 2); - - /* read IV - is the only input data */ - set_jump_tgt_here(desc, zero_assoc_jump_cmd2); - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | - FIFOLD_TYPE_LAST1); - - /* write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "gcm enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - keys_fit_inline = false; - if (DESC_GCM_DEC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* skip key loading if they are loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | - JUMP_TEST_ALL | JUMP_COND_SHRD | - JUMP_COND_SELF); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* assoclen + cryptlen = seqinlen - ivsize - icvsize */ - append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, - ctx->authsize + tfm->ivsize); - - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_sub(desc, REG1, REG3, REG2, CAAM_CMD_SZ); - - /* read IV */ - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); - - /* jump to zero-payload command if cryptlen is zero */ - append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); - zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - - append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ); - /* if asoclen is ZERO, skip reading assoc data */ - zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - /* read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - set_jump_tgt_here(desc, zero_assoc_jump_cmd1); - - append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); - - /* store encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - /* jump the zero-payload commands */ - append_jump(desc, JUMP_TEST_ALL | 4); - - /* zero-payload command */ - set_jump_tgt_here(desc, zero_payload_jump_cmd); - - /* if assoclen is ZERO, jump to ICV reading */ - append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ); - zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - /* read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - set_jump_tgt_here(desc, zero_assoc_jump_cmd2); - - /* read ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); - - ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "gcm dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - return 0; -} - -static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize) -{ - struct caam_ctx *ctx = crypto_aead_ctx(authenc); - - ctx->authsize = authsize; - gcm_set_sh_desc(authenc); - - return 0; -} - -static int rfc4106_set_sh_desc(struct crypto_aead *aead) -{ - struct aead_tfm *tfm = &aead->base.crt_aead; - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; - u32 *key_jump_cmd, *move_cmd, *write_iv_cmd; - u32 *desc; - u32 geniv; - - if (!ctx->enckeylen || !ctx->authsize) - return 0; - - /* - * RFC4106 encrypt shared descriptor - * Job Descriptor and Shared Descriptor - * must fit into the 64-word Descriptor h/w Buffer - */ - if (DESC_RFC4106_ENC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - desc = ctx->sh_desc_enc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* assoclen + cryptlen = seqinlen - ivsize */ - append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize); - - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, VARSEQINLEN, REG2, REG3, CAAM_CMD_SZ); - - /* Read Salt */ - append_fifo_load_as_imm(desc, (void *)(ctx->key + ctx->enckeylen), - 4, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_IV); - /* Read AES-GCM-ESP IV */ - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - - /* Will read cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* Write encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* Read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4106 enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - keys_fit_inline = false; - if (DESC_RFC4106_DEC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | - JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* assoclen + cryptlen = seqinlen - ivsize - icvsize */ - append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, - ctx->authsize + tfm->ivsize); - - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ); - - /* Will write cryptlen bytes */ - append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* Read Salt */ - append_fifo_load_as_imm(desc, (void *)(ctx->key + ctx->enckeylen), - 4, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_IV); - /* Read AES-GCM-ESP IV */ - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - - /* Will read cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); - - /* Store payload data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* Read encrypted data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - /* Read ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); - - ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4106 dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - keys_fit_inline = false; - if (DESC_RFC4106_GIVENC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen <= - CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - /* rfc4106_givencrypt shared descriptor */ - desc = ctx->sh_desc_givenc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Generate IV */ - geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | - NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | - NFIFOENTRY_PTYPE_RND | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - move_cmd = append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_DESCBUF | - (tfm->ivsize << MOVE_LEN_SHIFT)); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Copy generated IV to OFIFO */ - write_iv_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_OUTFIFO | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* ivsize + cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* assoclen = seqinlen - (ivsize + cryptlen) */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - - /* Will write ivsize + cryptlen */ - append_math_add(desc, VARSEQOUTLEN, REG3, REG0, CAAM_CMD_SZ); - - /* Read Salt and generated IV */ - append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_IV | - FIFOLD_TYPE_FLUSH1 | IMMEDIATE | 12); - /* Append Salt */ - append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4); - set_move_tgt_here(desc, move_cmd); - set_move_tgt_here(desc, write_iv_cmd); - /* Blank commands. Will be overwritten by generated IV. */ - append_cmd(desc, 0x00000000); - append_cmd(desc, 0x00000000); - /* End of blank commands */ - - /* No need to reload iv */ - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_SKIP); - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - - /* Will read cryptlen */ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Store generated IV and encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* Read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "rfc4106 givenc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - return 0; -} - -static int rfc4106_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - struct caam_ctx *ctx = crypto_aead_ctx(authenc); - - ctx->authsize = authsize; - rfc4106_set_sh_desc(authenc); - - return 0; -} - -static int rfc4543_set_sh_desc(struct crypto_aead *aead) -{ - struct aead_tfm *tfm = &aead->base.crt_aead; - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; - u32 *key_jump_cmd, *write_iv_cmd, *write_aad_cmd; - u32 *read_move_cmd, *write_move_cmd; - u32 *desc; - u32 geniv; - - if (!ctx->enckeylen || !ctx->authsize) - return 0; - - /* - * RFC4543 encrypt shared descriptor - * Job Descriptor and Shared Descriptor - * must fit into the 64-word Descriptor h/w Buffer - */ - if (DESC_RFC4543_ENC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - desc = ctx->sh_desc_enc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* Load AES-GMAC ESP IV into Math1 register */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_DECO_MATH1 | - LDST_CLASS_DECO | tfm->ivsize); - - /* Wait the DMA transaction to finish */ - append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | - (1 << JUMP_OFFSET_SHIFT)); - - /* Overwrite blank immediate AES-GMAC ESP IV data */ - write_iv_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* Overwrite blank immediate AAD data */ - write_aad_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* assoclen = (seqinlen - ivsize) - cryptlen */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - - /* Read Salt and AES-GMAC ESP IV */ - append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | (4 + tfm->ivsize)); - /* Append Salt */ - append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4); - set_move_tgt_here(desc, write_iv_cmd); - /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */ - append_cmd(desc, 0x00000000); - append_cmd(desc, 0x00000000); - /* End of blank commands */ - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD); - - /* Will read cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* Will write cryptlen bytes */ - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | - (0x8 << MOVE_LEN_SHIFT)); - - /* Authenticate AES-GMAC ESP IV */ - append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE | - FIFOLD_TYPE_AAD | tfm->ivsize); - set_move_tgt_here(desc, write_aad_cmd); - /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */ - append_cmd(desc, 0x00000000); - append_cmd(desc, 0x00000000); - /* End of blank commands */ - - /* Read and write cryptlen bytes */ - aead_append_src_dst(desc, FIFOLD_TYPE_AAD); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - /* Move payload data to OFIFO */ - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4543 enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - keys_fit_inline = false; - if (DESC_RFC4543_DEC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | - JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* Load AES-GMAC ESP IV into Math1 register */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_DECO_MATH1 | - LDST_CLASS_DECO | tfm->ivsize); - - /* Wait the DMA transaction to finish */ - append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | - (1 << JUMP_OFFSET_SHIFT)); - - /* assoclen + cryptlen = (seqinlen - ivsize) - icvsize */ - append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, ctx->authsize); - - /* Overwrite blank immediate AES-GMAC ESP IV data */ - write_iv_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* Overwrite blank immediate AAD data */ - write_aad_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | - (0x8 << MOVE_LEN_SHIFT)); - - /* Read Salt and AES-GMAC ESP IV */ - append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | (4 + tfm->ivsize)); - /* Append Salt */ - append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4); - set_move_tgt_here(desc, write_iv_cmd); - /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */ - append_cmd(desc, 0x00000000); - append_cmd(desc, 0x00000000); - /* End of blank commands */ - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD); - - /* Will read cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); - - /* Will write cryptlen bytes */ - append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); - - /* Authenticate AES-GMAC ESP IV */ - append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE | - FIFOLD_TYPE_AAD | tfm->ivsize); - set_move_tgt_here(desc, write_aad_cmd); - /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */ - append_cmd(desc, 0x00000000); - append_cmd(desc, 0x00000000); - /* End of blank commands */ - - /* Store payload data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* In-snoop cryptlen data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST2FLUSH1); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - /* Move payload data to OFIFO */ - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Read ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); - - ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4543 dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - keys_fit_inline = false; - if (DESC_RFC4543_GIVENC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; - - /* rfc4543_givencrypt shared descriptor */ - desc = ctx->sh_desc_givenc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Generate IV */ - geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | - NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | - NFIFOENTRY_PTYPE_RND | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - /* Move generated IV to Math1 register */ - append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_MATH1 | - (tfm->ivsize << MOVE_LEN_SHIFT)); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Overwrite blank immediate AES-GMAC IV data */ - write_iv_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* Overwrite blank immediate AAD data */ - write_aad_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* Copy generated IV to OFIFO */ - append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_OUTFIFO | - (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* ivsize + cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* assoclen = seqinlen - (ivsize + cryptlen) */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - - /* Will write ivsize + cryptlen */ - append_math_add(desc, VARSEQOUTLEN, REG3, REG0, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | - (0x8 << MOVE_LEN_SHIFT)); - - /* Read Salt and AES-GMAC generated IV */ - append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE | - FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | (4 + tfm->ivsize)); - /* Append Salt */ - append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4); - set_move_tgt_here(desc, write_iv_cmd); - /* Blank commands. Will be overwritten by AES-GMAC generated IV. */ - append_cmd(desc, 0x00000000); - append_cmd(desc, 0x00000000); - /* End of blank commands */ - - /* No need to reload iv */ - append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_SKIP); - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD); - - /* Will read cryptlen */ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Authenticate AES-GMAC IV */ - append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE | - FIFOLD_TYPE_AAD | tfm->ivsize); - set_move_tgt_here(desc, write_aad_cmd); - /* Blank commands. Will be overwritten by AES-GMAC IV. */ - append_cmd(desc, 0x00000000); - append_cmd(desc, 0x00000000); - /* End of blank commands */ - - /* Read and write cryptlen bytes */ - aead_append_src_dst(desc, FIFOLD_TYPE_AAD); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - /* Move payload data to OFIFO */ - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "rfc4543 givenc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - return 0; -} - -static int rfc4543_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - struct caam_ctx *ctx = crypto_aead_ctx(authenc); - - ctx->authsize = authsize; - rfc4543_set_sh_desc(authenc); - - return 0; -} - -static u32 gen_split_aead_key(struct caam_ctx *ctx, const u8 *key_in, - u32 authkeylen) -{ - return gen_split_key(ctx->jrdev, ctx->key, ctx->split_key_len, - ctx->split_key_pad_len, key_in, authkeylen, - ctx->alg_op); -} - -static int aead_setkey(struct crypto_aead *aead, - const u8 *key, unsigned int keylen) -{ - /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ - static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - struct crypto_authenc_keys keys; - int ret = 0; - - if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) - goto badkey; - - /* Pick class 2 key length from algorithm submask */ - ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> - OP_ALG_ALGSEL_SHIFT] * 2; - ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); - - if (ctx->split_key_pad_len + keys.enckeylen > CAAM_MAX_KEY_SIZE) - goto badkey; - -#ifdef DEBUG - printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", - keys.authkeylen + keys.enckeylen, keys.enckeylen, - keys.authkeylen); - printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", - ctx->split_key_len, ctx->split_key_pad_len); - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif - - ret = gen_split_aead_key(ctx, keys.authkey, keys.authkeylen); - if (ret) { - goto badkey; - } - - /* postpend encryption key to auth split key */ - memcpy(ctx->key + ctx->split_key_pad_len, keys.enckey, keys.enckeylen); - - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + - keys.enckeylen, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->key_dma)) { - 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 - - ctx->enckeylen = keys.enckeylen; + ctx->enckeylen = enckeylen; ret = aead_set_sh_desc(aead); if (ret) { dma_unmap_single(jrdev, ctx->key_dma, ctx->split_key_pad_len + - keys.enckeylen, DMA_TO_DEVICE); + enckeylen, DMA_TO_DEVICE); } return ret; @@ -1715,154 +548,20 @@ return -EINVAL; } -static int gcm_setkey(struct crypto_aead *aead, - const u8 *key, unsigned int keylen) -{ - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - int ret = 0; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif - - memcpy(ctx->key, key, keylen); - ctx->key_dma = dma_map_single(jrdev, ctx->key, keylen, - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->key_dma)) { - dev_err(jrdev, "unable to map key i/o memory\n"); - return -ENOMEM; - } - ctx->enckeylen = keylen; - - ret = gcm_set_sh_desc(aead); - if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, - DMA_TO_DEVICE); - } - - return ret; -} - -static int rfc4106_setkey(struct crypto_aead *aead, - const u8 *key, unsigned int keylen) -{ - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - int ret = 0; - - if (keylen < 4) - return -EINVAL; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif - - memcpy(ctx->key, key, keylen); - - /* - * The last four bytes of the key material are used as the salt value - * in the nonce. Update the AES key length. - */ - ctx->enckeylen = keylen - 4; - - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->enckeylen, - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->key_dma)) { - dev_err(jrdev, "unable to map key i/o memory\n"); - return -ENOMEM; - } - - ret = rfc4106_set_sh_desc(aead); - if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, - DMA_TO_DEVICE); - } - - return ret; -} - -static int rfc4543_setkey(struct crypto_aead *aead, - const u8 *key, unsigned int keylen) -{ - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - int ret = 0; - - if (keylen < 4) - return -EINVAL; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif - - memcpy(ctx->key, key, keylen); - - /* - * The last four bytes of the key material are used as the salt value - * in the nonce. Update the AES key length. - */ - ctx->enckeylen = keylen - 4; - - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->enckeylen, - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->key_dma)) { - dev_err(jrdev, "unable to map key i/o memory\n"); - return -ENOMEM; - } - - ret = rfc4543_set_sh_desc(aead); - if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, - DMA_TO_DEVICE); - } - - return ret; -} - static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, const u8 *key, unsigned int keylen) { struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct ablkcipher_tfm *crt = &ablkcipher->base.crt_ablkcipher; - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher); - const char *alg_name = crypto_tfm_alg_name(tfm); + struct ablkcipher_tfm *tfm = &ablkcipher->base.crt_ablkcipher; struct device *jrdev = ctx->jrdev; int ret = 0; - u32 *key_jump_cmd; + u32 *key_jump_cmd, *jump_cmd; u32 *desc; - u32 *nonce; - u32 geniv; - u32 ctx1_iv_off = 0; - const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == - OP_ALG_AAI_CTR_MOD128); - const bool is_rfc3686 = (ctr_mode && - (strstr(alg_name, "rfc3686") != NULL)); #ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif - /* - * AES-CTR needs to load IV in CONTEXT1 reg - * at an offset of 128bits (16bytes) - * CONTEXT1[255:128] = IV - */ - if (ctr_mode) - ctx1_iv_off = 16; - - /* - * RFC3686 specific: - * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} - * | *key = {KEY, NONCE} - */ - if (is_rfc3686) { - ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; - keylen -= CTR_RFC3686_NONCE_SIZE; - } memcpy(ctx->key, key, keylen); ctx->key_dma = dma_map_single(jrdev, ctx->key, keylen, @@ -1872,10 +571,11 @@ 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; - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); @@ -1885,32 +585,20 @@ ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - /* Load nonce into CONTEXT1 reg */ - if (is_rfc3686) { - nonce = (u32 *)(key + keylen); - append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - set_jump_tgt_here(desc, key_jump_cmd); - /* Load iv */ - append_seq_load(desc, crt->ivsize, LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); - - /* Load counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM | - LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); + /* Propagate errors from shared to job descriptor */ + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + /* 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); @@ -1926,15 +614,17 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher enc shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ablkcipher enc shdesc@"xstr(__LINE__)": ", 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; - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); @@ -1944,133 +634,49 @@ ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - /* Load nonce into CONTEXT1 reg */ - if (is_rfc3686) { - nonce = (u32 *)(key + keylen); - append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - + /* For aead, only propagate error immediately if shared */ + jump_cmd = append_jump(desc, JUMP_TEST_ALL); set_jump_tgt_here(desc, key_jump_cmd); + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + set_jump_tgt_here(desc, jump_cmd); /* load IV */ - append_seq_load(desc, crt->ivsize, LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); - - /* Load counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM | - LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); + 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 */ - if (ctr_mode) append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); - else + 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); + /* Wait for key to load before allowing propagating error */ + append_dec_shr_done(desc); + ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { + if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - /* ablkcipher_givencrypt shared descriptor */ - desc = ctx->sh_desc_givenc; - - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | - KEY_DEST_CLASS_REG); - - /* Load Nonce into CONTEXT1 reg */ - if (is_rfc3686) { - nonce = (u32 *)(key + keylen); - append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - set_jump_tgt_here(desc, key_jump_cmd); - - /* Generate IV */ - geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | - NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | - NFIFOENTRY_PTYPE_RND | (crt->ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_INFIFO | - MOVE_DEST_CLASS1CTX | - (crt->ivsize << MOVE_LEN_SHIFT) | - (ctx1_iv_off << MOVE_OFFSET_SHIFT)); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Copy generated IV to memory */ - append_seq_store(desc, crt->ivsize, - LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | - (ctx1_iv_off << LDST_OFFSET_SHIFT)); - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_u32(desc, (u32)1, LDST_IMM | - LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - if (ctx1_iv_off) - append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP | - (1 << JUMP_OFFSET_SHIFT)); - - /* Load operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - - ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher givenc shdesc@" __stringify(__LINE__) ": ", + print_hex_dump(KERN_ERR, "ablkcipher dec shdesc@"xstr(__LINE__)": ", 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; } @@ -2195,19 +801,22 @@ edesc = (struct aead_edesc *)((char *)desc - offsetof(struct aead_edesc, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } aead_unmap(jrdev, edesc, req); #ifdef DEBUG - print_hex_dump(KERN_ERR, "assoc @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), req->assoclen , 1); - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src) - ivsize, edesc->src_nents ? 100 : ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), edesc->src_nents ? 100 : req->cryptlen + ctx->authsize + 4, 1); @@ -2235,16 +844,19 @@ offsetof(struct aead_edesc, hw_desc)); #ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->dst), - req->cryptlen - ctx->authsize, 1); + req->cryptlen, 1); #endif - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } aead_unmap(jrdev, edesc, req); @@ -2255,7 +867,7 @@ err = -EBADMSG; #ifdef DEBUG - print_hex_dump(KERN_ERR, "iphdrout@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "iphdrout@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ((char *)sg_virt(req->assoc) - sizeof(struct iphdr)), sizeof(struct iphdr) + req->assoclen + @@ -2263,7 +875,7 @@ ctx->authsize + 36, 1); if (!err && edesc->sec4_sg_bytes) { struct scatterlist *sg = sg_last(req->src, edesc->src_nents); - print_hex_dump(KERN_ERR, "sglastout@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "sglastout@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(sg), sg->length + ctx->authsize + 16, 1); } @@ -2289,14 +901,17 @@ edesc = (struct ablkcipher_edesc *)((char *)desc - offsetof(struct ablkcipher_edesc, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } #ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->info, edesc->src_nents > 1 ? 100 : ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), edesc->dst_nents > 1 ? 100 : req->nbytes, 1); #endif @@ -2321,14 +936,17 @@ edesc = (struct ablkcipher_edesc *)((char *)desc - offsetof(struct ablkcipher_edesc, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } #ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->info, ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), edesc->dst_nents > 1 ? 100 : req->nbytes, 1); #endif @@ -2355,38 +973,29 @@ u32 out_options = 0, in_options; dma_addr_t dst_dma, src_dma; int len, sec4_sg_index = 0; - bool is_gcm = false; #ifdef DEBUG debug("assoclen %d cryptlen %d authsize %d\n", req->assoclen, req->cryptlen, authsize); - print_hex_dump(KERN_ERR, "assoc @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), req->assoclen , 1); - print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, edesc->src_nents ? 100 : ivsize, 1); - print_hex_dump(KERN_ERR, "src @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), edesc->src_nents ? 100 : req->cryptlen, 1); - print_hex_dump(KERN_ERR, "shrdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, desc_bytes(sh_desc), 1); #endif - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - len = desc_len(sh_desc); init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); if (all_contig) { - if (is_gcm) - src_dma = edesc->iv_dma; - else - src_dma = sg_dma_address(req->assoc); + src_dma = sg_dma_address(req->assoc); in_options = 0; } else { src_dma = edesc->sec4_sg_dma; @@ -2394,9 +1003,12 @@ (edesc->src_nents ? : 1); in_options = LDST_SGF; } - - append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + req->cryptlen, - in_options); + if (encrypt) + append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + + req->cryptlen - authsize, in_options); + else + append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + + req->cryptlen, in_options); if (likely(req->src == req->dst)) { if (all_contig) { @@ -2417,8 +1029,7 @@ } } if (encrypt) - append_seq_out_ptr(desc, dst_dma, req->cryptlen + authsize, - out_options); + append_seq_out_ptr(desc, dst_dma, req->cryptlen, out_options); else append_seq_out_ptr(desc, dst_dma, req->cryptlen - authsize, out_options); @@ -2440,53 +1051,43 @@ u32 out_options = 0, in_options; dma_addr_t dst_dma, src_dma; int len, sec4_sg_index = 0; - bool is_gcm = false; #ifdef DEBUG debug("assoclen %d cryptlen %d authsize %d\n", req->assoclen, req->cryptlen, authsize); - print_hex_dump(KERN_ERR, "assoc @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), req->assoclen , 1); - print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); - print_hex_dump(KERN_ERR, "src @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), edesc->src_nents > 1 ? 100 : req->cryptlen, 1); - print_hex_dump(KERN_ERR, "shrdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, desc_bytes(sh_desc), 1); #endif - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - len = desc_len(sh_desc); init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); if (contig & GIV_SRC_CONTIG) { - if (is_gcm) - src_dma = edesc->iv_dma; - else - src_dma = sg_dma_address(req->assoc); + src_dma = sg_dma_address(req->assoc); in_options = 0; } else { src_dma = edesc->sec4_sg_dma; sec4_sg_index += edesc->assoc_nents + 1 + edesc->src_nents; in_options = LDST_SGF; } - append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + req->cryptlen, - in_options); + append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + + req->cryptlen - authsize, in_options); if (contig & GIV_DST_CONTIG) { dst_dma = edesc->iv_dma; } else { if (likely(req->src == req->dst)) { dst_dma = src_dma + sizeof(struct sec4_sg_entry) * - (edesc->assoc_nents + - (is_gcm ? 1 + edesc->src_nents : 0)); + edesc->assoc_nents; out_options = LDST_SGF; } else { dst_dma = edesc->sec4_sg_dma + @@ -2496,8 +1097,7 @@ } } - append_seq_out_ptr(desc, dst_dma, ivsize + req->cryptlen + authsize, - out_options); + append_seq_out_ptr(desc, dst_dma, ivsize + req->cryptlen, out_options); } /* @@ -2516,10 +1116,10 @@ int len, sec4_sg_index = 0; #ifdef DEBUG - print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->info, ivsize, 1); - print_hex_dump(KERN_ERR, "src @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), edesc->src_nents ? 100 : req->nbytes, 1); #endif @@ -2532,7 +1132,7 @@ in_options = 0; } else { src_dma = edesc->sec4_sg_dma; - sec4_sg_index += edesc->src_nents + 1; + sec4_sg_index += (iv_contig ? 0 : 1) + edesc->src_nents; in_options = LDST_SGF; } append_seq_in_ptr(desc, src_dma, req->nbytes + ivsize, in_options); @@ -2558,59 +1158,10 @@ } /* - * Fill in ablkcipher givencrypt job descriptor - */ -static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, - struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req, - bool iv_contig) -{ - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - u32 *desc = edesc->hw_desc; - u32 out_options, in_options; - dma_addr_t dst_dma, src_dma; - int len, sec4_sg_index = 0; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "presciv@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, - ivsize, 1); - print_hex_dump(KERN_ERR, "src @" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents ? 100 : req->nbytes, 1); -#endif - - len = desc_len(sh_desc); - init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); - - if (!edesc->src_nents) { - src_dma = sg_dma_address(req->src); - in_options = 0; - } else { - src_dma = edesc->sec4_sg_dma; - sec4_sg_index += edesc->src_nents; - in_options = LDST_SGF; - } - append_seq_in_ptr(desc, src_dma, req->nbytes, in_options); - - if (iv_contig) { - dst_dma = edesc->iv_dma; - out_options = 0; - } else { - dst_dma = edesc->sec4_sg_dma + - sec4_sg_index * sizeof(struct sec4_sg_entry); - out_options = LDST_SGF; - } - append_seq_out_ptr(desc, dst_dma, req->nbytes + ivsize, out_options); -} - -/* * allocate and map the aead extended descriptor */ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, - int desc_bytes, bool *all_contig_ptr, - bool encrypt) + int desc_bytes, bool *all_contig_ptr) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct caam_ctx *ctx = crypto_aead_ctx(aead); @@ -2625,26 +1176,15 @@ bool assoc_chained = false, src_chained = false, dst_chained = false; int ivsize = crypto_aead_ivsize(aead); int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; - unsigned int authsize = ctx->authsize; - bool is_gcm = false; assoc_nents = sg_count(req->assoc, req->assoclen, &assoc_chained); + src_nents = sg_count(req->src, req->cryptlen, &src_chained); - if (unlikely(req->dst != req->src)) { - src_nents = sg_count(req->src, req->cryptlen, &src_chained); - dst_nents = sg_count(req->dst, - req->cryptlen + - (encrypt ? authsize : (-authsize)), - &dst_chained); - } else { - src_nents = sg_count(req->src, - req->cryptlen + - (encrypt ? authsize : 0), - &src_chained); - } + if (unlikely(req->dst != req->src)) + dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained); sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, - DMA_TO_DEVICE, assoc_chained); + DMA_BIDIRECTIONAL, assoc_chained); if (likely(req->src == req->dst)) { sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, DMA_BIDIRECTIONAL, src_chained); @@ -2655,43 +1195,23 @@ DMA_FROM_DEVICE, dst_chained); } + /* Check if data are contiguous */ iv_dma = dma_map_single(jrdev, req->iv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - return ERR_PTR(-ENOMEM); - } - - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - - /* - * Check if data are contiguous. - * GCM expected input sequence: IV, AAD, text - * All other - expected input sequence: AAD, IV, text - */ - if (is_gcm) - all_contig = (!assoc_nents && - iv_dma + ivsize == sg_dma_address(req->assoc) && - !src_nents && sg_dma_address(req->assoc) + - req->assoclen == sg_dma_address(req->src)); - else - all_contig = (!assoc_nents && sg_dma_address(req->assoc) + - req->assoclen == iv_dma && !src_nents && - iv_dma + ivsize == sg_dma_address(req->src)); - if (!all_contig) { + if (assoc_nents || sg_dma_address(req->assoc) + req->assoclen != + iv_dma || src_nents || iv_dma + ivsize != + sg_dma_address(req->src)) { + all_contig = false; assoc_nents = assoc_nents ? : 1; src_nents = src_nents ? : 1; sec4_sg_len = assoc_nents + 1 + src_nents; } - 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"); @@ -2708,46 +1228,32 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct aead_edesc) + desc_bytes; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); *all_contig_ptr = all_contig; sec4_sg_index = 0; if (!all_contig) { - if (!is_gcm) { - sg_to_sec4_sg(req->assoc, - assoc_nents, - edesc->sec4_sg + - sec4_sg_index, 0); - sec4_sg_index += assoc_nents; - } - + sg_to_sec4_sg(req->assoc, + (assoc_nents ? : 1), + edesc->sec4_sg + + sec4_sg_index, 0); + sec4_sg_index += assoc_nents ? : 1; dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, iv_dma, ivsize, 0); sec4_sg_index += 1; - - if (is_gcm) { - sg_to_sec4_sg(req->assoc, - assoc_nents, - edesc->sec4_sg + - sec4_sg_index, 0); - sec4_sg_index += assoc_nents; - } - sg_to_sec4_sg_last(req->src, - src_nents, + (src_nents ? : 1), edesc->sec4_sg + sec4_sg_index, 0); - sec4_sg_index += src_nents; + sec4_sg_index += src_nents ? : 1; } if (dst_nents) { sg_to_sec4_sg_last(req->dst, dst_nents, edesc->sec4_sg + sec4_sg_index, 0); } - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return ERR_PTR(-ENOMEM); - } + dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, + DMA_TO_DEVICE); return edesc; } @@ -2762,9 +1268,11 @@ u32 *desc; int ret = 0; + req->cryptlen += ctx->authsize; + /* allocate extended descriptor */ edesc = aead_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &all_contig, true); + CAAM_CMD_SZ, &all_contig); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -2772,7 +1280,7 @@ init_aead_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req, all_contig, true); #ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, desc_bytes(edesc->hw_desc), 1); #endif @@ -2801,12 +1309,12 @@ /* allocate extended descriptor */ edesc = aead_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &all_contig, false); + CAAM_CMD_SZ, &all_contig); if (IS_ERR(edesc)) return PTR_ERR(edesc); #ifdef DEBUG - print_hex_dump(KERN_ERR, "dec src@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "dec src@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), req->cryptlen, 1); #endif @@ -2815,7 +1323,7 @@ init_aead_job(ctx->sh_desc_dec, ctx->sh_desc_dec_dma, edesc, req, all_contig, false); #ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, desc_bytes(edesc->hw_desc), 1); #endif @@ -2853,17 +1361,15 @@ int ivsize = crypto_aead_ivsize(aead); bool assoc_chained = false, src_chained = false, dst_chained = false; int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; - bool is_gcm = false; assoc_nents = sg_count(req->assoc, req->assoclen, &assoc_chained); src_nents = sg_count(req->src, req->cryptlen, &src_chained); if (unlikely(req->dst != req->src)) - dst_nents = sg_count(req->dst, req->cryptlen + ctx->authsize, - &dst_chained); + dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained); sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, - DMA_TO_DEVICE, assoc_chained); + DMA_BIDIRECTIONAL, assoc_chained); if (likely(req->src == req->dst)) { sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, DMA_BIDIRECTIONAL, src_chained); @@ -2874,64 +1380,32 @@ DMA_FROM_DEVICE, dst_chained); } + /* Check if data are contiguous */ iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - return ERR_PTR(-ENOMEM); - } - - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - - /* - * Check if data are contiguous. - * GCM expected input sequence: IV, AAD, text - * All other - expected input sequence: AAD, IV, text - */ - - if (is_gcm) { - if (assoc_nents || iv_dma + ivsize != - sg_dma_address(req->assoc) || src_nents || - sg_dma_address(req->assoc) + req->assoclen != - sg_dma_address(req->src)) - contig &= ~GIV_SRC_CONTIG; - } else { - if (assoc_nents || - sg_dma_address(req->assoc) + req->assoclen != iv_dma || - src_nents || iv_dma + ivsize != sg_dma_address(req->src)) - contig &= ~GIV_SRC_CONTIG; - } - + if (assoc_nents || sg_dma_address(req->assoc) + req->assoclen != + iv_dma || src_nents || iv_dma + ivsize != sg_dma_address(req->src)) + contig &= ~GIV_SRC_CONTIG; if (dst_nents || iv_dma + ivsize != sg_dma_address(req->dst)) contig &= ~GIV_DST_CONTIG; - + if (unlikely(req->src != req->dst)) { + dst_nents = dst_nents ? : 1; + sec4_sg_len += 1; + } if (!(contig & GIV_SRC_CONTIG)) { assoc_nents = assoc_nents ? : 1; src_nents = src_nents ? : 1; sec4_sg_len += assoc_nents + 1 + src_nents; - if (req->src == req->dst && - (src_nents || iv_dma + ivsize != sg_dma_address(req->src))) - contig &= ~GIV_DST_CONTIG; - } - - /* - * Add new sg entries for GCM output sequence. - * Expected output sequence: IV, encrypted text. - */ - if (is_gcm && req->src == req->dst && !(contig & GIV_DST_CONTIG)) - sec4_sg_len += 1 + src_nents; - - if (unlikely(req->src != req->dst)) { - dst_nents = dst_nents ? : 1; - sec4_sg_len += 1 + dst_nents; + if (likely(req->src == req->dst)) + contig &= ~GIV_DST_CONTIG; } + 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"); @@ -2948,40 +1422,24 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct aead_edesc) + desc_bytes; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); *contig_ptr = contig; sec4_sg_index = 0; if (!(contig & GIV_SRC_CONTIG)) { - if (!is_gcm) { - sg_to_sec4_sg(req->assoc, assoc_nents, - edesc->sec4_sg + sec4_sg_index, 0); - sec4_sg_index += assoc_nents; - } - + sg_to_sec4_sg(req->assoc, assoc_nents, + edesc->sec4_sg + + sec4_sg_index, 0); + sec4_sg_index += assoc_nents; dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, iv_dma, ivsize, 0); sec4_sg_index += 1; - - if (is_gcm) { - sg_to_sec4_sg(req->assoc, assoc_nents, - edesc->sec4_sg + sec4_sg_index, 0); - sec4_sg_index += assoc_nents; - } - sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg + sec4_sg_index, 0); sec4_sg_index += src_nents; } - - if (is_gcm && req->src == req->dst && !(contig & GIV_DST_CONTIG)) { - dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, - iv_dma, ivsize, 0); - sec4_sg_index += 1; - sg_to_sec4_sg_last(req->src, src_nents, - edesc->sec4_sg + sec4_sg_index, 0); - } - if (unlikely(req->src != req->dst && !(contig & GIV_DST_CONTIG))) { dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, iv_dma, ivsize, 0); @@ -2989,12 +1447,8 @@ sg_to_sec4_sg_last(req->dst, dst_nents, edesc->sec4_sg + sec4_sg_index, 0); } - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return ERR_PTR(-ENOMEM); - } + dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, + DMA_TO_DEVICE); return edesc; } @@ -3010,6 +1464,8 @@ u32 *desc; int ret = 0; + req->cryptlen += ctx->authsize; + /* allocate extended descriptor */ edesc = aead_giv_edesc_alloc(areq, DESC_JOB_IO_LEN * CAAM_CMD_SZ, &contig); @@ -3018,7 +1474,7 @@ return PTR_ERR(edesc); #ifdef DEBUG - print_hex_dump(KERN_ERR, "giv src@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "giv src@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), req->cryptlen, 1); #endif @@ -3027,7 +1483,7 @@ init_aead_giv_job(ctx->sh_desc_givenc, ctx->sh_desc_givenc_dma, edesc, req, contig); #ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, desc_bytes(edesc->hw_desc), 1); #endif @@ -3044,11 +1500,6 @@ return ret; } -static int aead_null_givencrypt(struct aead_givcrypt_request *areq) -{ - return aead_encrypt(&areq->areq); -} - /* * allocate and map the ablkcipher extended descriptor for ablkcipher */ @@ -3086,16 +1537,12 @@ DMA_FROM_DEVICE, dst_chained); } - iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - return ERR_PTR(-ENOMEM); - } - /* * Check if iv can be contiguous with source and destination. * 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 @@ -3104,7 +1551,7 @@ sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + + edesc = kzalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + sec4_sg_bytes, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); @@ -3134,15 +1581,13 @@ edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return ERR_PTR(-ENOMEM); - } - 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__)": ", + print_hex_dump(KERN_ERR, "ablkcipher sec4_sg@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, sec4_sg_bytes, 1); #endif @@ -3171,7 +1616,7 @@ init_ablkcipher_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req, iv_contig); #ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, desc_bytes(edesc->hw_desc), 1); #endif @@ -3209,7 +1654,7 @@ ctx->sh_desc_dec_dma, edesc, req, iv_contig); desc = edesc->hw_desc; #ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, desc_bytes(edesc->hw_desc), 1); #endif @@ -3225,291 +1670,28 @@ return ret; } -/* - * allocate and map the ablkcipher extended descriptor - * for ablkcipher givencrypt - */ -static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( - struct skcipher_givcrypt_request *greq, - int desc_bytes, - bool *iv_contig_out) -{ - struct ablkcipher_request *req = &greq->creq; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) ? - GFP_KERNEL : GFP_ATOMIC; - int src_nents, dst_nents = 0, sec4_sg_bytes; - struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma = 0; - bool iv_contig = false; - int sgc; - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - bool src_chained = false, dst_chained = false; - int sec4_sg_index; - - src_nents = sg_count(req->src, req->nbytes, &src_chained); - - if (unlikely(req->dst != req->src)) - dst_nents = sg_count(req->dst, req->nbytes, &dst_chained); - - if (likely(req->src == req->dst)) { - sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, - DMA_BIDIRECTIONAL, src_chained); - } else { - sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, - DMA_TO_DEVICE, src_chained); - sgc = dma_map_sg_chained(jrdev, req->dst, dst_nents ? : 1, - DMA_FROM_DEVICE, dst_chained); - } - - /* - * Check if iv can be contiguous with source and destination. - * If so, include it. If not, create scatterlist. - */ - iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - return ERR_PTR(-ENOMEM); - } - - if (!dst_nents && iv_dma + ivsize == sg_dma_address(req->dst)) - iv_contig = true; - else - dst_nents = dst_nents ? : 1; - sec4_sg_bytes = ((iv_contig ? 0 : 1) + src_nents + dst_nents) * - sizeof(struct sec4_sg_entry); - - /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(*edesc) + desc_bytes + - sec4_sg_bytes, GFP_DMA | flags); - if (!edesc) { - dev_err(jrdev, "could not allocate extended descriptor\n"); - return ERR_PTR(-ENOMEM); - } - - edesc->src_nents = src_nents; - edesc->src_chained = src_chained; - edesc->dst_nents = dst_nents; - edesc->dst_chained = dst_chained; - edesc->sec4_sg_bytes = sec4_sg_bytes; - edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + - desc_bytes; - - sec4_sg_index = 0; - if (src_nents) { - sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0); - sec4_sg_index += src_nents; - } - - if (!iv_contig) { - dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, - iv_dma, ivsize, 0); - sec4_sg_index += 1; - sg_to_sec4_sg_last(req->dst, dst_nents, - edesc->sec4_sg + sec4_sg_index, 0); - } - - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return ERR_PTR(-ENOMEM); - } - edesc->iv_dma = iv_dma; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher sec4_sg@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, - sec4_sg_bytes, 1); -#endif - - *iv_contig_out = iv_contig; - return edesc; -} - -static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq) -{ - struct ablkcipher_request *req = &creq->creq; - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct device *jrdev = ctx->jrdev; - bool iv_contig; - u32 *desc; - int ret = 0; - - /* allocate extended descriptor */ - edesc = ablkcipher_giv_edesc_alloc(creq, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); - if (IS_ERR(edesc)) - return PTR_ERR(edesc); - - /* Create and submit job descriptor*/ - init_ablkcipher_giv_job(ctx->sh_desc_givenc, ctx->sh_desc_givenc_dma, - edesc, req, iv_contig); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher jobdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif - desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req); - - if (!ret) { - ret = -EINPROGRESS; - } else { - ablkcipher_unmap(jrdev, edesc, req); - kfree(edesc); - } - - return ret; -} - #define template_aead template_u.aead #define template_ablkcipher template_u.ablkcipher struct caam_alg_template { char name[CRYPTO_MAX_ALG_NAME]; - char driver_name[CRYPTO_MAX_ALG_NAME]; - unsigned int blocksize; - u32 type; - union { - struct ablkcipher_alg ablkcipher; - struct aead_alg aead; - struct blkcipher_alg blkcipher; - struct cipher_alg cipher; - struct compress_alg compress; - struct rng_alg rng; - } template_u; - u32 class1_alg_type; - u32 class2_alg_type; - u32 alg_op; -}; - -static struct caam_alg_template driver_algs[] = { - /* single-pass ipsec_esp descriptor */ - { - .name = "authenc(hmac(md5),ecb(cipher_null))", - .driver_name = "authenc-hmac-md5-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", - .ivsize = NULL_IV_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, - }, - { - .name = "authenc(hmac(sha1),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha1-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", - .ivsize = NULL_IV_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, - }, - { - .name = "authenc(hmac(sha224),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha224-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", - .ivsize = NULL_IV_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, - }, - { - .name = "authenc(hmac(sha256),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha256-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", - .ivsize = NULL_IV_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA256 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, - }, - { - .name = "authenc(hmac(sha384),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha384-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", - .ivsize = NULL_IV_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, - }, - { - .name = "authenc(hmac(sha512),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha512-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", - .ivsize = NULL_IV_SIZE, - .maxauthsize = SHA512_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA512 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, - }, + char driver_name[CRYPTO_MAX_ALG_NAME]; + unsigned int blocksize; + u32 type; + union { + struct ablkcipher_alg ablkcipher; + struct aead_alg aead; + struct blkcipher_alg blkcipher; + struct cipher_alg cipher; + struct compress_alg compress; + struct rng_alg rng; + } template_u; + u32 class1_alg_type; + u32 class2_alg_type; + u32 alg_op; +}; + +static struct caam_alg_template driver_algs[] = { + /* single-pass ipsec_esp descriptor */ { .name = "authenc(hmac(md5),cbc(aes))", .driver_name = "authenc-hmac-md5-cbc-aes-caam", @@ -3865,188 +2047,81 @@ OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, }, + /* ablkcipher descriptor */ { - .name = "authenc(hmac(md5),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-md5-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, - }, - { - .name = "authenc(hmac(sha1),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha1-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, - }, - { - .name = "authenc(hmac(sha224),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha224-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, + .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_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_ECB, }, { - .name = "authenc(hmac(sha256),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha256-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA256 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .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 = "authenc(hmac(sha384),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha384-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, + .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_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB, }, { - .name = "authenc(hmac(sha512),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha512-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA512_DIGEST_SIZE, + .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, - .class2_alg_type = OP_ALG_ALGSEL_SHA512 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, - }, - { - .name = "rfc4106(gcm(aes))", - .driver_name = "rfc4106-gcm-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = rfc4106_setkey, - .setauthsize = rfc4106_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = 8, - .maxauthsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, - }, - { - .name = "rfc4543(gcm(aes))", - .driver_name = "rfc4543-gcm-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = rfc4543_setkey, - .setauthsize = rfc4543_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = 8, - .maxauthsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, - }, - /* Galois Counter Mode */ - { - .name = "gcm(aes)", - .driver_name = "gcm-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = gcm_setkey, - .setauthsize = gcm_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = NULL, - .geniv = "", - .ivsize = 12, - .maxauthsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, }, - /* ablkcipher descriptor */ { .name = "cbc(aes)", .driver_name = "cbc-aes-caam", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", + .geniv = "eseqiv", .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, @@ -4054,16 +2129,31 @@ .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, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", + .geniv = "eseqiv", .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, .ivsize = DES3_EDE_BLOCK_SIZE, @@ -4074,58 +2164,23 @@ .name = "cbc(des)", .driver_name = "cbc-des-caam", .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", + .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_CBC, - }, - { - .name = "ctr(aes)", - .driver_name = "ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "chainiv", - .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 = "rfc3686(ctr(aes))", - .driver_name = "rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", - .min_keysize = AES_MIN_KEY_SIZE + - CTR_RFC3686_NONCE_SIZE, - .max_keysize = AES_MAX_KEY_SIZE + - CTR_RFC3686_NONCE_SIZE, - .ivsize = CTR_RFC3686_IV_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, } }; struct caam_crypto_alg { struct list_head entry; + struct device *ctrldev; int class1_alg_type; int class2_alg_type; int alg_op; @@ -4138,12 +2193,14 @@ struct caam_crypto_alg *caam_alg = container_of(alg, struct caam_crypto_alg, crypto_alg); struct caam_ctx *ctx = crypto_tfm_ctx(tfm); + struct caam_drv_private *priv = dev_get_drvdata(caam_alg->ctrldev); + int tgt_jr = atomic_inc_return(&priv->tfm_count); - 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); - } + /* + * distribute tfms across job rings to ensure in-order + * crypto request processing per tfm + */ + ctx->jrdev = priv->algapi_jr[(tgt_jr / 2) % priv->num_jrs_for_algapi]; /* copy descriptor header template value */ ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam_alg->class1_alg_type; @@ -4170,31 +2227,57 @@ dma_unmap_single(ctx->jrdev, ctx->sh_desc_givenc_dma, desc_bytes(ctx->sh_desc_givenc), DMA_TO_DEVICE); - if (ctx->key_dma && - !dma_mapping_error(ctx->jrdev, ctx->key_dma)) - dma_unmap_single(ctx->jrdev, ctx->key_dma, - ctx->enckeylen + ctx->split_key_pad_len, - DMA_TO_DEVICE); - - caam_jr_free(ctx->jrdev); } static void __exit caam_algapi_exit(void) { + struct device_node *dev_node; + struct platform_device *pdev; + struct device *ctrldev; + struct caam_drv_private *priv; struct caam_crypto_alg *t_alg, *n; + int i, err; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { + 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) { + of_node_put(dev_node); + return; + } - if (!alg_list.next) + ctrldev = &pdev->dev; + priv = dev_get_drvdata(ctrldev); + + if (!priv->alg_list.next) { + of_node_put(dev_node); return; + } - list_for_each_entry_safe(t_alg, n, &alg_list, entry) { + list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) { crypto_unregister_alg(&t_alg->crypto_alg); list_del(&t_alg->entry); kfree(t_alg); } + + for (i = 0; i < priv->total_jobrs; i++) { + err = caam_jr_deregister(priv->algapi_jr[i]); + if (err < 0) + break; + } + kfree(priv->algapi_jr); + + of_node_put(dev_node); } -static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template +static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, + struct caam_alg_template *template) { struct caam_crypto_alg *t_alg; @@ -4202,7 +2285,7 @@ t_alg = kzalloc(sizeof(struct caam_crypto_alg), GFP_KERNEL); if (!t_alg) { - pr_err("failed to allocate t_alg\n"); + dev_err(ctrldev, "failed to allocate t_alg\n"); return ERR_PTR(-ENOMEM); } @@ -4218,13 +2301,13 @@ 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_GIVCIPHER: - alg->cra_type = &crypto_givcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - break; case CRYPTO_ALG_TYPE_ABLKCIPHER: alg->cra_type = &crypto_ablkcipher_type; alg->cra_ablkcipher = template->template_ablkcipher; @@ -4238,6 +2321,7 @@ t_alg->class1_alg_type = template->class1_alg_type; t_alg->class2_alg_type = template->class2_alg_type; t_alg->alg_op = template->alg_op; + t_alg->ctrldev = ctrldev; return t_alg; } @@ -4246,9 +2330,11 @@ { struct device_node *dev_node; struct platform_device *pdev; - struct device *ctrldev; - void *priv; - int i = 0, err = 0; + struct device *ctrldev, **jrdev; + 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) { @@ -4265,42 +2351,117 @@ ctrldev = &pdev->dev; priv = dev_get_drvdata(ctrldev); - of_node_put(dev_node); - /* - * 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(&priv->alg_list); + + jrdev = kmalloc(sizeof(*jrdev) * priv->total_jobrs, GFP_ATOMIC); + if (!jrdev) { + of_node_put(dev_node); + return -ENOMEM; + } + for (i = 0; i < priv->total_jobrs; i++) { + err = caam_jr_register(ctrldev, &jrdev[i]); + if (err < 0) + break; + } + if (err < 0 && i == 0) { + dev_err(ctrldev, "algapi error in job ring registration: %d\n", + err); + of_node_put(dev_node); + kfree(jrdev); + return err; + } - INIT_LIST_HEAD(&alg_list); + priv->num_jrs_for_algapi = i; + priv->algapi_jr = jrdev; + atomic_set(&priv->tfm_count, -1); + + /* + * 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; + } - /* register crypto algorithms the device supports */ 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]); + t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", - driver_algs[i].driver_name); + dev_warn(ctrldev, "%s alg allocation failed\n", + driver_algs[i].driver_name); continue; } err = crypto_register_alg(&t_alg->crypto_alg); if (err) { - pr_warn("%s alg registration failed\n", + dev_warn(ctrldev, "%s alg registration failed\n", t_alg->crypto_alg.cra_driver_name); kfree(t_alg); - } else - list_add_tail(&t_alg->entry, &alg_list); + } else { + list_add_tail(&t_alg->entry, &priv->alg_list); + dev_info(ctrldev, "%s\n", + t_alg->crypto_alg.cra_driver_name); + + if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD && + !memcmp(driver_algs[i].name, "authenc", 7) && + !done) { + char *name; + + name = driver_algs[i].name; + memmove(name + 10, name + 7, strlen(name) - 7); + memcpy(name + 7, "esn", 3); + + name = driver_algs[i].driver_name; + memmove(name + 10, name + 7, strlen(name) - 7); + memcpy(name + 7, "esn", 3); + + done = true; + goto authencesn; + } + } } - if (!list_empty(&alg_list)) - pr_info("caam algorithms registered in /proc/crypto\n"); + if (!list_empty(&priv->alg_list)) + dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", + (char *)of_get_property(dev_node, "compatible", NULL)); + + of_node_put(dev_node); return err; } diff -Nur linux-4.1.13.orig/drivers/crypto/caam/caamhash.c linux-4.1.13/drivers/crypto/caam/caamhash.c --- linux-4.1.13.orig/drivers/crypto/caam/caamhash.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/caamhash.c 2015-11-30 17:56:13.548139857 +0100 @@ -1,7 +1,7 @@ /* * caam - Freescale FSL CAAM support for ahash functions of crypto API * - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. * * Based on caamalg.c crypto API driver. * @@ -62,6 +62,7 @@ #include "error.h" #include "sg_sw_sec4.h" #include "key_gen.h" +#include #define CAAM_CRA_PRIORITY 3000 @@ -72,6 +73,8 @@ #define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE /* length of descriptors text */ +#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3) + #define DESC_AHASH_BASE (4 * CAAM_CMD_SZ) #define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ) #define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) @@ -89,14 +92,13 @@ #ifdef DEBUG /* for print_hex_dumps with line references */ +#define xstr(s) str(s) +#define str(s) #s #define debug(format, arg...) printk(format, arg) #else #define debug(format, arg...) #endif - -static struct list_head hash_list; - /* ahash per-session context */ struct caam_hash_ctx { struct device *jrdev; @@ -115,6 +117,7 @@ u8 key[CAAM_MAX_HASH_KEY_SIZE]; dma_addr_t key_dma; int ctx_len; + unsigned int key_len; unsigned int split_key_len; unsigned int split_key_pad_len; }; @@ -137,20 +140,13 @@ /* Common job descriptor seq in/out ptr routines */ /* Map state->caam_ctx, and append seq_out_ptr command that points to it */ -static inline int map_seq_out_ptr_ctx(u32 *desc, struct device *jrdev, - struct caam_hash_state *state, - int ctx_len) +static inline void map_seq_out_ptr_ctx(u32 *desc, struct device *jrdev, + struct caam_hash_state *state, + int ctx_len) { state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, ctx_len, DMA_FROM_DEVICE); - if (dma_mapping_error(jrdev, state->ctx_dma)) { - dev_err(jrdev, "unable to map ctx\n"); - return -ENOMEM; - } - append_seq_out_ptr(desc, state->ctx_dma, ctx_len, 0); - - return 0; } /* Map req->result, and append seq_out_ptr command that points to it */ @@ -173,6 +169,7 @@ dma_addr_t buf_dma; buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE); + dma_sync_single_for_device(jrdev, buf_dma, buflen, DMA_TO_DEVICE); dma_to_sec4_sg_one(sec4_sg, buf_dma, buflen, 0); return buf_dma; @@ -208,19 +205,17 @@ } /* Map state->caam_ctx, and add it to link table */ -static inline int ctx_map_to_sec4_sg(u32 *desc, struct device *jrdev, - struct caam_hash_state *state, int ctx_len, - struct sec4_sg_entry *sec4_sg, u32 flag) +static inline void ctx_map_to_sec4_sg(u32 *desc, struct device *jrdev, + struct caam_hash_state *state, + int ctx_len, + struct sec4_sg_entry *sec4_sg, + u32 flag) { state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, ctx_len, flag); - if (dma_mapping_error(jrdev, state->ctx_dma)) { - dev_err(jrdev, "unable to map ctx\n"); - return -ENOMEM; - } - + 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); - - return 0; } /* Common shared descriptor commands */ @@ -231,6 +226,13 @@ KEY_DEST_MDHA_SPLIT | KEY_ENC); } +static inline void append_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx) +{ + append_key_as_imm(desc, ctx->key, ctx->key_len, + ctx->key_len, CLASS_1 | + KEY_DEST_CLASS_REG); +} + /* Append key if it has been set */ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) { @@ -252,6 +254,25 @@ append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); } +static inline void init_sh_desc_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx) +{ + u32 *key_jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + if (ctx->key_len) { + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + append_key_axcbc(desc, ctx); + + set_jump_tgt_here(desc, key_jump_cmd); + } + + /* Propagate errors from shared to job descriptor */ + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + +} /* * For ahash read data from seqin following state->caam_ctx, * and write resulting class2 context to seqout, which may be state->caam_ctx @@ -271,6 +292,20 @@ LDST_SRCDST_BYTE_CONTEXT); } +static inline void axcbc_append_load_str(u32 *desc, int digestsize) +{ + /* Calculate remaining bytes to read */ + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Read remaining bytes */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 | + FIFOLD_TYPE_MSG | KEY_VLF); + + /* Store class1 context bytes */ + append_seq_store(desc, digestsize, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT); +} + /* * For ahash update, final and finup, import context, read and write to seqout */ @@ -293,6 +328,27 @@ ahash_append_load_str(desc, digestsize); } +/* + * For ahash update, final and finup, import context, read and write to seqout + */ +static inline void axcbc_ctx_data_to_out(u32 *desc, u32 op, u32 state, + int digestsize, + struct caam_hash_ctx *ctx) +{ + init_sh_desc_key_axcbc(desc, ctx); + + /* Import context from software */ + append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | ctx->ctx_len); + + /* Class 1 operation */ + append_operation(desc, op | state | OP_ALG_ENCRYPT); + + /* + * Load from buf and/or src and write to req->result or state->context + */ + axcbc_append_load_str(desc, digestsize); +} /* For ahash firsts and digest, read and write to seqout */ static inline void ahash_data_to_out(u32 *desc, u32 op, u32 state, int digestsize, struct caam_hash_ctx *ctx) @@ -308,6 +364,21 @@ ahash_append_load_str(desc, digestsize); } +/* For ahash firsts and digest, read and write to seqout */ +static inline void axcbc_data_to_out(u32 *desc, u32 op, u32 state, + int digestsize, struct caam_hash_ctx *ctx) +{ + init_sh_desc_key_axcbc(desc, ctx); + + /* Class 1 operation */ + append_operation(desc, op | state | OP_ALG_ENCRYPT); + + /* + * Load from buf and/or src and write to req->result or state->context + */ + axcbc_append_load_str(desc, digestsize); +} + static int ahash_set_sh_desc(struct crypto_ahash *ahash) { struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); @@ -342,8 +413,7 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, - "ahash update shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ahash update shdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -361,10 +431,11 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, - "ahash update first shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ahash update first shdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, + desc_bytes(desc), DMA_TO_DEVICE); /* ahash_final shared descriptor */ desc = ctx->sh_desc_fin; @@ -379,10 +450,12 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ahash final shdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, + desc_bytes(desc), DMA_TO_DEVICE); /* ahash_finup shared descriptor */ desc = ctx->sh_desc_finup; @@ -397,10 +470,12 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, "ahash finup shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ahash finup shdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_finup_dma, + desc_bytes(desc), DMA_TO_DEVICE); /* ahash_digest shared descriptor */ desc = ctx->sh_desc_digest; @@ -416,15 +491,134 @@ return -ENOMEM; } #ifdef DEBUG - print_hex_dump(KERN_ERR, - "ahash digest shdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ahash digest shdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, + desc_bytes(desc), DMA_TO_DEVICE); return 0; } +static int axcbc_set_sh_desc(struct crypto_ahash *ahash) +{ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int digestsize = crypto_ahash_digestsize(ahash); + struct device *jrdev = ctx->jrdev; + u32 have_key = 0; + u32 *desc; + + /* ahash_update shared descriptor */ + desc = ctx->sh_desc_update; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Import context from software */ + append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | ctx->ctx_len); + + /* Class 1 operation */ + append_operation(desc, ctx->alg_type | OP_ALG_AS_UPDATE | + OP_ALG_ENCRYPT); + + /* Load data and write to result or context */ + axcbc_append_load_str(desc, ctx->ctx_len); + + ctx->sh_desc_update_dma = dma_map_single(jrdev, desc, desc_bytes(desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->sh_desc_update_dma)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ahash update shdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif + + /* ahash_update_first shared descriptor */ + desc = ctx->sh_desc_update_first; + + axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INIT, + ctx->ctx_len, ctx); + + ctx->sh_desc_update_first_dma = dma_map_single(jrdev, desc, + desc_bytes(desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->sh_desc_update_first_dma)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ahash update first shdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, + desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_final shared descriptor */ + desc = ctx->sh_desc_fin; + + axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type, + OP_ALG_AS_FINALIZE, digestsize, ctx); + + ctx->sh_desc_fin_dma = dma_map_single(jrdev, desc, desc_bytes(desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->sh_desc_fin_dma)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ahash final shdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); +#endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, + desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_finup shared descriptor */ + desc = ctx->sh_desc_finup; + + axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type, + OP_ALG_AS_FINALIZE, digestsize, ctx); + + ctx->sh_desc_finup_dma = dma_map_single(jrdev, desc, desc_bytes(desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->sh_desc_finup_dma)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ahash finup shdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); +#endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_finup_dma, + desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_digest shared descriptor */ + desc = ctx->sh_desc_digest; + + axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INITFINAL, + digestsize, ctx); + + ctx->sh_desc_digest_dma = dma_map_single(jrdev, desc, + desc_bytes(desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->sh_desc_digest_dma)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ahash digest shdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); +#endif + dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, + desc_bytes(desc), DMA_TO_DEVICE); + + return 0; +} static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in, u32 keylen) { @@ -458,6 +652,8 @@ kfree(desc); return -ENOMEM; } + dma_sync_single_for_device(jrdev, src_dma, *keylen, DMA_TO_DEVICE); + dst_dma = dma_map_single(jrdev, (void *)key_out, digestsize, DMA_FROM_DEVICE); if (dma_mapping_error(jrdev, dst_dma)) { @@ -478,9 +674,9 @@ LDST_SRCDST_BYTE_CONTEXT); #ifdef DEBUG - print_hex_dump(KERN_ERR, "key_in@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "key_in@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_in, *keylen, 1); - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -493,17 +689,17 @@ wait_for_completion_interruptible(&result.completion); ret = result.err; #ifdef DEBUG - print_hex_dump(KERN_ERR, - "digested key@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "digested key@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_in, digestsize, 1); #endif } + *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); - *keylen = digestsize; - kfree(desc); return ret; @@ -545,7 +741,7 @@ #ifdef DEBUG printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", ctx->split_key_len, ctx->split_key_pad_len); - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif @@ -557,11 +753,14 @@ DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->key_dma)) { dev_err(jrdev, "unable to map key i/o memory\n"); - ret = -ENOMEM; - goto map_err; + 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__)": ", + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ctx->split_key_pad_len, 1); #endif @@ -572,7 +771,6 @@ DMA_TO_DEVICE); } -map_err: kfree(hashed_key); return ret; badkey: @@ -581,6 +779,25 @@ return -EINVAL; } +static int axcbc_setkey(struct crypto_ahash *ahash, + const u8 *key, unsigned int keylen) +{ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int ret = 0; + + ctx->key_len = keylen; + memcpy(ctx->key, key, keylen); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->key_len, 1); +#endif + + ret = axcbc_set_sh_desc(ahash); + + return ret; +} /* * ahash_edesc - s/w-extended ahash descriptor * @dst_dma: physical mapped address of req->result @@ -608,8 +825,11 @@ if (edesc->src_nents) dma_unmap_sg_chained(dev, req->src, edesc->src_nents, DMA_TO_DEVICE, edesc->chained); - if (edesc->dst_dma) + if (edesc->dst_dma) { + dma_sync_single_for_cpu(dev, edesc->dst_dma, dst_len, + DMA_FROM_DEVICE); dma_unmap_single(dev, edesc->dst_dma, dst_len, DMA_FROM_DEVICE); + } if (edesc->sec4_sg_bytes) dma_unmap_single(dev, edesc->sec4_sg_dma, @@ -624,8 +844,12 @@ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct caam_hash_state *state = ahash_request_ctx(req); - if (state->ctx_dma) + if (state->ctx_dma) { + if ((flag == DMA_FROM_DEVICE) || (flag == DMA_BIDIRECTIONAL)) + dma_sync_single_for_cpu(dev, state->ctx_dma, + ctx->ctx_len, flag); dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag); + } ahash_unmap(dev, edesc, req, dst_len); } @@ -645,18 +869,21 @@ edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } ahash_unmap(jrdev, edesc, req, digestsize); kfree(edesc); #ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, ctx->ctx_len, 1); if (req->result) - print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->result, digestsize, 1); #endif @@ -680,18 +907,21 @@ edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL); kfree(edesc); #ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, ctx->ctx_len, 1); if (req->result) - print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->result, digestsize, 1); #endif @@ -715,18 +945,21 @@ edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; - ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_TO_DEVICE); + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_FROM_DEVICE); kfree(edesc); #ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, ctx->ctx_len, 1); if (req->result) - print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->result, digestsize, 1); #endif @@ -750,18 +983,21 @@ edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } - ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_FROM_DEVICE); + ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE); kfree(edesc); #ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, ctx->ctx_len, 1); if (req->result) - print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->result, digestsize, 1); #endif @@ -807,7 +1043,7 @@ * allocate space for base edesc and hw desc commands, * link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, @@ -820,11 +1056,12 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, + DMA_TO_DEVICE); - ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len, - edesc->sec4_sg, DMA_BIDIRECTIONAL); - if (ret) - return ret; + ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len, + edesc->sec4_sg, DMA_BIDIRECTIONAL); state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, @@ -851,21 +1088,16 @@ init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE); - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return -ENOMEM; - } - append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + to_hash, LDST_SGF); 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__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -885,9 +1117,9 @@ *next_buflen = last_buflen; } #ifdef DEBUG - print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "buf@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); - print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "next buf@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, 1); #endif @@ -919,7 +1151,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"); @@ -933,37 +1165,29 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); edesc->src_nents = 0; - ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len, - edesc->sec4_sg, DMA_TO_DEVICE); - if (ret) - return ret; + ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len, edesc->sec4_sg, + DMA_TO_DEVICE); state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, buf, state->buf_dma, buflen, last_buflen); (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN; - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return -ENOMEM; - } - append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + buflen, LDST_SGF); edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, digestsize); - if (dma_mapping_error(jrdev, edesc->dst_dma)) { - dev_err(jrdev, "unable to map dst\n"); - return -ENOMEM; - } + + 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__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -1006,7 +1230,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"); @@ -1022,11 +1246,11 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); - ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len, - edesc->sec4_sg, DMA_TO_DEVICE); - if (ret) - return ret; + ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len, edesc->sec4_sg, + DMA_TO_DEVICE); state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, buf, state->buf_dma, buflen, @@ -1035,25 +1259,17 @@ src_map_to_sec4_sg(jrdev, req->src, src_nents, edesc->sec4_sg + sec4_sg_src_index, chained); - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return -ENOMEM; - } - append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + buflen + req->nbytes, LDST_SGF); edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, digestsize); - if (dma_mapping_error(jrdev, edesc->dst_dma)) { - dev_err(jrdev, "unable to map dst\n"); - return -ENOMEM; - } + + 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__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -1092,7 +1308,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"); @@ -1100,6 +1316,8 @@ } edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) + 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; @@ -1110,12 +1328,6 @@ if (src_nents) { sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0); - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return -ENOMEM; - } src_dma = edesc->sec4_sg_dma; options = LDST_SGF; } else { @@ -1124,15 +1336,14 @@ } 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); - if (dma_mapping_error(jrdev, edesc->dst_dma)) { - dev_err(jrdev, "unable to map dst\n"); - return -ENOMEM; - } #ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -1166,7 +1377,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"); @@ -1179,23 +1390,17 @@ init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE); state->buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, state->buf_dma)) { - dev_err(jrdev, "unable to map src\n"); - return -ENOMEM; - } append_seq_in_ptr(desc, state->buf_dma, buflen, 0); edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, digestsize); - if (dma_mapping_error(jrdev, edesc->dst_dma)) { - dev_err(jrdev, "unable to map dst\n"); - return -ENOMEM; - } 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__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -1246,7 +1451,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, @@ -1259,7 +1464,9 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN; - edesc->dst_dma = 0; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, + DMA_TO_DEVICE); state->buf_dma = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, buf, *buflen); @@ -1277,22 +1484,14 @@ init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE); - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return -ENOMEM; - } - append_seq_in_ptr(desc, edesc->sec4_sg_dma, to_hash, LDST_SGF); - ret = map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); - if (ret) - return ret; + 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__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -1315,9 +1514,9 @@ *next_buflen = 0; } #ifdef DEBUG - print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "buf@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); - print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "next buf@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, 1); #endif @@ -1353,7 +1552,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"); @@ -1369,6 +1568,8 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, buf, state->buf_dma, buflen, @@ -1377,25 +1578,17 @@ src_map_to_sec4_sg(jrdev, req->src, src_nents, edesc->sec4_sg + 1, chained); - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return -ENOMEM; - } - append_seq_in_ptr(desc, edesc->sec4_sg_dma, buflen + req->nbytes, LDST_SGF); edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, digestsize); - if (dma_mapping_error(jrdev, edesc->dst_dma)) { - dev_err(jrdev, "unable to map dst\n"); - return -ENOMEM; - } + + 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__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -1448,7 +1641,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, @@ -1461,19 +1654,13 @@ edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN; - edesc->dst_dma = 0; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, + DMA_TO_DEVICE); if (src_nents) { sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0); - edesc->sec4_sg_dma = dma_map_single(jrdev, - edesc->sec4_sg, - sec4_sg_bytes, - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return -ENOMEM; - } src_dma = edesc->sec4_sg_dma; options = LDST_SGF; } else { @@ -1492,12 +1679,12 @@ append_seq_in_ptr(desc, src_dma, to_hash, options); - ret = map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); - if (ret) - return ret; + 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__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -1522,7 +1709,7 @@ req->nbytes, 0); } #ifdef DEBUG - print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "next buf@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, 1); #endif @@ -1736,10 +1923,33 @@ .alg_type = OP_ALG_ALGSEL_MD5, .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, }, + { + .name = "xcbc(aes)", + .driver_name = "xcbc-aes-caam", + .hmac_name = "xcbc(aes)", + .hmac_driver_name = "xcbc-aes-caam", + .blocksize = XCBC_MAC_BLOCK_WORDS * 4, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = axcbc_setkey, + .halg = { + .digestsize = XCBC_MAC_DIGEST_SIZE, + }, + }, + .alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC, + .alg_op = OP_ALG_ALGSEL_AES, + }, }; struct caam_hash_alg { struct list_head entry; + struct device *ctrldev; int alg_type; int alg_op; struct ahash_alg ahash_alg; @@ -1756,6 +1966,7 @@ struct caam_hash_alg *caam_hash = container_of(alg, struct caam_hash_alg, ahash_alg); struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); + struct caam_drv_private *priv = dev_get_drvdata(caam_hash->ctrldev); /* Sizes for MDHA running digests: MD5, SHA1, 224, 256, 384, 512 */ static const u8 runninglen[] = { HASH_MSG_LEN + MD5_DIGEST_SIZE, HASH_MSG_LEN + SHA1_DIGEST_SIZE, @@ -1763,17 +1974,15 @@ HASH_MSG_LEN + SHA256_DIGEST_SIZE, HASH_MSG_LEN + 64, HASH_MSG_LEN + SHA512_DIGEST_SIZE }; + int tgt_jr = atomic_inc_return(&priv->tfm_count); int ret = 0; /* - * Get a Job ring from Job Ring driver to ensure in-order + * distribute tfms across job rings 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); - } + ctx->jrdev = priv->jrdev[tgt_jr % priv->total_jobrs]; + /* copy descriptor header template value */ ctx->alg_type = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_hash->alg_op; @@ -1789,6 +1998,39 @@ return ret; } +static int caam_axcbc_cra_init(struct crypto_tfm *tfm) +{ + struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); + struct crypto_alg *base = tfm->__crt_alg; + struct hash_alg_common *halg = + container_of(base, struct hash_alg_common, base); + struct ahash_alg *alg = + container_of(halg, struct ahash_alg, halg); + struct caam_hash_alg *caam_hash = + container_of(alg, struct caam_hash_alg, ahash_alg); + struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); + struct caam_drv_private *priv = dev_get_drvdata(caam_hash->ctrldev); + int tgt_jr = atomic_inc_return(&priv->tfm_count); + int ret = 0; + + /* + * distribute tfms across job rings to ensure in-order + * crypto request processing per tfm + */ + ctx->jrdev = priv->jrdev[tgt_jr % priv->total_jobrs]; + + /* copy descriptor header template value */ + ctx->alg_type = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; + ctx->alg_op = OP_TYPE_CLASS1_ALG | caam_hash->alg_op; + + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct caam_hash_state)); + + ret = axcbc_set_sh_desc(ahash); + + return ret; +} + static void caam_hash_cra_exit(struct crypto_tfm *tfm) { struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); @@ -1816,35 +2058,57 @@ !dma_mapping_error(ctx->jrdev, ctx->sh_desc_finup_dma)) dma_unmap_single(ctx->jrdev, ctx->sh_desc_finup_dma, desc_bytes(ctx->sh_desc_finup), DMA_TO_DEVICE); - - caam_jr_free(ctx->jrdev); } static void __exit caam_algapi_hash_exit(void) { + struct device_node *dev_node; + struct platform_device *pdev; + struct device *ctrldev; + struct caam_drv_private *priv; struct caam_hash_alg *t_alg, *n; - if (!hash_list.next) + 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) { + of_node_put(dev_node); return; + } - list_for_each_entry_safe(t_alg, n, &hash_list, entry) { + ctrldev = &pdev->dev; + priv = dev_get_drvdata(ctrldev); + + if (!priv->hash_list.next) { + of_node_put(dev_node); + return; + } + + list_for_each_entry_safe(t_alg, n, &priv->hash_list, entry) { crypto_unregister_ahash(&t_alg->ahash_alg); list_del(&t_alg->entry); kfree(t_alg); } + + of_node_put(dev_node); } static struct caam_hash_alg * -caam_hash_alloc(struct caam_hash_template *template, +caam_hash_alloc(struct device *ctrldev, struct caam_hash_template *template, bool keyed) { struct caam_hash_alg *t_alg; struct ahash_alg *halg; struct crypto_alg *alg; - t_alg = kzalloc(sizeof(struct caam_hash_alg), GFP_KERNEL); + t_alg = kzalloc(sizeof(struct caam_hash_alg), GFP_ATOMIC); if (!t_alg) { - pr_err("failed to allocate t_alg\n"); + dev_err(ctrldev, "failed to allocate t_alg\n"); return ERR_PTR(-ENOMEM); } @@ -1864,7 +2128,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; @@ -1875,6 +2143,7 @@ t_alg->alg_type = template->alg_type; t_alg->alg_op = template->alg_op; + t_alg->ctrldev = ctrldev; return t_alg; } @@ -1884,8 +2153,9 @@ struct device_node *dev_node; struct platform_device *pdev; struct device *ctrldev; - void *priv; - int i = 0, err = 0; + 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) { @@ -1899,60 +2169,68 @@ of_node_put(dev_node); return -ENODEV; } - ctrldev = &pdev->dev; priv = dev_get_drvdata(ctrldev); - of_node_put(dev_node); - /* - * 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(&priv->hash_list); - INIT_LIST_HEAD(&hash_list); + atomic_set(&priv->tfm_count, -1); + + /* 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; + } - /* register crypto algorithms the device supports */ 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); + t_alg = caam_hash_alloc(ctrldev, &driver_hash[i], true); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", - driver_hash[i].driver_name); + dev_warn(ctrldev, "%s alg allocation failed\n", + driver_hash[i].driver_name); continue; } err = crypto_register_ahash(&t_alg->ahash_alg); if (err) { - pr_warn("%s alg registration failed\n", + dev_warn(ctrldev, "%s alg registration failed\n", t_alg->ahash_alg.halg.base.cra_driver_name); kfree(t_alg); } else - list_add_tail(&t_alg->entry, &hash_list); + list_add_tail(&t_alg->entry, &priv->hash_list); /* register unkeyed version */ - t_alg = caam_hash_alloc(&driver_hash[i], false); + t_alg = caam_hash_alloc(ctrldev, &driver_hash[i], false); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", - driver_hash[i].driver_name); + dev_warn(ctrldev, "%s alg allocation failed\n", + driver_hash[i].driver_name); continue; } err = crypto_register_ahash(&t_alg->ahash_alg); if (err) { - pr_warn("%s alg registration failed\n", + dev_warn(ctrldev, "%s alg registration failed\n", t_alg->ahash_alg.halg.base.cra_driver_name); kfree(t_alg); } else - list_add_tail(&t_alg->entry, &hash_list); + list_add_tail(&t_alg->entry, &priv->hash_list); } + of_node_put(dev_node); return err; } diff -Nur linux-4.1.13.orig/drivers/crypto/caam/caam_keyblob.c linux-4.1.13/drivers/crypto/caam/caam_keyblob.c --- linux-4.1.13.orig/drivers/crypto/caam/caam_keyblob.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/caam_keyblob.c 2015-11-30 17:56:13.548139857 +0100 @@ -0,0 +1,687 @@ +/* + * Key blob driver based on CAAM hardware + * + * Copyright (C) 2015 Freescale Semiconductor, Inc. + */ + +#include +#include + +#include "compat.h" +#include "regs.h" +#include "jr.h" +#include "desc.h" +#include "intern.h" +#include "sm.h" +#include "caam_keyblob.h" + +#define INITIAL_DESCSZ 16 /* size of tmp buffer for descriptor const. */ + +/** + * struct kb_device - the metadata of the caam key blob device node + * @dev: the actual misc device + */ +struct kb_device { + struct miscdevice misc_dev; + struct device *jr_dev; +}; + +/* + * Pseudo-synchronous ring access functions for carrying out key + * encapsulation and decapsulation + */ + +struct sm_key_job_result { + int error; + struct completion completion; +}; + + +static struct kb_device *kb_dev; + +static struct kb_device *kb_device_create(void); +static int kb_device_destroy(struct kb_device *kb_dev); +static int kb_open(struct inode *inode, struct file *file); +static int kb_release(struct inode *inode, struct file *file); +static void sm_key_job_done(struct device *dev, u32 *desc, + u32 err, void *context); +static int gen_mem_encap(struct device *jr_dev, void __user *secretbuf, + int keylen, void __user *kmodbuf, void __user *outbuf); +static int gen_mem_decap(struct device *jr_dev, void __user *keyblobbuf, + int bloblen, void __user *kmodbuf, void __user *outbuf); +static long kb_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static int caam_keyblob_probe(struct platform_device *pdev); +static int caam_keyblob_remove(struct platform_device *pdev); + +static int kb_open(struct inode *inode, struct file *file) +{ + struct miscdevice *miscdev = file->private_data; + struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev); + struct device *jr_dev; + + if (!dev->jr_dev) { + jr_dev = caam_jr_alloc(); + if (IS_ERR(jr_dev)) { + pr_err("Job Ring Device allocation for transform failed\n"); + return -ENOMEM; + } + pr_info("Allocate a job ring device\n"); + dev->jr_dev = jr_dev; + } + else { + pr_err("Already created a job ring device"); + return -EPERM; + } + + return 0; +} + +static int kb_release(struct inode *inode, struct file *file) +{ + struct miscdevice *miscdev = file->private_data; + struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev); + + if (dev && dev->jr_dev) { + caam_jr_free(dev->jr_dev); + pr_info("Free a job ring device\n"); + dev->jr_dev = NULL; + } + return 0; +} + +static 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 */ +} + +/* + * 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; +} + + + +static int gen_mem_encap(struct device *jr_dev, void __user *secretbuf, + int keylen, void __user *kmodbuf, void __user *outbuf) +{ + int retval = 0; + u32 dsize; + u32 __iomem *encapdesc = NULL; + dma_addr_t secret_dma = 0, keymod_dma = 0, outbuf_dma = 0; + u8 __iomem *lsecret = NULL, *lkeymod = NULL, *loutbuf = NULL; + struct sm_key_job_result testres; + + /* Build/map/flush the scret */ + lsecret = kmalloc(keylen, GFP_KERNEL | GFP_DMA); + if (!lsecret) { + dev_err(jr_dev, "%s: can't alloc for key\n", __func__); + retval = -ENOMEM; + goto out; + } + if (copy_from_user(lsecret, secretbuf, keylen)) { + dev_err(jr_dev, "%s: can't Copy for key\n", __func__); + retval = -EFAULT; + goto out; + } + secret_dma = dma_map_single(jr_dev, lsecret, keylen, + DMA_TO_DEVICE); + + /* Build/map/flush the key modifier */ + lkeymod = kmalloc(GENMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA); + if (!lkeymod) { + dev_err(jr_dev, "%s: can't alloc for keymod\n", __func__); + retval = -ENOMEM; + goto out; + } + if (copy_from_user(lkeymod, kmodbuf, GENMEM_KEYMOD_LEN)) { + dev_err(jr_dev, "%s: can't Copy for keymod\n", __func__); + retval = -EFAULT; + goto out; + } + keymod_dma = dma_map_single(jr_dev, lkeymod, GENMEM_KEYMOD_LEN, + DMA_TO_DEVICE); + + loutbuf = kmalloc(keylen + BLOB_OVERHEAD, GFP_KERNEL | GFP_DMA); + if (!lkeymod) { + dev_err(jr_dev, "%s: can't alloc for output\n", __func__); + retval = -ENOMEM; + goto out; + } + outbuf_dma = dma_map_single(jr_dev, loutbuf, keylen + BLOB_OVERHEAD, + DMA_FROM_DEVICE); + dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, (void *)secret_dma, outbuf_dma, + keylen, RED_KEY, SM_GENMEM, KEY_COVER_ECB); + if (!dsize) { + dev_err(jr_dev, "can't alloc an encapsulation descriptor\n"); + retval = -ENOMEM; + goto out; + } + init_completion(&testres.completion); + + retval = caam_jr_enqueue(jr_dev, encapdesc, sm_key_job_done, + &testres); + if (!retval) { + wait_for_completion_interruptible(&testres.completion); + dev_info(jr_dev, "job ring return %d\n", testres.error); + if (!testres.error) { + dma_sync_single_for_cpu(jr_dev, outbuf_dma, keylen + BLOB_OVERHEAD, + DMA_FROM_DEVICE); + + if (copy_to_user(outbuf, loutbuf, keylen + BLOB_OVERHEAD)) { + retval = -EFAULT; + dev_err(jr_dev, "can't copy for output\n"); + goto out; + } + } + retval = testres.error; + } + +out: + if (outbuf_dma) + dma_unmap_single(jr_dev, outbuf_dma, keylen + BLOB_OVERHEAD, + DMA_FROM_DEVICE); + if (keymod_dma) + dma_unmap_single(jr_dev, keymod_dma, GENMEM_KEYMOD_LEN, DMA_TO_DEVICE); + if (secret_dma) + dma_unmap_single(jr_dev, secret_dma, keylen, DMA_TO_DEVICE); + kfree(encapdesc); + kfree(lkeymod); + kfree(lsecret); + kfree(loutbuf); + + return retval; +} + +static int gen_mem_decap(struct device *jr_dev, void __user *keyblobbuf, + int bloblen, void __user *kmodbuf, void __user *outbuf) +{ + int retval = 0; + int keylen = bloblen - BLOB_OVERHEAD; + u32 dsize; + dma_addr_t keyblob_dma = 0, keymod_dma = 0, outbuf_dma = 0; + u8 __iomem *lkeyblob = NULL, *lkeymod = NULL, *loutbuf = NULL; + struct sm_key_job_result testres; + u32 __iomem *decapdesc = NULL; + + /* Build/map/flush the scret */ + lkeyblob = kmalloc(bloblen, GFP_KERNEL | GFP_DMA); + if (!lkeyblob) { + dev_err(jr_dev, "%s: can't alloc for keylob\n", __func__); + retval = -ENOMEM; + goto out; + } + if (copy_from_user(lkeyblob, keyblobbuf, bloblen)) { + dev_err(jr_dev, "%s: can't Copy for keyblob\n", __func__); + retval = -EFAULT; + goto out; + } + keyblob_dma = dma_map_single(jr_dev, lkeyblob, bloblen, + DMA_TO_DEVICE); + + /* Build/map/flush the key modifier */ + lkeymod = kmalloc(GENMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA); + if (!lkeymod) { + dev_err(jr_dev, "%s: can't alloc for keymod\n", __func__); + retval = -ENOMEM; + goto out; + } + if (copy_from_user(lkeymod, kmodbuf, GENMEM_KEYMOD_LEN)) { + dev_err(jr_dev, "%s: can't Copy for keymod\n", __func__); + retval = -EFAULT; + goto out; + } + keymod_dma = dma_map_single(jr_dev, lkeymod, GENMEM_KEYMOD_LEN, + DMA_TO_DEVICE); + + loutbuf = kmalloc(keylen, GFP_KERNEL | GFP_DMA); + if (!loutbuf) { + dev_err(jr_dev, "%s: can't alloc for outbuf\n", __func__); + retval = -ENOMEM; + goto out; + } + outbuf_dma = dma_map_single(jr_dev, loutbuf, keylen, + DMA_FROM_DEVICE); + + /* Build the encapsulation job descriptor */ + dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, keyblob_dma, (u8 *)outbuf_dma, + keylen, RED_KEY, SM_GENMEM, KEY_COVER_ECB); + if (!dsize) { + dev_err(jr_dev, "can't alloc a decapsulation descriptor\n"); + retval = -ENOMEM; + goto out; + } + + init_completion(&testres.completion); + + retval = caam_jr_enqueue(jr_dev, decapdesc, sm_key_job_done, + &testres); + if (!retval) { + wait_for_completion_interruptible(&testres.completion); + dev_info(jr_dev, "job ring return %d\n", testres.error); + if (!testres.error) { + dma_sync_single_for_cpu(jr_dev, outbuf_dma, keylen, + DMA_FROM_DEVICE); + + if (copy_to_user(outbuf, loutbuf, keylen)) { + retval = -EFAULT; + goto out; + } + } + retval = testres.error; + } + +out: + if (outbuf_dma) + dma_unmap_single(jr_dev, outbuf_dma, keylen, + DMA_FROM_DEVICE); + if (keymod_dma) + dma_unmap_single(jr_dev, keymod_dma, GENMEM_KEYMOD_LEN, + DMA_TO_DEVICE); + if (keyblob_dma) + dma_unmap_single(jr_dev, keyblob_dma, bloblen, + DMA_TO_DEVICE); + kfree(decapdesc); + kfree(lkeymod); + kfree(lkeyblob); + kfree(loutbuf); + + return retval; +} + + +static long kb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + struct caam_kb_data kb_data; + struct miscdevice *miscdev = file->private_data; + struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev); + + if (copy_from_user(&kb_data, (void *)arg, sizeof(kb_data))) { + retval = -EFAULT; + goto err; + } + + if (!kb_data.rawkey || !kb_data.keyblob || + (kb_data.rawkey_len + BLOB_OVERHEAD != kb_data.keyblob_len) || + (kb_data.keymod_len != GENMEM_KEYMOD_LEN)) { + retval = -EINVAL; + goto err; + } + + printk(KERN_INFO"%s:rawkey_len %d, keyblob_len %d\n", + __func__, kb_data.rawkey_len, kb_data.keyblob_len); + + switch (cmd) { + case CAAM_KB_ENCRYPT: + { + retval = gen_mem_encap(dev->jr_dev, kb_data.rawkey, kb_data.rawkey_len, + kb_data.keymod, kb_data.keyblob); + break; + } + case CAAM_KB_DECRYPT: + { + retval = gen_mem_decap(dev->jr_dev, kb_data.keyblob, kb_data.keyblob_len, + kb_data.keymod, kb_data.rawkey); + break; + } + default: + return -ENOTTY; + } + +err: + return retval; +} + +static const struct file_operations kb_fops = { + .owner = THIS_MODULE, + .open = kb_open, + .release = kb_release, + .unlocked_ioctl = kb_ioctl, +}; + +static struct kb_device *kb_device_create(void) +{ + struct kb_device *idev; + int ret; + + idev = kzalloc(sizeof(struct kb_device), GFP_KERNEL); + if (!idev) + return ERR_PTR(-ENOMEM); + + idev->misc_dev.minor = MISC_DYNAMIC_MINOR; + idev->misc_dev.name = "caam_kb"; + idev->misc_dev.fops = &kb_fops; + idev->misc_dev.parent = NULL; + ret = misc_register(&idev->misc_dev); + if (ret) { + pr_err("ion: failed to register misc device.\n"); + return ERR_PTR(ret); + } + + return idev; +} + +static int kb_device_destroy(struct kb_device *kb_dev) +{ + if ((kb_dev) && (kb_dev->jr_dev)) { + caam_jr_free(kb_dev->jr_dev); + kb_dev->jr_dev = NULL; + } + + if (kb_dev) + misc_deregister(&kb_dev->misc_dev); + + return 0; +} +/* + * Probe key blob device + */ +static int caam_keyblob_probe(struct platform_device *pdev) +{ + int err; + + dev_dbg(&pdev->dev, "%s enter\n", __func__); + kb_dev = kb_device_create(); + if (IS_ERR_OR_NULL(kb_dev)) { + err = PTR_ERR(kb_dev); + goto err; + } + return 0; +err: + return err; +} + +/* + * Remove key blob device + */ +static int caam_keyblob_remove(struct platform_device *pdev) +{ + kb_device_destroy(kb_dev); + return 0; +} + +static struct of_device_id caam_keyblob_match[] = { + { + .compatible = "fsl,sec-v4.0-keyblob", + }, + { + .compatible = "fsl,sec4.0-keyblob", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, caam_keyblob_match); + +static struct platform_driver caam_keyblob_driver = { + .driver = { + .name = "caam_keyblob", + .owner = THIS_MODULE, + .of_match_table = caam_keyblob_match, + }, + .probe = caam_keyblob_probe, + .remove = caam_keyblob_remove, +}; + +static int __init keyblob_driver_init(void) +{ + return platform_driver_register(&caam_keyblob_driver); +} + +static void __exit keyblob_driver_exit(void) +{ + platform_driver_unregister(&caam_keyblob_driver); +} + +module_init(keyblob_driver_init); +module_exit(keyblob_driver_exit); + + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore"); +MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); diff -Nur linux-4.1.13.orig/drivers/crypto/caam/caam_keyblob.h linux-4.1.13/drivers/crypto/caam/caam_keyblob.h --- linux-4.1.13.orig/drivers/crypto/caam/caam_keyblob.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/caam_keyblob.h 2015-11-30 17:56:13.548139857 +0100 @@ -0,0 +1,45 @@ +/* + * CAAM public-level include definitions for the key blob + * + * Copyright (C) 2015 Freescale Semiconductor, Inc. + */ + +#ifndef CAAM_KEYBLOB_H +#define CAAM_KEYBLOB_H + + +#include +#include + +struct caam_kb_data { + char *rawkey; + size_t rawkey_len; + char *keyblob; + size_t keyblob_len; + char *keymod; + size_t keymod_len; +}; + + +#define CAAM_KB_MAGIC 'I' + +/** + * DOC: CAAM_KB_ENCRYPT - generate a key blob from raw key + * + * Takes an caam_kb_data struct and returns it with the key blob + */ +#define CAAM_KB_ENCRYPT _IOWR(CAAM_KB_MAGIC, 0, \ + struct caam_kb_data) + +/** + * DOC: CAAM_KB_DECRYPT - get keys from a key blob + * + * Takes an caam_kb_data struct and returns it with the raw key. + */ +#define CAAM_KB_DECRYPT _IOWR(CAAM_KB_MAGIC, 1, struct caam_kb_data) + +#ifndef GENMEM_KEYMOD_LEN +#define GENMEM_KEYMOD_LEN 16 +#endif + +#endif /* CAAM_KEYBLOB_H */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/caamrng.c linux-4.1.13/drivers/crypto/caam/caamrng.c --- linux-4.1.13.orig/drivers/crypto/caam/caamrng.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/caamrng.c 2015-11-30 17:56:13.548139857 +0100 @@ -1,7 +1,7 @@ /* * caam - Freescale FSL CAAM support for hw_random * - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. * * Based on caamalg.c crypto API driver. * @@ -80,9 +80,12 @@ 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) @@ -103,11 +106,18 @@ bd = (struct buf_data *)((char *)desc - offsetof(struct buf_data, hw_desc)); - if (err) - caam_jr_strstatus(jrdev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } 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); @@ -185,7 +195,7 @@ max - copied_idx, false); } -static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx) +static inline void rng_create_sh_desc(struct caam_rng_ctx *ctx) { struct device *jrdev = ctx->jrdev; u32 *desc = ctx->sh_desc; @@ -203,18 +213,16 @@ ctx->sh_desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } + 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); #endif - return 0; } -static inline int rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id) +static inline void rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id) { struct device *jrdev = ctx->jrdev; struct buf_data *bd = &ctx->bufs[buf_id]; @@ -225,17 +233,12 @@ HDR_REVERSE); bd->addr = dma_map_single(jrdev, bd->buf, RN_BUF_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(jrdev, bd->addr)) { - dev_err(jrdev, "unable to map dst\n"); - return -ENOMEM; - } append_seq_out_ptr_intlen(desc, bd->addr, RN_BUF_SIZE, 0); #ifdef DEBUG print_hex_dump(KERN_ERR, "rng job desc@: ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif - return 0; } static void caam_cleanup(struct hwrng *rng) @@ -252,44 +255,67 @@ rng_unmap_ctx(rng_ctx); } -static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id) +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST +static inline void test_len(struct hwrng *rng, size_t len, bool wait) { - struct buf_data *bd = &ctx->bufs[buf_id]; - int err; + u8 *buf; + int real_len; - err = rng_create_job_desc(ctx, buf_id); - if (err) - return err; + 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); +} - atomic_set(&bd->empty, BUF_EMPTY); - submit_job(ctx, buf_id == ctx->current_buf); - wait_for_completion(&bd->filled); +static inline void test_mode_once(struct hwrng *rng, bool wait) +{ +#define TEST_CHUNK (RN_BUF_SIZE / 4) - return 0; + 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 int caam_init_rng(struct caam_rng_ctx *ctx, struct device *jrdev) +static inline void test_mode(struct hwrng *rng, bool wait) { - int err; - - ctx->jrdev = jrdev; +#define TEST_PASS 1 + int i; - err = rng_create_sh_desc(ctx); - if (err) - return err; + for (i = 0; i < TEST_PASS; i++) + test_mode_once(rng, wait); +} - ctx->current_buf = 0; - ctx->cur_buf_idx = 0; +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 - err = caam_init_buf(ctx, 0); - if (err) - return err; +static void caam_init_buf(struct caam_rng_ctx *ctx, int buf_id) +{ + struct buf_data *bd = &ctx->bufs[buf_id]; - err = caam_init_buf(ctx, 1); - if (err) - return err; + rng_create_job_desc(ctx, buf_id); + atomic_set(&bd->empty, BUF_EMPTY); + submit_job(ctx, buf_id == ctx->current_buf); + wait_for_completion(&bd->filled); +} - return 0; +static void caam_init_rng(struct caam_rng_ctx *ctx, struct device *jrdev) +{ + ctx->jrdev = jrdev; + rng_create_sh_desc(ctx); + ctx->current_buf = 0; + ctx->cur_buf_idx = 0; + caam_init_buf(ctx, 0); + caam_init_buf(ctx, 1); } static struct hwrng caam_rng = { @@ -300,19 +326,15 @@ static void __exit caam_rng_exit(void) { - caam_jr_free(rng_ctx->jrdev); hwrng_unregister(&caam_rng); - kfree(rng_ctx); } static int __init caam_rng_init(void) { - struct device *dev; struct device_node *dev_node; struct platform_device *pdev; struct device *ctrldev; - void *priv; - int err; + struct caam_drv_private *priv; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); if (!dev_node) { @@ -322,35 +344,26 @@ } pdev = of_find_device_by_node(dev_node); - if (!pdev) { - of_node_put(dev_node); + if (!pdev) return -ENODEV; - } ctrldev = &pdev->dev; priv = dev_get_drvdata(ctrldev); of_node_put(dev_node); - /* - * 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) + /* Check RNG present in hardware before registration */ + if (!(rd_reg64(&priv->ctrl->perfmon.cha_num) & CHA_ID_RNG_MASK)) return -ENODEV; - dev = caam_jr_alloc(); - if (IS_ERR(dev)) { - pr_err("Job Ring Device allocation for transform failed\n"); - return PTR_ERR(dev); - } - rng_ctx = kmalloc(sizeof(struct caam_rng_ctx), GFP_DMA); - if (!rng_ctx) - return -ENOMEM; - err = caam_init_rng(rng_ctx, dev); - if (err) - return err; + rng_ctx = kmalloc(sizeof(struct caam_rng_ctx), GFP_KERNEL | GFP_DMA); + + caam_init_rng(rng_ctx, priv->jrdev[0]); + +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST + self_test(&caam_rng); +#endif - dev_info(dev, "registering rng-caam\n"); + dev_info(priv->jrdev[0], "registering rng-caam\n"); return hwrng_register(&caam_rng); } diff -Nur linux-4.1.13.orig/drivers/crypto/caam/compat.h linux-4.1.13/drivers/crypto/caam/compat.h --- linux-4.1.13.orig/drivers/crypto/caam/compat.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/compat.h 2015-11-30 17:56:13.548139857 +0100 @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,12 +25,15 @@ #include #include #include +#include + +#ifdef CONFIG_ARM /* needs the clock control subsystem */ +#include +#endif #include #include -#include #include -#include #include #include #include diff -Nur linux-4.1.13.orig/drivers/crypto/caam/ctrl.c linux-4.1.13/drivers/crypto/caam/ctrl.c --- linux-4.1.13.orig/drivers/crypto/caam/ctrl.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/ctrl.c 2015-11-30 17:56:13.548139857 +0100 @@ -1,405 +1,260 @@ -/* * CAAM control-plane driver backend +/* + * CAAM control-plane driver backend * Controller-level driver, kernel property detection, initialization * - * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. */ -#include -#include -#include - #include "compat.h" #include "regs.h" #include "intern.h" #include "jr.h" #include "desc_constr.h" #include "error.h" +#include "ctrl.h" +#include "sm.h" +#include -/* - * Descriptor to instantiate RNG State Handle 0 in normal mode and - * load the JDKEK, TDKEK and TDSK registers - */ -static void build_instantiation_desc(u32 *desc, int handle, int do_sk) -{ - u32 *jump_cmd, op_flags; - - init_job_desc(desc, 0); - - op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | - (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT; - - /* INIT RNG in non-test mode */ - append_operation(desc, op_flags); - - if (!handle && do_sk) { - /* - * For SH0, Secure Keys must be generated as well - */ +/* Used to capture the array of job rings */ +struct device **caam_jr_dev; - /* wait for done */ - jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); - set_jump_tgt_here(desc, jump_cmd); +static int caam_remove(struct platform_device *pdev) +{ + struct device *ctrldev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_jr *jrpriv; + struct caam_full __iomem *topregs; + int ring, ret = 0; - /* - * load 1 to clear written reg: - * resets the done interrrupt and returns the RNG to idle. - */ - append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; - /* Initialize State Handle */ - append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | - OP_ALG_AAI_RNG4_SK); + /* shut down JobRs */ + for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { + ret |= caam_jr_shutdown(ctrlpriv->jrdev[ring]); + jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]); + irq_dispose_mapping(jrpriv->irq); } - append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); -} + /* Shut down debug views */ +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(ctrlpriv->dfs_root); +#endif -/* Descriptor for deinstantiation of State Handle 0 of the RNG block. */ -static void build_deinstantiation_desc(u32 *desc, int handle) -{ - init_job_desc(desc, 0); + /* Unmap controller region */ + iounmap(&topregs->ctrl); - /* Uninstantiate State Handle 0 */ - append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | - (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL); +#ifdef CONFIG_ARM + /* shut clocks off before finalizing shutdown */ + clk_disable(ctrlpriv->caam_ipg); + clk_disable(ctrlpriv->caam_mem); + clk_disable(ctrlpriv->caam_aclk); +#endif + + kfree(ctrlpriv->jrdev); + kfree(ctrlpriv); - append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); + return ret; } /* - * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of - * the software (no JR/QI used). - * @ctrldev - pointer to device - * @status - descriptor status, after being run - * - * Return: - 0 if no error occurred - * - -ENODEV if the DECO couldn't be acquired - * - -EAGAIN if an error occurred while executing the descriptor + * Descriptor to instantiate RNG State Handle 0 in normal mode and + * load the JDKEK, TDKEK and TDSK registers */ -static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc, - u32 *status) +static void build_instantiation_desc(u32 *desc) { - struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); - struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; - struct caam_deco __iomem *deco = ctrlpriv->deco; - unsigned int timeout = 100000; - u32 deco_dbg_reg, flags; - int i; - + u32 *jump_cmd; - if (ctrlpriv->virt_en == 1) { - setbits32(&ctrl->deco_rsr, DECORSR_JR0); - - while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) && - --timeout) - cpu_relax(); - - timeout = 100000; - } - - setbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE); - - while (!(rd_reg32(&ctrl->deco_rq) & DECORR_DEN0) && - --timeout) - cpu_relax(); + init_job_desc(desc, 0); - if (!timeout) { - dev_err(ctrldev, "failed to acquire DECO 0\n"); - clrbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE); - return -ENODEV; - } + /* INIT RNG in non-test mode */ + append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | + OP_ALG_AS_INIT); - for (i = 0; i < desc_len(desc); i++) - wr_reg32(&deco->descbuf[i], *(desc + i)); + /* wait for done */ + jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); + set_jump_tgt_here(desc, jump_cmd); - flags = DECO_JQCR_WHL; /* - * If the descriptor length is longer than 4 words, then the - * FOUR bit in JRCTRL register must be set. + * load 1 to clear written reg: + * resets the done interrupt and returns the RNG to idle. */ - if (desc_len(desc) >= 4) - flags |= DECO_JQCR_FOUR; + append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); - /* Instruct the DECO to execute it */ - wr_reg32(&deco->jr_ctl_hi, flags); - - timeout = 10000000; - do { - deco_dbg_reg = rd_reg32(&deco->desc_dbg); - /* - * If an error occured in the descriptor, then - * the DECO status field will be set to 0x0D - */ - if ((deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) == - DESC_DBG_DECO_STAT_HOST_ERR) - break; - cpu_relax(); - } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout); - - *status = rd_reg32(&deco->op_status_hi) & - DECO_OP_STATUS_HI_ERR_MASK; - - if (ctrlpriv->virt_en == 1) - clrbits32(&ctrl->deco_rsr, DECORSR_JR0); - - /* Mark the DECO as free */ - clrbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE); - - if (!timeout) - return -EAGAIN; - - return 0; } -/* - * instantiate_rng - builds and executes a descriptor on DECO0, - * which initializes the RNG block. - * @ctrldev - pointer to device - * @state_handle_mask - bitmask containing the instantiation status - * for the RNG4 state handles which exist in - * the RNG4 block: 1 if it's been instantiated - * by an external entry, 0 otherwise. - * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK; - * Caution: this can be done only once; if the keys need to be - * regenerated, a POR is required - * - * Return: - 0 if no error occurred - * - -ENOMEM if there isn't enough memory to allocate the descriptor - * - -ENODEV if DECO0 couldn't be acquired - * - -EAGAIN if an error occurred when executing the descriptor - * f.i. there was a RNG hardware error due to not "good enough" - * entropy being aquired. - */ -static int instantiate_rng(struct device *ctrldev, int state_handle_mask, - int gen_sk) +static void generate_secure_keys_desc(u32 *desc) { - struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); - struct caam_ctrl __iomem *ctrl; - u32 *desc, status, rdsta_val; - int ret = 0, sh_idx; - - ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; - desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL); - if (!desc) - return -ENOMEM; + /* generate secure keys (non-test) */ + append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | + OP_ALG_RNG4_SK); +} - for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { - /* - * If the corresponding bit is set, this state handle - * was initialized by somebody else, so it's left alone. - */ - if ((1 << sh_idx) & state_handle_mask) - continue; +struct instantiate_result { + struct completion completion; + int err; +}; - /* Create the descriptor for instantiating RNG State Handle */ - build_instantiation_desc(desc, sh_idx, gen_sk); +static void rng4_init_done(struct device *dev, u32 *desc, u32 err, + void *context) +{ + struct instantiate_result *instantiation = context; - /* Try to run it through DECO0 */ - ret = run_descriptor_deco0(ctrldev, desc, &status); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; - /* - * If ret is not 0, or descriptor status is not 0, then - * something went wrong. No need to try the next state - * handle (if available), bail out here. - * Also, if for some reason, the State Handle didn't get - * instantiated although the descriptor has finished - * without any error (HW optimizations for later - * CAAM eras), then try again. - */ - rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK; - if (status || !(rdsta_val & (1 << sh_idx))) - ret = -EAGAIN; - if (ret) - break; - dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); - /* Clear the contents before recreating the descriptor */ - memset(desc, 0x00, CAAM_CMD_SZ * 7); + dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); } - kfree(desc); - - return ret; + instantiation->err = err; + complete(&instantiation->completion); } -/* - * deinstantiate_rng - builds and executes a descriptor on DECO0, - * which deinitializes the RNG block. - * @ctrldev - pointer to device - * @state_handle_mask - bitmask containing the instantiation status - * for the RNG4 state handles which exist in - * the RNG4 block: 1 if it's been instantiated - * - * Return: - 0 if no error occurred - * - -ENOMEM if there isn't enough memory to allocate the descriptor - * - -ENODEV if DECO0 couldn't be acquired - * - -EAGAIN if an error occurred when executing the descriptor - */ -static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask) +static int instantiate_rng(struct device *jrdev, u32 keys_generated) { - u32 *desc, status; - int sh_idx, ret = 0; + struct instantiate_result instantiation; - desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL); - if (!desc) + dma_addr_t desc_dma; + u32 *desc; + int ret; + + desc = kmalloc(CAAM_CMD_SZ * 6, GFP_KERNEL | GFP_DMA); + if (!desc) { + dev_err(jrdev, "cannot allocate RNG init descriptor memory\n"); return -ENOMEM; - - for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { - /* - * If the corresponding bit is set, then it means the state - * handle was initialized by us, and thus it needs to be - * deintialized as well - */ - if ((1 << sh_idx) & state_handle_mask) { - /* - * Create the descriptor for deinstantating this state - * handle - */ - build_deinstantiation_desc(desc, sh_idx); - - /* Try to run it through DECO0 */ - ret = run_descriptor_deco0(ctrldev, desc, &status); - - if (ret || status) { - dev_err(ctrldev, - "Failed to deinstantiate RNG4 SH%d\n", - sh_idx); - break; - } - dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx); - } } - kfree(desc); - - return ret; -} + build_instantiation_desc(desc); -static int caam_remove(struct platform_device *pdev) -{ - struct device *ctrldev; - struct caam_drv_private *ctrlpriv; - struct caam_ctrl __iomem *ctrl; - int ring, ret = 0; - - ctrldev = &pdev->dev; - ctrlpriv = dev_get_drvdata(ctrldev); - ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; - - /* Remove platform devices for JobRs */ - for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { - if (ctrlpriv->jrpdev[ring]) - of_device_unregister(ctrlpriv->jrpdev[ring]); + /* If keys have not been generated, add op code to generate key. */ + if (!keys_generated) + generate_secure_keys_desc(desc); + + desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); + dma_sync_single_for_device(jrdev, desc_dma, desc_bytes(desc), + DMA_TO_DEVICE); + init_completion(&instantiation.completion); + ret = caam_jr_enqueue(jrdev, desc, rng4_init_done, &instantiation); + if (!ret) { + wait_for_completion_interruptible(&instantiation.completion); + ret = instantiation.err; + if (ret) + dev_err(jrdev, "unable to instantiate RNG\n"); } - /* De-initialize RNG state handles initialized by this driver. */ - if (ctrlpriv->rng4_sh_init) - deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init); - - /* Shut down debug views */ -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(ctrlpriv->dfs_root); -#endif + dma_unmap_single(jrdev, desc_dma, desc_bytes(desc), DMA_TO_DEVICE); - /* Unmap controller region */ - iounmap(&ctrl); + kfree(desc); return ret; } /* - * kick_trng - sets the various parameters for enabling the initialization - * of the RNG4 block in CAAM - * @pdev - pointer to the platform device - * @ent_delay - Defines the length (in system clocks) of each entropy sample. + * By default, the TRNG runs for 200 clocks per sample; + * 1600 clocks per sample generates better entropy. */ -static void kick_trng(struct platform_device *pdev, int ent_delay) +static void kick_trng(struct platform_device *pdev) { struct device *ctrldev = &pdev->dev; struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); - struct caam_ctrl __iomem *ctrl; + struct caam_full __iomem *topregs; struct rng4tst __iomem *r4tst; u32 val; - ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; - r4tst = &ctrl->r4tst[0]; + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; + r4tst = &topregs->ctrl.r4tst[0]; + val = rd_reg32(&r4tst->rtmctl); /* put RNG4 into program mode */ setbits32(&r4tst->rtmctl, RTMCTL_PRGM); - - /* - * Performance-wise, it does not make sense to - * set the delay to a value that is lower - * than the last one that worked (i.e. the state handles - * were instantiated properly. Thus, instead of wasting - * time trying to set the values controlling the sample - * frequency, the function simply returns. - */ - val = (rd_reg32(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK) - >> RTSDCTL_ENT_DLY_SHIFT; - if (ent_delay <= val) { - /* put RNG4 into run mode */ - clrbits32(&r4tst->rtmctl, RTMCTL_PRGM); - return; - } - + /* Set clocks per sample to the default, and divider to zero */ val = rd_reg32(&r4tst->rtsdctl); val = (val & ~RTSDCTL_ENT_DLY_MASK) | - (ent_delay << RTSDCTL_ENT_DLY_SHIFT); + (RNG4_ENT_CLOCKS_SAMPLE << RTSDCTL_ENT_DLY_SHIFT); wr_reg32(&r4tst->rtsdctl, val); - /* min. freq. count, equal to 1/4 of the entropy sample length */ - wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2); - /* disable maximum frequency count */ - wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE); - /* read the control register */ - val = rd_reg32(&r4tst->rtmctl); - /* - * select raw sampling in both entropy shifter - * and statistical checker - */ - setbits32(&val, RTMCTL_SAMP_MODE_RAW_ES_SC); + /* min. freq. count */ + wr_reg32(&r4tst->rtfrqmin, RNG4_ENT_CLOCKS_SAMPLE / 4); + /* max. freq. count */ + wr_reg32(&r4tst->rtfrqmax, RNG4_ENT_CLOCKS_SAMPLE * 8); /* put RNG4 into run mode */ - clrbits32(&val, RTMCTL_PRGM); - /* write back the control register */ - wr_reg32(&r4tst->rtmctl, val); + clrbits32(&r4tst->rtmctl, RTMCTL_PRGM); } /** * caam_get_era() - Return the ERA of the SEC on SoC, based - * on "sec-era" propery in the DTS. This property is updated by u-boot. + * on the SEC_VID register. + * 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(void) +int caam_get_era(u64 caam_id) { - struct device_node *caam_node; - for_each_compatible_node(caam_node, NULL, "fsl,sec-v4.0") { - const uint32_t *prop = (uint32_t *)of_get_property(caam_node, - "fsl,sec-era", - NULL); - return prop ? *prop : -ENOTSUPP; - } + struct sec_vid *sec_vid = (struct sec_vid *)&caam_id; + static const struct { + u16 ip_id; + u8 maj_rev; + u8 era; + } caam_eras[] = { + {0x0A10, 1, 1}, + {0x0A10, 2, 2}, + {0x0A12, 1, 3}, + {0x0A14, 1, 3}, + {0x0A14, 2, 4}, + {0x0A16, 1, 4}, + {0x0A11, 1, 4}, + {0x0A10, 3, 4}, + {0x0A18, 1, 4}, + {0x0A11, 2, 5}, + {0x0A12, 2, 5}, + {0x0A13, 1, 5}, + {0x0A1C, 1, 5}, + {0x0A12, 4, 6}, + {0x0A13, 2, 6}, + {0x0A16, 2, 6}, + {0x0A18, 2, 6}, + {0x0A1A, 1, 6}, + {0x0A1C, 2, 6}, + {0x0A17, 1, 6} + }; + int i; + + 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; return -ENOTSUPP; } EXPORT_SYMBOL(caam_get_era); +/* + * Return a job ring device. This is available so outside + * entities can gain direct access to the job ring. For now, + * this function returns the first job ring (at index 0). + */ +struct device *caam_get_jrdev(void) +{ + return caam_jr_dev[0]; +} +EXPORT_SYMBOL(caam_get_jrdev); + + /* Probe routine for CAAM top (controller) level */ static int caam_probe(struct platform_device *pdev) { - int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; + int ret, ring, rspec; u64 caam_id; struct device *dev; struct device_node *nprop, *np; struct caam_ctrl __iomem *ctrl; + struct caam_full __iomem *topregs; + struct snvs_full __iomem *snvsregs; struct caam_drv_private *ctrlpriv; #ifdef CONFIG_DEBUG_FS struct caam_perfmon *perfmon; #endif - u32 scfgr, comp_params; - u32 cha_vid_ls; - int pg_size; - int BLOCK_OFFSET = 0; - ctrlpriv = devm_kzalloc(&pdev->dev, sizeof(struct caam_drv_private), - GFP_KERNEL); + ctrlpriv = kzalloc(sizeof(struct caam_drv_private), GFP_KERNEL); if (!ctrlpriv) return -ENOMEM; @@ -415,71 +270,128 @@ dev_err(dev, "caam: of_iomap() failed\n"); return -ENOMEM; } - /* Finding the page size for using the CTPR_MS register */ - comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms); - pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT; - - /* Allocating the BLOCK_OFFSET based on the supported page size on - * the platform - */ - if (pg_size == 0) - BLOCK_OFFSET = PG_SIZE_4K; - else - BLOCK_OFFSET = PG_SIZE_64K; - ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl; - ctrlpriv->assure = (struct caam_assurance __force *) - ((uint8_t *)ctrl + - BLOCK_OFFSET * ASSURE_BLOCK_NUMBER - ); - ctrlpriv->deco = (struct caam_deco __force *) - ((uint8_t *)ctrl + - BLOCK_OFFSET * DECO_BLOCK_NUMBER - ); + + /* 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); + ctrlpriv->secvio_irq = of_irq_to_resource(nprop, 0, NULL); + + /* Get SNVS register Page */ + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-snvs"); + + if (!np) + return -ENODEV; + + snvsregs = of_iomap(np, 0); + ctrlpriv->snvs = snvsregs; + /* Get CAAM-SM node and of_iomap() and save */ + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm"); + + if (!np) + return -ENODEV; + + ctrlpriv->sm_base = of_iomap(np, 0); + ctrlpriv->sm_size = 0x3fff; + +/* + * ARM targets tend to have clock control subsystems that can + * enable/disable clocking to our device. Turn clocking on to proceed + */ +#ifdef CONFIG_ARM + ctrlpriv->caam_ipg = devm_clk_get(&ctrlpriv->pdev->dev, "caam_ipg"); + if (IS_ERR(ctrlpriv->caam_ipg)) { + ret = PTR_ERR(ctrlpriv->caam_ipg); + dev_err(&ctrlpriv->pdev->dev, + "can't identify CAAM ipg clk: %d\n", ret); + return -ENODEV; + } + ctrlpriv->caam_mem = devm_clk_get(&ctrlpriv->pdev->dev, "caam_mem"); + if (IS_ERR(ctrlpriv->caam_mem)) { + ret = PTR_ERR(ctrlpriv->caam_mem); + dev_err(&ctrlpriv->pdev->dev, + "can't identify CAAM secure mem clk: %d\n", ret); + return -ENODEV; + } + ctrlpriv->caam_aclk = devm_clk_get(&ctrlpriv->pdev->dev, "caam_aclk"); + if (IS_ERR(ctrlpriv->caam_aclk)) { + ret = PTR_ERR(ctrlpriv->caam_aclk); + dev_err(&ctrlpriv->pdev->dev, + "can't identify CAAM aclk clk: %d\n", ret); + return -ENODEV; + } + + ret = clk_prepare(ctrlpriv->caam_ipg); + if (ret < 0) { + dev_err(&pdev->dev, "can't prepare CAAM ipg clock: %d\n", ret); + return -ENODEV; + } + ret = clk_prepare(ctrlpriv->caam_mem); + if (ret < 0) { + dev_err(&pdev->dev, "can't prepare CAAM secure mem clock: %d\n", ret); + return -ENODEV; + } + ret = clk_prepare(ctrlpriv->caam_aclk); + if (ret < 0) { + dev_err(&pdev->dev, "can't prepare CAAM aclk clock: %d\n", ret); + return -ENODEV; + } + + ret = clk_enable(ctrlpriv->caam_ipg); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM ipg clock: %d\n", ret); + return -ENODEV; + } + ret = clk_enable(ctrlpriv->caam_mem); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n", ret); + return -ENODEV; + } + ret = clk_enable(ctrlpriv->caam_aclk); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM aclk clock: %d\n", ret); + return -ENODEV; + } + + pr_debug("%s caam_ipg clock:%d\n", __func__, + (int)clk_get_rate(ctrlpriv->caam_ipg)); + pr_debug("%s caam_mem clock:%d\n", __func__, + (int)clk_get_rate(ctrlpriv->caam_mem)); + pr_debug("%s caam_aclk clock:%d\n", __func__, + (int)clk_get_rate(ctrlpriv->caam_aclk)); +#endif /* * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, * long pointers in master configuration register */ - setbits32(&ctrl->mcr, MCFGR_WDENABLE | + setbits32(&topregs->ctrl.mcr, MCFGR_WDENABLE | (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); +#ifdef CONFIG_ARCH_MX6 /* - * Read the Compile Time paramters and SCFGR to determine - * if Virtualization is enabled for this platform + * 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. */ - scfgr = rd_reg32(&ctrl->scfgr); - - ctrlpriv->virt_en = 0; - if (comp_params & CTPR_MS_VIRT_EN_INCL) { - /* VIRT_EN_INCL = 1 & VIRT_EN_POR = 1 or - * VIRT_EN_INCL = 1 & VIRT_EN_POR = 0 & SCFGR_VIRT_EN = 1 - */ - if ((comp_params & CTPR_MS_VIRT_EN_POR) || - (!(comp_params & CTPR_MS_VIRT_EN_POR) && - (scfgr & SCFGR_VIRT_EN))) - ctrlpriv->virt_en = 1; - } else { - /* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */ - if (comp_params & CTPR_MS_VIRT_EN_POR) - ctrlpriv->virt_en = 1; - } - - if (ctrlpriv->virt_en == 1) - setbits32(&ctrl->jrstart, JRSTART_JR0_START | - JRSTART_JR1_START | JRSTART_JR2_START | - JRSTART_JR3_START); + 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_and_coherent(dev, DMA_BIT_MASK(40)); + if (of_device_is_compatible(nprop, "fsl,sec-v4.0")) + dma_set_mask(dev, DMA_BIT_MASK(40)); else - dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); + dma_set_mask(dev, DMA_BIT_MASK(36)); else - dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + dma_set_mask(dev, DMA_BIT_MASK(32)); /* * Detect and enable JobRs @@ -487,51 +399,65 @@ * for all, then go probe each one. */ rspec = 0; - for_each_available_child_of_node(nprop, np) - if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || - of_device_is_compatible(np, "fsl,sec4.0-job-ring")) + for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") + rspec++; + if (!rspec) { + /* for backward compatible with device trees */ + for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") rspec++; + } - ctrlpriv->jrpdev = devm_kzalloc(&pdev->dev, - sizeof(struct platform_device *) * rspec, - GFP_KERNEL); - if (ctrlpriv->jrpdev == NULL) { - iounmap(&ctrl); + ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL); + if (ctrlpriv->jrdev == NULL) { + iounmap(&topregs->ctrl); return -ENOMEM; } ring = 0; ctrlpriv->total_jobrs = 0; - for_each_available_child_of_node(nprop, np) - if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || - of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { - ctrlpriv->jrpdev[ring] = - of_platform_device_create(np, NULL, dev); - if (!ctrlpriv->jrpdev[ring]) { - pr_warn("JR%d Platform device creation error\n", - ring); - continue; + for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") { + ret = caam_jr_probe(pdev, np, ring); + if (ret < 0) { + /* + * Job ring not found, error out. At some + * point, we should enhance job ring handling + * to allow for non-consecutive job rings to + * be found. + */ + pr_err("fsl,sec-v4.0-job-ring not found "); + pr_err("(ring %d)\n", ring); + return ret; + } + ctrlpriv->total_jobrs++; + ring++; + } + + if (!ring) { + for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") { + ret = caam_jr_probe(pdev, np, ring); + if (ret < 0) { + /* + * Job ring not found, error out. At some + * point, we should enhance job ring handling + * to allow for non-consecutive job rings to + * be found. + */ + pr_err("fsl,sec4.0-job-ring not found "); + pr_err("(ring %d)\n", ring); + return ret; } - ctrlpriv->jr[ring] = (struct caam_job_ring __force *) - ((uint8_t *)ctrl + - (ring + JR_BLOCK_NUMBER) * - BLOCK_OFFSET - ); ctrlpriv->total_jobrs++; ring++; + } } /* Check to see if QI present. If so, enable */ - ctrlpriv->qi_present = - !!(rd_reg32(&ctrl->perfmon.comp_parms_ms) & - CTPR_MS_QI_MASK); + ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) & + CTPR_QI_MASK); if (ctrlpriv->qi_present) { - ctrlpriv->qi = (struct caam_queue_if __force *) - ((uint8_t *)ctrl + - BLOCK_OFFSET * QI_BLOCK_NUMBER - ); + ctrlpriv->qi = (struct caam_queue_if __force *)&topregs->qi; /* This is all that's required to physically enable QI */ - wr_reg32(&ctrlpriv->qi->qi_control_lo, QICTL_DQEN); + wr_reg32(&topregs->qi.qi_control_lo, QICTL_DQEN); } /* If no QI and no rings specified, quit and go home */ @@ -541,81 +467,53 @@ return -ENOMEM; } - cha_vid_ls = rd_reg32(&ctrl->perfmon.cha_id_ls); - /* - * If SEC has RNG version >= 4 and RNG state handle has not been - * already instantiated, do RNG instantiation + * RNG4 based SECs (v5+ | >= i.MX6) need special initialization prior + * to executing any descriptors. If there's a problem with init, + * remove other subsystems and return; internal padding functions + * cannot run without an RNG. This procedure assumes a single RNG4 + * instance. */ - if ((cha_vid_ls & CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT >= 4) { - ctrlpriv->rng4_sh_init = - rd_reg32(&ctrl->r4tst[0].rdsta); + if ((rd_reg64(&topregs->ctrl.perfmon.cha_id) & CHA_ID_RNG_MASK) + == CHA_ID_RNG_4) { + struct rng4tst __iomem *r4tst; + u32 rdsta, rng_if, rng_skvn; + /* - * If the secure keys (TDKEK, JDKEK, TDSK), were already - * generated, signal this to the function that is instantiating - * the state handles. An error would occur if RNG4 attempts - * to regenerate these keys before the next POR. + * Check to see if the RNG has already been instantiated. + * If either the state 0 or 1 instantiated flags are set, + * then don't continue on and try to instantiate the RNG + * again. */ - gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1; - ctrlpriv->rng4_sh_init &= RDSTA_IFMASK; - do { - int inst_handles = - rd_reg32(&ctrl->r4tst[0].rdsta) & - RDSTA_IFMASK; - /* - * If either SH were instantiated by somebody else - * (e.g. u-boot) then it is assumed that the entropy - * parameters are properly set and thus the function - * setting these (kick_trng(...)) is skipped. - * Also, if a handle was instantiated, do not change - * the TRNG parameters. - */ - if (!(ctrlpriv->rng4_sh_init || inst_handles)) { - dev_info(dev, - "Entropy delay = %u\n", - ent_delay); - kick_trng(pdev, ent_delay); - ent_delay += 400; + r4tst = &topregs->ctrl.r4tst[0]; + rdsta = rd_reg32(&r4tst->rdsta); /* Read RDSTA register */ + + /* Check IF bit for non-deterministic instantiation */ + rng_if = rdsta & RDSTA_IF; + + /* Check SKVN bit for non-deterministic key generation */ + rng_skvn = rdsta & RDSTA_SKVN; + if (!rng_if) { + kick_trng(pdev); + ret = instantiate_rng(ctrlpriv->jrdev[0], rng_skvn); + if (ret) { + caam_remove(pdev); + return -ENODEV; } - /* - * if instantiate_rng(...) fails, the loop will rerun - * and the kick_trng(...) function will modfiy the - * upper and lower limits of the entropy sampling - * interval, leading to a sucessful initialization of - * the RNG. - */ - ret = instantiate_rng(dev, inst_handles, - gen_sk); - if (ret == -EAGAIN) - /* - * if here, the loop will rerun, - * so don't hog the CPU - */ - cpu_relax(); - } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); - if (ret) { - dev_err(dev, "failed to instantiate RNG"); - caam_remove(pdev); - return ret; + ctrlpriv->rng_inst++; } - /* - * Set handles init'ed by this module as the complement of the - * already initialized ones - */ - ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK; - - /* Enable RDB bit so that RNG works faster */ - setbits32(&ctrl->scfgr, SCFGR_RDBENABLE); } /* NOTE: RTIC detection ought to go here, around Si time */ - caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 | - (u64)rd_reg32(&ctrl->perfmon.caam_id_ls); + /* Initialize queue allocator lock */ + spin_lock_init(&ctrlpriv->jr_alloc_lock); + + caam_id = rd_reg64(&topregs->ctrl.perfmon.caam_id); /* Report "alive" for developer to see */ dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, - caam_get_era()); + caam_get_era(caam_id)); dev_info(dev, "job rings = %d, qi = %d\n", ctrlpriv->total_jobrs, ctrlpriv->qi_present); @@ -627,7 +525,7 @@ */ perfmon = (struct caam_perfmon __force *)&ctrl->perfmon; - ctrlpriv->dfs_root = debugfs_create_dir(dev_name(dev), NULL); + ctrlpriv->dfs_root = debugfs_create_dir("caam", NULL); ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root); /* Controller-level - performance monitor counters */ @@ -716,6 +614,7 @@ static struct platform_driver caam_driver = { .driver = { .name = "caam", + .owner = THIS_MODULE, .of_match_table = caam_match, }, .probe = caam_probe, diff -Nur linux-4.1.13.orig/drivers/crypto/caam/ctrl.h linux-4.1.13/drivers/crypto/caam/ctrl.h --- linux-4.1.13.orig/drivers/crypto/caam/ctrl.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/ctrl.h 2015-11-30 17:56:13.548139857 +0100 @@ -8,6 +8,6 @@ #define CTRL_H /* Prototypes for backend-level services exposed to APIs */ -int caam_get_era(void); +int caam_get_era(u64 caam_id); #endif /* CTRL_H */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/desc_constr.h linux-4.1.13/drivers/crypto/caam/desc_constr.h --- linux-4.1.13.orig/drivers/crypto/caam/desc_constr.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/desc_constr.h 2015-11-30 17:56:13.548139857 +0100 @@ -10,7 +10,6 @@ #define CAAM_CMD_SZ sizeof(u32) #define CAAM_PTR_SZ sizeof(dma_addr_t) #define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE) -#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3) #ifdef DEBUG #define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\ @@ -111,26 +110,6 @@ (*desc)++; } -#define append_u32 append_cmd - -static inline void append_u64(u32 *desc, u64 data) -{ - u32 *offset = desc_end(desc); - - *offset = upper_32_bits(data); - *(++offset) = lower_32_bits(data); - - (*desc) += 2; -} - -/* Write command without affecting header, and return pointer to next word */ -static inline u32 *write_cmd(u32 *desc, u32 command) -{ - *desc = command; - - return desc + 1; -} - static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len, u32 command) { @@ -143,8 +122,7 @@ unsigned int len, u32 command) { append_cmd(desc, command); - if (!(command & (SQIN_RTO | SQIN_PRE))) - append_ptr(desc, ptr); + append_ptr(desc, ptr); append_cmd(desc, len); } @@ -155,29 +133,21 @@ append_data(desc, data, len); } -#define APPEND_CMD_RET(cmd, op) \ -static inline u32 *append_##cmd(u32 *desc, u32 options) \ -{ \ - u32 *cmd = desc_end(desc); \ - PRINT_POS; \ - append_cmd(desc, CMD_##op | options); \ - return cmd; \ +static inline u32 *append_jump(u32 *desc, u32 options) +{ + u32 *cmd = desc_end(desc); + + PRINT_POS; + append_cmd(desc, CMD_JUMP | options); + + return cmd; } -APPEND_CMD_RET(jump, JUMP) -APPEND_CMD_RET(move, MOVE) static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd) { *jump_cmd = *jump_cmd | (desc_len(desc) - (jump_cmd - desc)); } -static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd) -{ - *move_cmd &= ~MOVE_OFFSET_MASK; - *move_cmd = *move_cmd | ((desc_len(desc) << (MOVE_OFFSET_SHIFT + 2)) & - MOVE_OFFSET_MASK); -} - #define APPEND_CMD(cmd, op) \ static inline void append_##cmd(u32 *desc, u32 options) \ { \ @@ -185,6 +155,7 @@ append_cmd(desc, CMD_##op | options); \ } APPEND_CMD(operation, OPERATION) +APPEND_CMD(move, MOVE) #define APPEND_CMD_LEN(cmd, op) \ static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \ @@ -192,8 +163,6 @@ PRINT_POS; \ append_cmd(desc, CMD_##op | len | options); \ } - -APPEND_CMD_LEN(seq_load, SEQ_LOAD) APPEND_CMD_LEN(seq_store, SEQ_STORE) APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD) APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE) @@ -207,36 +176,17 @@ } APPEND_CMD_PTR(key, KEY) APPEND_CMD_PTR(load, LOAD) +APPEND_CMD_PTR(store, STORE) APPEND_CMD_PTR(fifo_load, FIFO_LOAD) APPEND_CMD_PTR(fifo_store, FIFO_STORE) -static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len, - u32 options) -{ - u32 cmd_src; - - cmd_src = options & LDST_SRCDST_MASK; - - append_cmd(desc, CMD_STORE | options | len); - - /* The following options do not require pointer */ - if (!(cmd_src == LDST_SRCDST_WORD_DESCBUF_SHARED || - cmd_src == LDST_SRCDST_WORD_DESCBUF_JOB || - cmd_src == LDST_SRCDST_WORD_DESCBUF_JOB_WE || - cmd_src == LDST_SRCDST_WORD_DESCBUF_SHARED_WE)) - append_ptr(desc, ptr); -} - #define APPEND_SEQ_PTR_INTLEN(cmd, op) \ static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, dma_addr_t ptr, \ unsigned int len, \ u32 options) \ { \ PRINT_POS; \ - if (options & (SQIN_RTO | SQIN_PRE)) \ - append_cmd(desc, CMD_SEQ_##op##_PTR | len | options); \ - else \ - append_cmd_ptr(desc, ptr, len, CMD_SEQ_##op##_PTR | options); \ + append_cmd_ptr(desc, ptr, len, CMD_SEQ_##op##_PTR | options); \ } APPEND_SEQ_PTR_INTLEN(in, IN) APPEND_SEQ_PTR_INTLEN(out, OUT) @@ -309,7 +259,7 @@ */ #define APPEND_MATH(op, desc, dest, src_0, src_1, len) \ append_cmd(desc, CMD_MATH | MATH_FUN_##op | MATH_DEST_##dest | \ - MATH_SRC0_##src_0 | MATH_SRC1_##src_1 | (u32)len); + MATH_SRC0_##src_0 | MATH_SRC1_##src_1 | (u32) (len & MATH_LEN_MASK)); #define append_math_add(desc, dest, src0, src1, len) \ APPEND_MATH(ADD, desc, dest, src0, src1, len) @@ -329,15 +279,13 @@ APPEND_MATH(LSHIFT, desc, dest, src0, src1, len) #define append_math_rshift(desc, dest, src0, src1, len) \ APPEND_MATH(RSHIFT, desc, dest, src0, src1, len) -#define append_math_ldshift(desc, dest, src0, src1, len) \ - APPEND_MATH(SHLD, desc, dest, src0, src1, len) /* Exactly one source is IMM. Data is passed in as u32 value */ #define APPEND_MATH_IMM_u32(op, desc, dest, src_0, src_1, data) \ do { \ APPEND_MATH(op, desc, dest, src_0, src_1, CAAM_CMD_SZ); \ append_cmd(desc, data); \ -} while (0) +} while (0); #define append_math_add_imm_u32(desc, dest, src0, src1, data) \ APPEND_MATH_IMM_u32(ADD, desc, dest, src0, src1, data) @@ -357,34 +305,3 @@ APPEND_MATH_IMM_u32(LSHIFT, desc, dest, src0, src1, data) #define append_math_rshift_imm_u32(desc, dest, src0, src1, data) \ APPEND_MATH_IMM_u32(RSHIFT, desc, dest, src0, src1, data) - -/* Exactly one source is IMM. Data is passed in as u64 value */ -#define APPEND_MATH_IMM_u64(op, desc, dest, src_0, src_1, data) \ -do { \ - u32 upper = (data >> 16) >> 16; \ - APPEND_MATH(op, desc, dest, src_0, src_1, CAAM_CMD_SZ * 2 | \ - (upper ? 0 : MATH_IFB)); \ - if (upper) \ - append_u64(desc, data); \ - else \ - append_u32(desc, data); \ -} while (0) - -#define append_math_add_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(ADD, desc, dest, src0, src1, data) -#define append_math_sub_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(SUB, desc, dest, src0, src1, data) -#define append_math_add_c_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(ADDC, desc, dest, src0, src1, data) -#define append_math_sub_b_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(SUBB, desc, dest, src0, src1, data) -#define append_math_and_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(AND, desc, dest, src0, src1, data) -#define append_math_or_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(OR, desc, dest, src0, src1, data) -#define append_math_xor_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(XOR, desc, dest, src0, src1, data) -#define append_math_lshift_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(LSHIFT, desc, dest, src0, src1, data) -#define append_math_rshift_imm_u64(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u64(RSHIFT, desc, dest, src0, src1, data) diff -Nur linux-4.1.13.orig/drivers/crypto/caam/desc.h linux-4.1.13/drivers/crypto/caam/desc.h --- linux-4.1.13.orig/drivers/crypto/caam/desc.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/desc.h 2015-11-30 17:56:13.548139857 +0100 @@ -2,19 +2,35 @@ * CAAM descriptor composition header * Definitions to support CAAM descriptor instruction generation * - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. */ #ifndef DESC_H #define DESC_H +/* + * 16-byte hardware scatter/gather table + * An 8-byte table exists in the hardware spec, but has never been + * implemented to date. The 8/16 option is selected at RTL-compile-time. + * and this selection is visible in the Compile Time Parameters Register + */ + +#define SEC4_SG_LEN_EXT 0x80000000 /* Entry points to table */ +#define SEC4_SG_LEN_FIN 0x40000000 /* Last ent in table */ +#define SEC4_SG_BPID_MASK 0x000000ff +#define SEC4_SG_BPID_SHIFT 16 +#define SEC4_SG_LEN_MASK 0x3fffffff /* Excludes EXT and FINAL */ +#define SEC4_SG_OFFS_MASK 0x00001fff + struct sec4_sg_entry { +#ifdef CONFIG_64BIT u64 ptr; -#define SEC4_SG_LEN_FIN 0x40000000 -#define SEC4_SG_LEN_EXT 0x80000000 +#else + u32 reserved; + u32 ptr; +#endif u32 len; - u8 reserved; - u8 buf_pool_id; + u16 buf_pool_id; u16 offset; }; @@ -231,12 +247,7 @@ #define LDST_SRCDST_WORD_PKHA_B_SZ (0x11 << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_PKHA_N_SZ (0x12 << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_PKHA_E_SZ (0x13 << LDST_SRCDST_SHIFT) -#define LDST_SRCDST_WORD_CLASS_CTX (0x20 << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_DESCBUF (0x40 << LDST_SRCDST_SHIFT) -#define LDST_SRCDST_WORD_DESCBUF_JOB (0x41 << LDST_SRCDST_SHIFT) -#define LDST_SRCDST_WORD_DESCBUF_SHARED (0x42 << LDST_SRCDST_SHIFT) -#define LDST_SRCDST_WORD_DESCBUF_JOB_WE (0x45 << LDST_SRCDST_SHIFT) -#define LDST_SRCDST_WORD_DESCBUF_SHARED_WE (0x46 << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_INFO_FIFO (0x7a << LDST_SRCDST_SHIFT) /* Offset in source/destination */ @@ -321,6 +332,7 @@ /* Continue - Not the last FIFO store to come */ #define FIFOST_CONT_SHIFT 23 #define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT) +#define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT) /* * Extended Length - use 32-bit extended length that @@ -370,7 +382,6 @@ #define FIFOLD_TYPE_LAST2FLUSH1 (0x05 << FIFOLD_TYPE_SHIFT) #define FIFOLD_TYPE_LASTBOTH (0x06 << FIFOLD_TYPE_SHIFT) #define FIFOLD_TYPE_LASTBOTHFL (0x07 << FIFOLD_TYPE_SHIFT) -#define FIFOLD_TYPE_NOINFOFIFO (0x0F << FIFOLD_TYPE_SHIFT) #define FIFOLDST_LEN_MASK 0xffff #define FIFOLDST_EXT_LEN_MASK 0xffffffff @@ -1092,6 +1103,23 @@ #define OP_PCL_PKPROT_ECC 0x0002 #define OP_PCL_PKPROT_F2M 0x0001 +/* Blob protocol protinfo bits */ +#define OP_PCL_BLOB_TK 0x0200 +#define OP_PCL_BLOB_EKT 0x0100 + +#define OP_PCL_BLOB_K2KR_MEM 0x0000 +#define OP_PCL_BLOB_K2KR_C1KR 0x0010 +#define OP_PCL_BLOB_K2KR_C2KR 0x0030 +#define OP_PCL_BLOB_K2KR_AFHAS 0x0050 +#define OP_PCL_BLOB_K2KR_C2KR_SPLIT 0x0070 + +#define OP_PCL_BLOB_PTXT_SECMEM 0x0008 +#define OP_PCL_BLOB_BLACK 0x0004 + +#define OP_PCL_BLOB_FMT_NORMAL 0x0000 +#define OP_PCL_BLOB_FMT_MSTR 0x0002 +#define OP_PCL_BLOB_FMT_TEST 0x0003 + /* For non-protocol/alg-only op commands */ #define OP_ALG_TYPE_SHIFT 24 #define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT) @@ -1154,15 +1182,8 @@ /* randomizer AAI set */ #define OP_ALG_AAI_RNG (0x00 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG_NZB (0x10 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG_OBP (0x20 << OP_ALG_AAI_SHIFT) - -/* RNG4 AAI set */ -#define OP_ALG_AAI_RNG4_SH_0 (0x00 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG4_SH_1 (0x01 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG4_PS (0x40 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG4_AI (0x80 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG4_SK (0x100 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_NOZERO (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_ODD (0x20 << OP_ALG_AAI_SHIFT) /* hmac/smac AAI set */ #define OP_ALG_AAI_HASH (0x00 << OP_ALG_AAI_SHIFT) @@ -1184,6 +1205,12 @@ #define OP_ALG_AAI_GSM (0x10 << OP_ALG_AAI_SHIFT) #define OP_ALG_AAI_EDGE (0x20 << OP_ALG_AAI_SHIFT) +/* RNG4 set */ +#define OP_ALG_RNG4_SHIFT 4 +#define OP_ALG_RNG4_MASK (0x1f3 << OP_ALG_RNG4_SHIFT) + +#define OP_ALG_RNG4_SK (0x100 << OP_ALG_RNG4_SHIFT) + #define OP_ALG_AS_SHIFT 2 #define OP_ALG_AS_MASK (0x3 << OP_ALG_AS_SHIFT) #define OP_ALG_AS_UPDATE (0 << OP_ALG_AS_SHIFT) @@ -1300,10 +1327,10 @@ #define SQOUT_SGF 0x01000000 /* Appends to a previous pointer */ -#define SQOUT_PRE SQIN_PRE +#define SQOUT_PRE 0x00800000 /* Restore sequence with pointer/length */ -#define SQOUT_RTO SQIN_RTO +#define SQOUT_RTO 0x00200000 /* Use extended length following pointer */ #define SQOUT_EXT 0x00400000 @@ -1365,7 +1392,6 @@ #define MOVE_DEST_MATH3 (0x07 << MOVE_DEST_SHIFT) #define MOVE_DEST_CLASS1INFIFO (0x08 << MOVE_DEST_SHIFT) #define MOVE_DEST_CLASS2INFIFO (0x09 << MOVE_DEST_SHIFT) -#define MOVE_DEST_INFIFO_NOINFO (0x0a << MOVE_DEST_SHIFT) #define MOVE_DEST_PK_A (0x0c << MOVE_DEST_SHIFT) #define MOVE_DEST_CLASS1KEY (0x0d << MOVE_DEST_SHIFT) #define MOVE_DEST_CLASS2KEY (0x0e << MOVE_DEST_SHIFT) @@ -1418,7 +1444,6 @@ #define MATH_SRC0_REG2 (0x02 << MATH_SRC0_SHIFT) #define MATH_SRC0_REG3 (0x03 << MATH_SRC0_SHIFT) #define MATH_SRC0_IMM (0x04 << MATH_SRC0_SHIFT) -#define MATH_SRC0_DPOVRD (0x07 << MATH_SRC0_SHIFT) #define MATH_SRC0_SEQINLEN (0x08 << MATH_SRC0_SHIFT) #define MATH_SRC0_SEQOUTLEN (0x09 << MATH_SRC0_SHIFT) #define MATH_SRC0_VARSEQINLEN (0x0a << MATH_SRC0_SHIFT) @@ -1433,7 +1458,6 @@ #define MATH_SRC1_REG2 (0x02 << MATH_SRC1_SHIFT) #define MATH_SRC1_REG3 (0x03 << MATH_SRC1_SHIFT) #define MATH_SRC1_IMM (0x04 << MATH_SRC1_SHIFT) -#define MATH_SRC1_DPOVRD (0x07 << MATH_SRC0_SHIFT) #define MATH_SRC1_INFIFO (0x0a << MATH_SRC1_SHIFT) #define MATH_SRC1_OUTFIFO (0x0b << MATH_SRC1_SHIFT) #define MATH_SRC1_ONE (0x0c << MATH_SRC1_SHIFT) @@ -1609,13 +1633,28 @@ #define NFIFOENTRY_PLEN_SHIFT 0 #define NFIFOENTRY_PLEN_MASK (0xFF << NFIFOENTRY_PLEN_SHIFT) -/* Append Load Immediate Command */ -#define FD_CMD_APPEND_LOAD_IMMEDIATE 0x80000000 +/* + * PDB internal definitions + */ + +/* IPSec ESP CBC Encap/Decap Options */ +#define PDBOPTS_ESPCBC_ARSNONE 0x00 /* no antireplay window */ +#define PDBOPTS_ESPCBC_ARS32 0x40 /* 32-entry antireplay window */ +#define PDBOPTS_ESPCBC_ARS64 0xc0 /* 64-entry antireplay window */ +#define PDBOPTS_ESPCBC_IVSRC 0x20 /* IV comes from internal random gen */ +#define PDBOPTS_ESPCBC_ESN 0x10 /* extended sequence included */ +#define PDBOPTS_ESPCBC_OUTFMT 0x08 /* output only decapsulation (decap) */ +#define PDBOPTS_ESPCBC_IPHDRSRC 0x08 /* IP header comes from PDB (encap) */ +#define PDBOPTS_ESPCBC_INCIPHDR 0x04 /* Prepend IP header to output frame */ +#define PDBOPTS_ESPCBC_IPVSN 0x02 /* process IPv6 header */ +#define PDBOPTS_ESPCBC_TUNNEL 0x01 /* tunnel mode next-header byte */ + +#define ARC4_BLOCK_SIZE 1 +#define ARC4_MAX_KEY_SIZE 256 +#define ARC4_MIN_KEY_SIZE 1 -/* Set SEQ LIODN equal to the Non-SEQ LIODN for the job */ -#define FD_CMD_SET_SEQ_LIODN_EQUAL_NONSEQ_LIODN 0x40000000 +#define XCBC_MAC_DIGEST_SIZE 16 +#define XCBC_MAC_BLOCK_WORDS 16 -/* Frame Descriptor Command for Replacement Job Descriptor */ -#define FD_CMD_REPLACE_JOB_DESC 0x20000000 #endif /* DESC_H */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/error.c linux-4.1.13/drivers/crypto/caam/error.c --- linux-4.1.13.orig/drivers/crypto/caam/error.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/error.c 2015-11-30 17:56:13.548139857 +0100 @@ -11,243 +11,264 @@ #include "jr.h" #include "error.h" -static const struct { - u8 value; - const char *error_text; -} desc_error_list[] = { - { 0x00, "No error." }, - { 0x01, "SGT Length Error. The descriptor is trying to read more data than is contained in the SGT table." }, - { 0x02, "SGT Null Entry Error." }, - { 0x03, "Job Ring Control Error. There is a bad value in the Job Ring Control register." }, - { 0x04, "Invalid Descriptor Command. The Descriptor Command field is invalid." }, - { 0x05, "Reserved." }, - { 0x06, "Invalid KEY Command" }, - { 0x07, "Invalid LOAD Command" }, - { 0x08, "Invalid STORE Command" }, - { 0x09, "Invalid OPERATION Command" }, - { 0x0A, "Invalid FIFO LOAD Command" }, - { 0x0B, "Invalid FIFO STORE Command" }, - { 0x0C, "Invalid MOVE/MOVE_LEN Command" }, - { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is invalid because the target is not a Job Header Command, or the jump is from a Trusted Descriptor to a Job Descriptor, or because the target Descriptor contains a Shared Descriptor." }, - { 0x0E, "Invalid MATH Command" }, - { 0x0F, "Invalid SIGNATURE Command" }, - { 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO LOAD, or SEQ FIFO STORE decremented the input or output sequence length below 0. This error may result if a built-in PROTOCOL Command has encountered a malformed PDU." }, - { 0x11, "Skip data type invalid. The type must be 0xE or 0xF."}, - { 0x12, "Shared Descriptor Header Error" }, - { 0x13, "Header Error. Invalid length or parity, or certain other problems." }, - { 0x14, "Burster Error. Burster has gotten to an illegal state" }, - { 0x15, "Context Register Length Error. The descriptor is trying to read or write past the end of the Context Register. A SEQ LOAD or SEQ STORE with the VLF bit set was executed with too large a length in the variable length register (VSOL for SEQ STORE or VSIL for SEQ LOAD)." }, - { 0x16, "DMA Error" }, - { 0x17, "Reserved." }, - { 0x1A, "Job failed due to JR reset" }, - { 0x1B, "Job failed due to Fail Mode" }, - { 0x1C, "DECO Watchdog timer timeout error" }, - { 0x1D, "DECO tried to copy a key from another DECO but the other DECO's Key Registers were locked" }, - { 0x1E, "DECO attempted to copy data from a DECO that had an unmasked Descriptor error" }, - { 0x1F, "LIODN error. DECO was trying to share from itself or from another DECO but the two Non-SEQ LIODN values didn't match or the 'shared from' DECO's Descriptor required that the SEQ LIODNs be the same and they aren't." }, - { 0x20, "DECO has completed a reset initiated via the DRR register" }, - { 0x21, "Nonce error. When using EKT (CCM) key encryption option in the FIFO STORE Command, the Nonce counter reached its maximum value and this encryption mode can no longer be used." }, - { 0x22, "Meta data is too large (> 511 bytes) for TLS decap (input frame; block ciphers) and IPsec decap (output frame, when doing the next header byte update) and DCRC (output frame)." }, - { 0x23, "Read Input Frame error" }, - { 0x24, "JDKEK, TDKEK or TDSK not loaded error" }, - { 0x80, "DNR (do not run) error" }, - { 0x81, "undefined protocol command" }, - { 0x82, "invalid setting in PDB" }, - { 0x83, "Anti-replay LATE error" }, - { 0x84, "Anti-replay REPLAY error" }, - { 0x85, "Sequence number overflow" }, - { 0x86, "Sigver invalid signature" }, - { 0x87, "DSA Sign Illegal test descriptor" }, - { 0x88, "Protocol Format Error - A protocol has seen an error in the format of data received. When running RSA, this means that formatting with random padding was used, and did not follow the form: 0x00, 0x02, 8-to-N bytes of non-zero pad, 0x00, F data." }, - { 0x89, "Protocol Size Error - A protocol has seen an error in size. When running RSA, pdb size N < (size of F) when no formatting is used; or pdb size N < (F + 11) when formatting is used." }, - { 0xC1, "Blob Command error: Undefined mode" }, - { 0xC2, "Blob Command error: Secure Memory Blob mode error" }, - { 0xC4, "Blob Command error: Black Blob key or input size error" }, - { 0xC5, "Blob Command error: Invalid key destination" }, - { 0xC8, "Blob Command error: Trusted/Secure mode error" }, - { 0xF0, "IPsec TTL or hop limit field either came in as 0, or was decremented to 0" }, - { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, -}; - -static const char * const cha_id_list[] = { - "", - "AES", - "DES", - "ARC4", - "MDHA", - "RNG", - "SNOW f8", - "Kasumi f8/9", - "PKHA", - "CRCA", - "SNOW f9", - "ZUCE", - "ZUCA", -}; - -static const char * const err_id_list[] = { - "No error.", - "Mode error.", - "Data size error.", - "Key size error.", - "PKHA A memory size error.", - "PKHA B memory size error.", - "Data arrived out of sequence error.", - "PKHA divide-by-zero error.", - "PKHA modulus even error.", - "DES key parity error.", - "ICV check failed.", - "Hardware error.", - "Unsupported CCM AAD size.", - "Class 1 CHA is not reset", - "Invalid CHA combination was selected", - "Invalid CHA selected.", -}; - -static const char * const rng_err_id_list[] = { - "", - "", - "", - "Instantiate", - "Not instantiated", - "Test instantiate", - "Prediction resistance", - "Prediction resistance and test request", - "Uninstantiate", - "Secure key generation", -}; +#define SPRINTFCAT(str, format, param, max_alloc) \ +{ \ + char *tmp; \ + \ + tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC); \ + if (likely(tmp)) { \ + sprintf(tmp, format, param); \ + strcat(str, tmp); \ + kfree(tmp); \ + } else { \ + strcat(str, "kmalloc failure in SPRINTFCAT"); \ + } \ +} -static void report_ccb_status(struct device *jrdev, const u32 status, - const char *error) +static void report_jump_idx(u32 status, char *outstr) { - u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> - JRSTA_CCBERR_CHAID_SHIFT; - u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >> JRSTA_DECOERR_INDEX_SHIFT; - char *idx_str; - const char *cha_str = "unidentified cha_id value 0x"; - char cha_err_code[3] = { 0 }; - const char *err_str = "unidentified err_id value 0x"; - char err_err_code[3] = { 0 }; if (status & JRSTA_DECOERR_JUMP) - idx_str = "jump tgt desc idx"; + strcat(outstr, "jump tgt desc idx "); else - idx_str = "desc idx"; + strcat(outstr, "desc idx "); - if (cha_id < ARRAY_SIZE(cha_id_list)) - cha_str = cha_id_list[cha_id]; - else - snprintf(cha_err_code, sizeof(cha_err_code), "%02x", cha_id); + SPRINTFCAT(outstr, "%d: ", idx, sizeof("255")); +} + +static void report_ccb_status(u32 status, char *outstr) +{ + static const char * const cha_id_list[] = { + "", + "AES", + "DES", + "ARC4", + "MDHA", + "RNG", + "SNOW f8", + "Kasumi f8/9", + "PKHA", + "CRCA", + "SNOW f9", + "ZUCE", + "ZUCA", + }; + static const char * const err_id_list[] = { + "No error.", + "Mode error.", + "Data size error.", + "Key size error.", + "PKHA A memory size error.", + "PKHA B memory size error.", + "Data arrived out of sequence error.", + "PKHA divide-by-zero error.", + "PKHA modulus even error.", + "DES key parity error.", + "ICV check failed.", + "Hardware error.", + "Unsupported CCM AAD size.", + "Class 1 CHA is not reset", + "Invalid CHA combination was selected", + "Invalid CHA selected.", + }; + static const char * const rng_err_id_list[] = { + "", + "", + "", + "Instantiate", + "Not instantiated", + "Test instantiate", + "Prediction resistance", + "Prediction resistance and test request", + "Uninstantiate", + "Secure key generation", + }; + u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> + JRSTA_CCBERR_CHAID_SHIFT; + u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; + + report_jump_idx(status, outstr); + + if (cha_id < ARRAY_SIZE(cha_id_list)) { + SPRINTFCAT(outstr, "%s: ", cha_id_list[cha_id], + strlen(cha_id_list[cha_id])); + } else { + SPRINTFCAT(outstr, "unidentified cha_id value 0x%02x: ", + cha_id, sizeof("ff")); + } if ((cha_id << JRSTA_CCBERR_CHAID_SHIFT) == JRSTA_CCBERR_CHAID_RNG && err_id < ARRAY_SIZE(rng_err_id_list) && strlen(rng_err_id_list[err_id])) { /* RNG-only error */ - err_str = rng_err_id_list[err_id]; - } else if (err_id < ARRAY_SIZE(err_id_list)) - err_str = err_id_list[err_id]; - else - snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); - - /* - * CCB ICV check failures are part of normal operation life; - * we leave the upper layers to do what they want with them. - */ - if (err_id != JRSTA_CCBERR_ERRID_ICVCHK) - dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n", - status, error, idx_str, idx, - cha_str, cha_err_code, - err_str, err_err_code); + SPRINTFCAT(outstr, "%s", rng_err_id_list[err_id], + strlen(rng_err_id_list[err_id])); + } else if (err_id < ARRAY_SIZE(err_id_list)) { + SPRINTFCAT(outstr, "%s", err_id_list[err_id], + strlen(err_id_list[err_id])); + } else { + SPRINTFCAT(outstr, "unidentified err_id value 0x%02x", + err_id, sizeof("ff")); + } } -static void report_jump_status(struct device *jrdev, const u32 status, - const char *error) +static void report_jump_status(u32 status, char *outstr) { - dev_err(jrdev, "%08x: %s: %s() not implemented\n", - status, error, __func__); + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); } -static void report_deco_status(struct device *jrdev, const u32 status, - const char *error) +static void report_deco_status(u32 status, char *outstr) { - u8 err_id = status & JRSTA_DECOERR_ERROR_MASK; - u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >> - JRSTA_DECOERR_INDEX_SHIFT; - char *idx_str; - const char *err_str = "unidentified error value 0x"; - char err_err_code[3] = { 0 }; + static const struct { + u8 value; + char *error_text; + } desc_error_list[] = { + { 0x00, "No error." }, + { 0x01, "SGT Length Error. The descriptor is trying to read " + "more data than is contained in the SGT table." }, + { 0x02, "SGT Null Entry Error." }, + { 0x03, "Job Ring Control Error. There is a bad value in the " + "Job Ring Control register." }, + { 0x04, "Invalid Descriptor Command. The Descriptor Command " + "field is invalid." }, + { 0x05, "Reserved." }, + { 0x06, "Invalid KEY Command" }, + { 0x07, "Invalid LOAD Command" }, + { 0x08, "Invalid STORE Command" }, + { 0x09, "Invalid OPERATION Command" }, + { 0x0A, "Invalid FIFO LOAD Command" }, + { 0x0B, "Invalid FIFO STORE Command" }, + { 0x0C, "Invalid MOVE/MOVE_LEN Command" }, + { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is " + "invalid because the target is not a Job Header " + "Command, or the jump is from a Trusted Descriptor to " + "a Job Descriptor, or because the target Descriptor " + "contains a Shared Descriptor." }, + { 0x0E, "Invalid MATH Command" }, + { 0x0F, "Invalid SIGNATURE Command" }, + { 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR " + "Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO " + "LOAD, or SEQ FIFO STORE decremented the input or " + "output sequence length below 0. This error may result " + "if a built-in PROTOCOL Command has encountered a " + "malformed PDU." }, + { 0x11, "Skip data type invalid. The type must be 0xE or 0xF."}, + { 0x12, "Shared Descriptor Header Error" }, + { 0x13, "Header Error. Invalid length or parity, or certain " + "other problems." }, + { 0x14, "Burster Error. Burster has gotten to an illegal " + "state" }, + { 0x15, "Context Register Length Error. The descriptor is " + "trying to read or write past the end of the Context " + "Register. A SEQ LOAD or SEQ STORE with the VLF bit " + "set was executed with too large a length in the " + "variable length register (VSOL for SEQ STORE or VSIL " + "for SEQ LOAD)." }, + { 0x16, "DMA Error" }, + { 0x17, "Reserved." }, + { 0x1A, "Job failed due to JR reset" }, + { 0x1B, "Job failed due to Fail Mode" }, + { 0x1C, "DECO Watchdog timer timeout error" }, + { 0x1D, "DECO tried to copy a key from another DECO but the " + "other DECO's Key Registers were locked" }, + { 0x1E, "DECO attempted to copy data from a DECO that had an " + "unmasked Descriptor error" }, + { 0x1F, "LIODN error. DECO was trying to share from itself or " + "from another DECO but the two Non-SEQ LIODN values " + "didn't match or the 'shared from' DECO's Descriptor " + "required that the SEQ LIODNs be the same and they " + "aren't." }, + { 0x20, "DECO has completed a reset initiated via the DRR " + "register" }, + { 0x21, "Nonce error. When using EKT (CCM) key encryption " + "option in the FIFO STORE Command, the Nonce counter " + "reached its maximum value and this encryption mode " + "can no longer be used." }, + { 0x22, "Meta data is too large (> 511 bytes) for TLS decap " + "(input frame; block ciphers) and IPsec decap (output " + "frame, when doing the next header byte update) and " + "DCRC (output frame)." }, + { 0x23, "Read Input Frame error" }, + { 0x24, "JDKEK, TDKEK or TDSK not loaded error" }, + { 0x80, "DNR (do not run) error" }, + { 0x81, "undefined protocol command" }, + { 0x82, "invalid setting in PDB" }, + { 0x83, "Anti-replay LATE error" }, + { 0x84, "Anti-replay REPLAY error" }, + { 0x85, "Sequence number overflow" }, + { 0x86, "Sigver invalid signature" }, + { 0x87, "DSA Sign Illegal test descriptor" }, + { 0x88, "Protocol Format Error - A protocol has seen an error " + "in the format of data received. When running RSA, " + "this means that formatting with random padding was " + "used, and did not follow the form: 0x00, 0x02, 8-to-N " + "bytes of non-zero pad, 0x00, F data." }, + { 0x89, "Protocol Size Error - A protocol has seen an error in " + "size. When running RSA, pdb size N < (size of F) when " + "no formatting is used; or pdb size N < (F + 11) when " + "formatting is used." }, + { 0xC1, "Blob Command error: Undefined mode" }, + { 0xC2, "Blob Command error: Secure Memory Blob mode error" }, + { 0xC4, "Blob Command error: Black Blob key or input size " + "error" }, + { 0xC5, "Blob Command error: Invalid key destination" }, + { 0xC8, "Blob Command error: Trusted/Secure mode error" }, + { 0xF0, "IPsec TTL or hop limit field either came in as 0, " + "or was decremented to 0" }, + { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, + }; + u8 desc_error = status & JRSTA_DECOERR_ERROR_MASK; int i; - if (status & JRSTA_DECOERR_JUMP) - idx_str = "jump tgt desc idx"; - else - idx_str = "desc idx"; + report_jump_idx(status, outstr); for (i = 0; i < ARRAY_SIZE(desc_error_list); i++) - if (desc_error_list[i].value == err_id) + if (desc_error_list[i].value == desc_error) break; - if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text) - err_str = desc_error_list[i].error_text; - else - snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); - - dev_err(jrdev, "%08x: %s: %s %d: %s%s\n", - status, error, idx_str, idx, err_str, err_err_code); + if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text) { + SPRINTFCAT(outstr, "%s", desc_error_list[i].error_text, + strlen(desc_error_list[i].error_text)); + } else { + SPRINTFCAT(outstr, "unidentified error value 0x%02x", + desc_error, sizeof("ff")); + } } -static void report_jr_status(struct device *jrdev, const u32 status, - const char *error) +static void report_jr_status(u32 status, char *outstr) { - dev_err(jrdev, "%08x: %s: %s() not implemented\n", - status, error, __func__); + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); } -static void report_cond_code_status(struct device *jrdev, const u32 status, - const char *error) +static void report_cond_code_status(u32 status, char *outstr) { - dev_err(jrdev, "%08x: %s: %s() not implemented\n", - status, error, __func__); + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); } -void caam_jr_strstatus(struct device *jrdev, u32 status) +char *caam_jr_strstatus(char *outstr, u32 status) { static const struct stat_src { - void (*report_ssed)(struct device *jrdev, const u32 status, - const char *error); - const char *error; - } status_src[16] = { + void (*report_ssed)(u32 status, char *outstr); + char *error; + } status_src[] = { { NULL, "No error" }, { NULL, NULL }, { report_ccb_status, "CCB" }, { report_jump_status, "Jump" }, { report_deco_status, "DECO" }, - { NULL, "Queue Manager Interface" }, + { NULL, NULL }, { report_jr_status, "Job Ring" }, { report_cond_code_status, "Condition Code" }, - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL }, }; u32 ssrc = status >> JRSTA_SSRC_SHIFT; - const char *error = status_src[ssrc].error; - /* - * If there is an error handling function, call it to report the error. - * Otherwise print the error source name. - */ + sprintf(outstr, "%s: ", status_src[ssrc].error); + if (status_src[ssrc].report_ssed) - status_src[ssrc].report_ssed(jrdev, status, error); - else if (error) - dev_err(jrdev, "%d: %s\n", ssrc, error); - else - dev_err(jrdev, "%d: unknown error source\n", ssrc); + status_src[ssrc].report_ssed(status, outstr); + + return outstr; } EXPORT_SYMBOL(caam_jr_strstatus); diff -Nur linux-4.1.13.orig/drivers/crypto/caam/error.h linux-4.1.13/drivers/crypto/caam/error.h --- linux-4.1.13.orig/drivers/crypto/caam/error.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/error.h 2015-11-30 17:56:13.548139857 +0100 @@ -7,5 +7,5 @@ #ifndef CAAM_ERROR_H #define CAAM_ERROR_H #define CAAM_ERROR_STR_MAX 302 -void caam_jr_strstatus(struct device *jrdev, u32 status); +extern char *caam_jr_strstatus(char *outstr, u32 status); #endif /* CAAM_ERROR_H */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/intern.h linux-4.1.13/drivers/crypto/caam/intern.h --- linux-4.1.13.orig/drivers/crypto/caam/intern.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/intern.h 2015-11-30 17:56:13.548139857 +0100 @@ -2,13 +2,19 @@ * CAAM/SEC 4.x driver backend * Private/internal definitions between modules * - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. * */ #ifndef INTERN_H #define INTERN_H +#define JOBR_UNASSIGNED 0 +#define JOBR_ASSIGNED 1 + +/* Default clock/sample settings for an RNG4 entropy source */ +#define RNG4_ENT_CLOCKS_SAMPLE 1600 + /* Currently comes from Kconfig param as a ^2 (driver-required) */ #define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE) @@ -37,15 +43,13 @@ /* Private sub-storage for a single JobR */ struct caam_drv_private_jr { - struct list_head list_node; /* Job Ring device list */ - struct device *dev; + struct device *parentdev; /* points back to controller dev */ + struct platform_device *jr_pdev;/* points to platform device for JR */ int ridx; struct caam_job_ring __iomem *rregs; /* JobR's register space */ struct tasklet_struct irqtask; int irq; /* One per queue */ - - /* Number of scatterlist crypt transforms active on the JobR */ - atomic_t tfm_count ____cacheline_aligned; + int assign; /* busy/free */ /* Job ring info */ int ringsize; /* Size of rings (assume input = output) */ @@ -66,15 +70,20 @@ struct caam_drv_private { struct device *dev; - struct platform_device **jrpdev; /* Alloc'ed array per sub-device */ + struct device *smdev; + struct device *secviodev; + struct device **jrdev; /* Alloc'ed array per sub-device */ + spinlock_t jr_alloc_lock; struct platform_device *pdev; /* Physical-presence section */ - struct caam_ctrl __iomem *ctrl; /* controller region */ - struct caam_deco __iomem *deco; /* DECO/CCB views */ - struct caam_assurance __iomem *assure; - struct caam_queue_if __iomem *qi; /* QI control region */ - struct caam_job_ring __iomem *jr[4]; /* JobR's register space */ + struct caam_ctrl *ctrl; /* controller region */ + struct caam_deco **deco; /* DECO/CCB views */ + struct caam_assurance *ac; + struct caam_queue_if *qi; /* QI control region */ + struct snvs_full __iomem *snvs; /* SNVS HP+LP register space */ + dma_addr_t __iomem *sm_base; /* Secure memory storage base */ + u32 sm_size; /* * Detected geometry block. Filled in from device tree if powerpc, @@ -83,14 +92,22 @@ u8 total_jobrs; /* Total Job Rings in device */ u8 qi_present; /* Nonzero if QI present in device */ int secvio_irq; /* Security violation interrupt number */ - int virt_en; /* Virtualization enabled in CAAM */ - -#define RNG4_MAX_HANDLES 2 - /* RNG4 block */ - u32 rng4_sh_init; /* This bitmap shows which of the State - Handles of the RNG4 block are initialized - by this driver */ + int rng_inst; /* Total instantiated RNGs */ + /* which jr allocated to scatterlist crypto */ + atomic_t tfm_count ____cacheline_aligned; + int num_jrs_for_algapi; + struct device **algapi_jr; + /* list of registered crypto algorithms (mk generic context handle?) */ + struct list_head alg_list; + /* list of registered hash algorithms (mk generic context handle?) */ + struct list_head hash_list; + +#ifdef CONFIG_ARM + struct clk *caam_ipg; + struct clk *caam_mem; + struct clk *caam_aclk; +#endif /* * debugfs entries for developer view into driver/device * variables at runtime. diff -Nur linux-4.1.13.orig/drivers/crypto/caam/jr.c linux-4.1.13/drivers/crypto/caam/jr.c --- linux-4.1.13.orig/drivers/crypto/caam/jr.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/jr.c 2015-11-30 17:56:13.548139857 +0100 @@ -2,125 +2,15 @@ * CAAM/SEC 4.x transport/backend driver * JobR backend functionality * - * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. */ -#include -#include - #include "compat.h" #include "regs.h" #include "jr.h" #include "desc.h" #include "intern.h" -struct jr_driver_data { - /* List of Physical JobR's with the Driver */ - struct list_head jr_list; - spinlock_t jr_alloc_lock; /* jr_list lock */ -} ____cacheline_aligned; - -static struct jr_driver_data driver_data; - -static int caam_reset_hw_jr(struct device *dev) -{ - struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); - unsigned int timeout = 100000; - - /* - * mask interrupts since we are going to poll - * for reset completion status - */ - setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); - - /* initiate flush (required prior to reset) */ - wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); - while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) == - JRINT_ERR_HALT_INPROGRESS) && --timeout) - cpu_relax(); - - if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) != - JRINT_ERR_HALT_COMPLETE || timeout == 0) { - dev_err(dev, "failed to flush job ring %d\n", jrp->ridx); - return -EIO; - } - - /* initiate reset */ - timeout = 100000; - wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); - while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout) - cpu_relax(); - - if (timeout == 0) { - dev_err(dev, "failed to reset job ring %d\n", jrp->ridx); - return -EIO; - } - - /* unmask interrupts */ - clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); - - return 0; -} - -/* - * Shutdown JobR independent of platform property code - */ -int caam_jr_shutdown(struct device *dev) -{ - struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); - dma_addr_t inpbusaddr, outbusaddr; - int ret; - - ret = caam_reset_hw_jr(dev); - - tasklet_kill(&jrp->irqtask); - - /* Release interrupt */ - free_irq(jrp->irq, dev); - - /* Free rings */ - inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); - outbusaddr = rd_reg64(&jrp->rregs->outring_base); - dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH, - jrp->inpring, inpbusaddr); - dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, - jrp->outring, outbusaddr); - kfree(jrp->entinfo); - - return ret; -} - -static int caam_jr_remove(struct platform_device *pdev) -{ - int ret; - struct device *jrdev; - struct caam_drv_private_jr *jrpriv; - - jrdev = &pdev->dev; - jrpriv = dev_get_drvdata(jrdev); - - /* - * Return EBUSY if job ring already allocated. - */ - if (atomic_read(&jrpriv->tfm_count)) { - dev_err(jrdev, "Device is busy\n"); - return -EBUSY; - } - - /* Remove the node from Physical JobR list maintained by driver */ - spin_lock(&driver_data.jr_alloc_lock); - list_del(&jrpriv->list_node); - spin_unlock(&driver_data.jr_alloc_lock); - - /* Release ring */ - ret = caam_jr_shutdown(jrdev); - if (ret) - dev_err(jrdev, "Failed to shut down job ring\n"); - irq_dispose_mapping(jrpriv->irq); - - return ret; -} - /* Main per-ring interrupt handler */ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) { @@ -168,6 +58,9 @@ void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); u32 *userdesc, userstatus; void *userarg; + dma_addr_t outbusaddr; + + outbusaddr = rd_reg64(&jrp->rregs->outring_base); while (rd_reg32(&jrp->rregs->outring_used)) { @@ -177,10 +70,15 @@ 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); + smp_read_barrier_depends(); + if (jrp->outring[hw_idx].desc == jrp->entinfo[sw_idx].desc_addr_dma) break; /* found */ @@ -202,6 +100,8 @@ userdesc = jrp->entinfo[sw_idx].desc_addr_virt; userstatus = jrp->outring[hw_idx].jrstatus; + smp_mb(); + /* set done */ wr_reg32(&jrp->rregs->outring_rmvd, 1); @@ -216,6 +116,7 @@ if (sw_idx == tail) { do { tail = (tail + 1) & (JOBR_DEPTH - 1); + smp_read_barrier_depends(); } while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 && jrp->entinfo[tail].desc_addr_dma == 0); @@ -233,57 +134,70 @@ } /** - * caam_jr_alloc() - Alloc a job ring for someone to use as needed. - * - * returns : pointer to the newly allocated physical - * JobR dev can be written to if successful. + * caam_jr_register() - Alloc a ring for someone to use as needed. Returns + * an ordinal of the rings allocated, else returns -ENODEV if no rings + * are available. + * @ctrldev: points to the controller level dev (parent) that + * owns rings available for use. + * @dev: points to where a pointer to the newly allocated queue's + * dev can be written to if successful. **/ -struct device *caam_jr_alloc(void) +int caam_jr_register(struct device *ctrldev, struct device **rdev) { - struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL; - struct device *dev = NULL; - int min_tfm_cnt = INT_MAX; - int tfm_cnt; - - spin_lock(&driver_data.jr_alloc_lock); - - if (list_empty(&driver_data.jr_list)) { - spin_unlock(&driver_data.jr_alloc_lock); - return ERR_PTR(-ENODEV); - } - - list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) { - tfm_cnt = atomic_read(&jrpriv->tfm_count); - if (tfm_cnt < min_tfm_cnt) { - min_tfm_cnt = tfm_cnt; - min_jrpriv = jrpriv; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); + struct caam_drv_private_jr *jrpriv = NULL; + int ring; + + /* Lock, if free ring - assign, unlock */ + spin_lock(&ctrlpriv->jr_alloc_lock); + for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { + jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]); + if (jrpriv->assign == JOBR_UNASSIGNED) { + jrpriv->assign = JOBR_ASSIGNED; + *rdev = ctrlpriv->jrdev[ring]; + spin_unlock(&ctrlpriv->jr_alloc_lock); + return ring; } - if (!min_tfm_cnt) - break; } - if (min_jrpriv) { - atomic_inc(&min_jrpriv->tfm_count); - dev = min_jrpriv->dev; - } - spin_unlock(&driver_data.jr_alloc_lock); + /* If assigned, write dev where caller needs it */ + spin_unlock(&ctrlpriv->jr_alloc_lock); + *rdev = NULL; - return dev; + return -ENODEV; } -EXPORT_SYMBOL(caam_jr_alloc); +EXPORT_SYMBOL(caam_jr_register); /** - * caam_jr_free() - Free the Job Ring - * @rdev - points to the dev that identifies the Job ring to - * be released. + * caam_jr_deregister() - Deregister an API and release the queue. + * Returns 0 if OK, -EBUSY if queue still contains pending entries + * or unprocessed results at the time of the call + * @dev - points to the dev that identifies the queue to + * be released. **/ -void caam_jr_free(struct device *rdev) +int caam_jr_deregister(struct device *rdev) { struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev); + struct caam_drv_private *ctrlpriv; + + /* Get the owning controller's private space */ + ctrlpriv = dev_get_drvdata(jrpriv->parentdev); + + /* + * Make sure ring empty before release + */ + if (rd_reg32(&jrpriv->rregs->outring_used) || + (rd_reg32(&jrpriv->rregs->inpring_avail) != JOBR_DEPTH)) + return -EBUSY; - atomic_dec(&jrpriv->tfm_count); + /* Release ring */ + spin_lock(&ctrlpriv->jr_alloc_lock); + jrpriv->assign = JOBR_UNASSIGNED; + spin_unlock(&ctrlpriv->jr_alloc_lock); + + return 0; } -EXPORT_SYMBOL(caam_jr_free); +EXPORT_SYMBOL(caam_jr_deregister); /** * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK, @@ -321,7 +235,7 @@ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); struct caam_jrentry_info *head_entry; int head, tail, desc_size; - dma_addr_t desc_dma; + dma_addr_t desc_dma, inpbusaddr; desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32); desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE); @@ -330,6 +244,13 @@ return -EIO; } + dma_sync_single_for_device(dev, desc_dma, desc_size, DMA_TO_DEVICE); + + inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); + dma_sync_single_for_device(dev, inpbusaddr, + sizeof(dma_addr_t) * JOBR_DEPTH, + DMA_TO_DEVICE); + spin_lock_bh(&jrp->inplock); head = jrp->head; @@ -351,12 +272,18 @@ jrp->inpring[jrp->inp_ring_write_index] = desc_dma; + dma_sync_single_for_device(dev, inpbusaddr, + sizeof(dma_addr_t) * JOBR_DEPTH, + DMA_TO_DEVICE); + smp_wmb(); jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) & (JOBR_DEPTH - 1); jrp->head = (head + 1) & (JOBR_DEPTH - 1); + wmb(); + wr_reg32(&jrp->rregs->inpring_jobadd, 1); spin_unlock_bh(&jrp->inplock); @@ -365,6 +292,46 @@ } EXPORT_SYMBOL(caam_jr_enqueue); +static int caam_reset_hw_jr(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + unsigned int timeout = 100000; + + /* + * mask interrupts since we are going to poll + * for reset completion status + */ + setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + /* initiate flush (required prior to reset) */ + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) == + JRINT_ERR_HALT_INPROGRESS) && --timeout) + cpu_relax(); + + if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) != + JRINT_ERR_HALT_COMPLETE || timeout == 0) { + dev_err(dev, "failed to flush job ring %d\n", jrp->ridx); + return -EIO; + } + + /* initiate reset */ + timeout = 100000; + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout) + cpu_relax(); + + if (timeout == 0) { + dev_err(dev, "failed to reset job ring %d\n", jrp->ridx); + return -EIO; + } + + /* unmask interrupts */ + clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + return 0; +} + /* * Init JobR independent of platform property detection */ @@ -380,32 +347,34 @@ /* Connect job ring interrupt handler. */ error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, - dev_name(dev), dev); + "caam-jobr", dev); if (error) { dev_err(dev, "can't connect JobR %d interrupt (%d)\n", jrp->ridx, jrp->irq); - goto out_kill_deq; + irq_dispose_mapping(jrp->irq); + jrp->irq = 0; + return -EINVAL; } error = caam_reset_hw_jr(dev); if (error) - goto out_free_irq; + return error; - error = -ENOMEM; jrp->inpring = dma_alloc_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH, &inpbusaddr, GFP_KERNEL); - if (!jrp->inpring) - goto out_free_irq; jrp->outring = dma_alloc_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, &outbusaddr, GFP_KERNEL); - if (!jrp->outring) - goto out_free_inpring; jrp->entinfo = kzalloc(sizeof(struct caam_jrentry_info) * JOBR_DEPTH, GFP_KERNEL); - if (!jrp->entinfo) - goto out_free_outring; + + if ((jrp->inpring == NULL) || (jrp->outring == NULL) || + (jrp->entinfo == NULL)) { + dev_err(dev, "can't allocate job rings for %d\n", + jrp->ridx); + return -ENOMEM; + } for (i = 0; i < JOBR_DEPTH; i++) jrp->entinfo[i].desc_addr_dma = !0; @@ -431,120 +400,123 @@ (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) | (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT)); + jrp->assign = JOBR_UNASSIGNED; return 0; +} -out_free_outring: - dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, - jrp->outring, outbusaddr); -out_free_inpring: +/* + * Shutdown JobR independent of platform property code + */ +int caam_jr_shutdown(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + dma_addr_t inpbusaddr, outbusaddr; + int ret; + + ret = caam_reset_hw_jr(dev); + + tasklet_kill(&jrp->irqtask); + + /* Release interrupt */ + free_irq(jrp->irq, dev); + + /* Free rings */ + inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); + outbusaddr = rd_reg64(&jrp->rregs->outring_base); dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH, jrp->inpring, inpbusaddr); - dev_err(dev, "can't allocate job rings for %d\n", jrp->ridx); -out_free_irq: - free_irq(jrp->irq, dev); -out_kill_deq: - tasklet_kill(&jrp->irqtask); - return error; -} + dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, + jrp->outring, outbusaddr); + kfree(jrp->entinfo); + of_device_unregister(jrp->jr_pdev); + return ret; +} /* - * Probe routine for each detected JobR subsystem. + * Probe routine for each detected JobR subsystem. It assumes that + * property detection was picked up externally. */ -static int caam_jr_probe(struct platform_device *pdev) +int caam_jr_probe(struct platform_device *pdev, struct device_node *np, + int ring) { - struct device *jrdev; - struct device_node *nprop; - struct caam_job_ring __iomem *ctrl; + struct device *ctrldev, *jrdev; + struct platform_device *jr_pdev; + struct caam_drv_private *ctrlpriv; struct caam_drv_private_jr *jrpriv; - static int total_jobrs; + const __be32 *jroffset_addr; + u32 jroffset; int error; - jrdev = &pdev->dev; - jrpriv = devm_kmalloc(jrdev, sizeof(struct caam_drv_private_jr), - GFP_KERNEL); - if (!jrpriv) + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + + jrpriv = kmalloc(sizeof(struct caam_drv_private_jr), + GFP_KERNEL); + if (jrpriv == NULL) { + dev_err(ctrldev, "can't alloc private mem for job ring %d\n", + ring); return -ENOMEM; + } + jrpriv->parentdev = ctrldev; /* point back to parent */ + jrpriv->ridx = ring; /* save ring identity relative to detection */ - dev_set_drvdata(jrdev, jrpriv); + /* + * Derive a pointer to the detected JobRs regs + * Driver has already iomapped the entire space, we just + * need to add in the offset to this JobR. Don't know if I + * like this long-term, but it'll run + */ + jroffset_addr = of_get_property(np, "reg", NULL); - /* save ring identity relative to detection */ - jrpriv->ridx = total_jobrs++; + if (jroffset_addr == NULL) { + kfree(jrpriv); + return -EINVAL; + } - nprop = pdev->dev.of_node; - /* Get configuration properties from device tree */ - /* First, get register page */ - ctrl = of_iomap(nprop, 0); - if (!ctrl) { - dev_err(jrdev, "of_iomap() failed\n"); - return -ENOMEM; + /* + * Fix the endianness of this value read from the device + * tree if running on ARM. + */ + jroffset = be32_to_cpup(jroffset_addr); + + jrpriv->rregs = (struct caam_job_ring __iomem *)((void *)ctrlpriv->ctrl + + jroffset); + + /* Build a local dev for each detected queue */ + jr_pdev = of_platform_device_create(np, NULL, ctrldev); + if (jr_pdev == NULL) { + kfree(jrpriv); + return -EINVAL; } - jrpriv->rregs = (struct caam_job_ring __force *)ctrl; + jrpriv->jr_pdev = jr_pdev; + jrdev = &jr_pdev->dev; + dev_set_drvdata(jrdev, jrpriv); + ctrlpriv->jrdev[ring] = jrdev; if (sizeof(dma_addr_t) == sizeof(u64)) - if (of_device_is_compatible(nprop, "fsl,sec-v5.0-job-ring")) - dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(40)); + if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring")) + dma_set_mask(jrdev, DMA_BIT_MASK(40)); else - dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(36)); + dma_set_mask(jrdev, DMA_BIT_MASK(36)); else - dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(32)); + dma_set_mask(jrdev, DMA_BIT_MASK(32)); /* Identify the interrupt */ - jrpriv->irq = irq_of_parse_and_map(nprop, 0); + jrpriv->irq = of_irq_to_resource(np, 0, NULL); + if (jrpriv->irq <= 0) { + kfree(jrpriv); + return -EINVAL; + } /* Now do the platform independent part */ error = caam_jr_init(jrdev); /* now turn on hardware */ if (error) { - irq_dispose_mapping(jrpriv->irq); + of_device_unregister(jr_pdev); + kfree(jrpriv); return error; } - jrpriv->dev = jrdev; - spin_lock(&driver_data.jr_alloc_lock); - list_add_tail(&jrpriv->list_node, &driver_data.jr_list); - spin_unlock(&driver_data.jr_alloc_lock); - - atomic_set(&jrpriv->tfm_count, 0); - - return 0; -} - -static struct of_device_id caam_jr_match[] = { - { - .compatible = "fsl,sec-v4.0-job-ring", - }, - { - .compatible = "fsl,sec4.0-job-ring", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, caam_jr_match); - -static struct platform_driver caam_jr_driver = { - .driver = { - .name = "caam_jr", - .of_match_table = caam_jr_match, - }, - .probe = caam_jr_probe, - .remove = caam_jr_remove, -}; - -static int __init jr_driver_init(void) -{ - spin_lock_init(&driver_data.jr_alloc_lock); - INIT_LIST_HEAD(&driver_data.jr_list); - return platform_driver_register(&caam_jr_driver); -} - -static void __exit jr_driver_exit(void) -{ - platform_driver_unregister(&caam_jr_driver); + return error; } - -module_init(jr_driver_init); -module_exit(jr_driver_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("FSL CAAM JR request backend"); -MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); diff -Nur linux-4.1.13.orig/drivers/crypto/caam/jr.h linux-4.1.13/drivers/crypto/caam/jr.h --- linux-4.1.13.orig/drivers/crypto/caam/jr.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/jr.h 2015-11-30 17:56:13.548139857 +0100 @@ -1,18 +1,22 @@ /* * CAAM public-level include definitions for the JobR backend * - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. */ #ifndef JR_H #define JR_H /* Prototypes for backend-level services exposed to APIs */ -struct device *caam_jr_alloc(void); -void caam_jr_free(struct device *rdev); +int caam_jr_register(struct device *ctrldev, struct device **rdev); +int caam_jr_deregister(struct device *rdev); int caam_jr_enqueue(struct device *dev, u32 *desc, void (*cbk)(struct device *dev, u32 *desc, u32 status, void *areq), void *areq); +extern int caam_jr_probe(struct platform_device *pdev, struct device_node *np, + int ring); +extern int caam_jr_shutdown(struct device *dev); +extern struct device *caam_get_jrdev(void); #endif /* JR_H */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/Kconfig linux-4.1.13/drivers/crypto/caam/Kconfig --- linux-4.1.13.orig/drivers/crypto/caam/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/Kconfig 2015-11-30 17:56:13.548139857 +0100 @@ -1,32 +1,19 @@ 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). - This module creates job ring devices, and configures h/w + This module adds a job ring operation interface, and configures h/w to operate as a DPAA component automatically, depending on h/w feature availability. To compile this driver as a module, choose M here: the module will be called caam. -config CRYPTO_DEV_FSL_CAAM_JR - tristate "Freescale CAAM Job Ring driver backend" - depends on CRYPTO_DEV_FSL_CAAM - default y - help - Enables the driver module for Job Rings which are part of - Freescale's Cryptographic Accelerator - and Assurance Module (CAAM). This module adds a job ring operation - interface. - - To compile this driver as a module, choose M here: the module - will be called caam_jr. - config CRYPTO_DEV_FSL_CAAM_RINGSIZE int "Job Ring size" - depends on CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM range 2 9 default "9" help @@ -44,7 +31,7 @@ config CRYPTO_DEV_FSL_CAAM_INTC bool "Job Ring interrupt coalescing" - depends on CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM default n help Enable the Job Ring's interrupt coalescing feature. @@ -75,7 +62,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API tristate "Register algorithm implementations with the Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM default y select CRYPTO_ALGAPI select CRYPTO_AUTHENC @@ -89,7 +76,7 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API tristate "Register hash algorithm implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM default y select CRYPTO_HASH help @@ -101,7 +88,7 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API tristate "Register caam device for hwrng API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM default y select CRYPTO_RNG select HW_RANDOM @@ -112,6 +99,54 @@ To compile this as a module, choose M here: the module will be called caamrng. +config CRYPTO_DEV_FSL_CAAM_RNG_TEST + boolean "Test caam rng" + depends on CRYPTO_DEV_FSL_CAAM_RNG_API + default n + help + Selecting this will enable self-test for caam rng. + +config CRYPTO_DEV_FSL_CAAM_SM + tristate "CAAM Secure Memory / Keystore API (EXPERIMENTAL)" + default n + help + Enables use of a prototype kernel-level Keystore API with CAAM + Secure Memory for insertion/extraction of bus-protected secrets. + +config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE + int "Size of each keystore slot in Secure Memory" + depends on CRYPTO_DEV_FSL_CAAM_SM + range 5 9 + default 7 + help + Select size of allocation units to divide Secure Memory pages into + (the size of a "slot" as referenced inside the API code). + Established as powers of two. + Examples: + 5 => 32 bytes + 6 => 64 bytes + 7 => 128 bytes + 8 => 256 bytes + 9 => 512 bytes + +config CRYPTO_DEV_FSL_CAAM_SM_TEST + tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)" + depends on CRYPTO_DEV_FSL_CAAM_SM + default n + help + Example thread to exercise the Keystore API and to verify that + stored and recovered secrets can be used for general purpose + encryption/decryption. + +config CRYPTO_DEV_FSL_CAAM_SECVIO + tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)" + depends on CRYPTO_DEV_FSL_CAAM + default n + help + Enables installation of an interrupt handler with registrable + handler functions which can be specified to act on the consequences + of a security violation. + config CRYPTO_DEV_FSL_CAAM_DEBUG bool "Enable debug output in CAAM driver" depends on CRYPTO_DEV_FSL_CAAM @@ -119,3 +154,19 @@ help Selecting this will enable printing of various debug information in the CAAM driver. + +config CRYPTO_DEV_FSL_CAAM_KEYBLOB + tristate "Freescale CAAM memory keyblob driver backend" + depends on CRYPTO_DEV_FSL_CAAM + depends on CRYPTO_DEV_FSL_CAAM_JR + default y + help + Enables the driver module for Key Blob which are part of + Freescale's Cryptographic Accelerator + and Assurance Module (CAAM). This module adds a key blob operation + interface. + + To compile this driver as a module, choose M here: the module + will be called caam_keyblob. + + diff -Nur linux-4.1.13.orig/drivers/crypto/caam/key_gen.c linux-4.1.13/drivers/crypto/caam/key_gen.c --- linux-4.1.13.orig/drivers/crypto/caam/key_gen.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/key_gen.c 2015-11-30 17:56:13.552139590 +0100 @@ -1,7 +1,7 @@ /* * CAAM/SEC 4.x functions for handling key-generation jobs * - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. * */ #include "compat.h" @@ -19,8 +19,11 @@ dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - if (err) - caam_jr_strstatus(dev, err); + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } res->err = err; @@ -48,29 +51,24 @@ u32 *desc; struct split_key_result result; dma_addr_t dma_addr_in, dma_addr_out; - int ret = -ENOMEM; + int ret = 0; desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); if (!desc) { dev_err(jrdev, "unable to allocate key input memory\n"); - return ret; + return -ENOMEM; } + init_job_desc(desc, 0); + dma_addr_in = dma_map_single(jrdev, (void *)key_in, keylen, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, dma_addr_in)) { dev_err(jrdev, "unable to map key input memory\n"); - goto out_free; + kfree(desc); + return -ENOMEM; } - - dma_addr_out = dma_map_single(jrdev, key_out, split_key_pad_len, - DMA_FROM_DEVICE); - if (dma_mapping_error(jrdev, dma_addr_out)) { - dev_err(jrdev, "unable to map key output memory\n"); - goto out_unmap_in; - } - - 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 */ @@ -91,9 +89,9 @@ LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); #ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif @@ -106,12 +104,13 @@ wait_for_completion_interruptible(&result.completion); ret = result.err; #ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_out, 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-4.1.13.orig/drivers/crypto/caam/Makefile linux-4.1.13/drivers/crypto/caam/Makefile --- linux-4.1.13.orig/drivers/crypto/caam/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/Makefile 2015-11-30 17:56:13.552139590 +0100 @@ -1,15 +1,14 @@ # # Makefile for the CAAM backend and dependent components # -ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y) - EXTRA_CFLAGS := -DDEBUG -endif obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o 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 +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB) += caam_keyblob.o -caam-objs := ctrl.o -caam_jr-objs := jr.o key_gen.o error.o +caam-objs := ctrl.o jr.o error.o key_gen.o diff -Nur linux-4.1.13.orig/drivers/crypto/caam/pdb.h linux-4.1.13/drivers/crypto/caam/pdb.h --- linux-4.1.13.orig/drivers/crypto/caam/pdb.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/pdb.h 2015-11-30 17:56:13.552139590 +0100 @@ -44,7 +44,6 @@ #define PDBOPTS_ESP_IPHDRSRC 0x08 /* IP header comes from PDB (encap) */ #define PDBOPTS_ESP_INCIPHDR 0x04 /* Prepend IP header to output frame */ #define PDBOPTS_ESP_IPVSN 0x02 /* process IPv6 header */ -#define PDBOPTS_ESP_AOFL 0x04 /* adjust out frame len (decap, SEC>=5.3)*/ #define PDBOPTS_ESP_TUNNEL 0x01 /* tunnel mode next-header byte */ #define PDBOPTS_ESP_IPV6 0x02 /* ip header version is V6 */ #define PDBOPTS_ESP_DIFFSERV 0x40 /* copy TOS/TC from inner iphdr */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/regs.h linux-4.1.13/drivers/crypto/caam/regs.h --- linux-4.1.13.orig/drivers/crypto/caam/regs.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/regs.h 2015-11-30 17:56:13.552139590 +0100 @@ -1,7 +1,7 @@ /* * CAAM hardware register-level view * - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. */ #ifndef REGS_H @@ -74,17 +74,22 @@ #endif #else #ifdef __LITTLE_ENDIAN -#define wr_reg32(reg, data) __raw_writel(data, reg) -#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(data, reg) -#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 -#ifdef __BIG_ENDIAN static inline void wr_reg64(u64 __iomem *reg, u64 data) { wr_reg32((u32 __iomem *)reg, (data & 0xffffffff00000000ull) >> 32); @@ -96,21 +101,6 @@ return (((u64)rd_reg32((u32 __iomem *)reg)) << 32) | ((u64)rd_reg32((u32 __iomem *)reg + 1)); } -#else -#ifdef __LITTLE_ENDIAN -static inline void wr_reg64(u64 __iomem *reg, u64 data) -{ - wr_reg32((u32 __iomem *)reg + 1, (data & 0xffffffff00000000ull) >> 32); - wr_reg32((u32 __iomem *)reg, data & 0x00000000ffffffffull); -} - -static inline u64 rd_reg64(u64 __iomem *reg) -{ - return (((u64)rd_reg32((u32 __iomem *)reg + 1)) << 32) | - ((u64)rd_reg32((u32 __iomem *)reg)); -} -#endif -#endif #endif /* @@ -123,6 +113,98 @@ } __packed; /* + * CHA version ID / instantiation bitfields + * Defined for use within cha_id in perfmon + * Note that the same shift/mask selectors can be used to pull out number + * of instantiated blocks within cha_num in perfmon, the locations are + * the same. + */ + +/* Job Ring */ +#define CHA_ID_JR_SHIFT 60 +#define CHA_ID_JR_MASK (0xfull << CHA_ID_JR_SHIFT) + +/* DEscriptor COntroller */ +#define CHA_ID_DECO_SHIFT 56 +#define CHA_ID_DECO_MASK (0xfull << CHA_ID_DECO_SHIFT) +#define CHA_NUM_DECONUM_SHIFT 56 /* legacy definition */ +#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT) + +/* ZUC-Authentication */ +#define CHA_ID_ZA_SHIFT 44 +#define CHA_ID_ZA_MASK (0xfull << CHA_ID_ZA_SHIFT) + +/* ZUC-Encryption */ +#define CHA_ID_ZE_SHIFT 40 +#define CHA_ID_ZE_MASK (0xfull << CHA_ID_ZE_SHIFT) + +/* SNOW f9 */ +#define CHA_ID_SNW9_SHIFT 36 +#define CHA_ID_SNW9_MASK (0xfull << CHA_ID_SNW9_SHIFT) + +/* CRC */ +#define CHA_ID_CRC_SHIFT 32 +#define CHA_ID_CRC_MASK (0xfull << CHA_ID_CRC_SHIFT) + +/* Public Key */ +#define CHA_ID_PK_SHIFT 28 +#define CHA_ID_PK_MASK (0xfull << CHA_ID_PK_SHIFT) + +/* Kasumi */ +#define CHA_ID_KAS_SHIFT 24 +#define CHA_ID_KAS_MASK (0xfull << CHA_ID_KAS_SHIFT) + +/* SNOW f8 */ +#define CHA_ID_SNW8_SHIFT 20 +#define CHA_ID_SNW8_MASK (0xfull << CHA_ID_SNW8_SHIFT) + +/* + * Random Generator + * RNG4 = FIPS-verification-compliant, requires init kickstart for use + */ +#define CHA_ID_RNG_SHIFT 16 +#define CHA_ID_RNG_MASK (0xfull << CHA_ID_RNG_SHIFT) +#define CHA_ID_RNG_A (0x1ull << CHA_ID_RNG_SHIFT) +#define CHA_ID_RNG_B (0x2ull << CHA_ID_RNG_SHIFT) +#define CHA_ID_RNG_C (0x3ull << CHA_ID_RNG_SHIFT) +#define CHA_ID_RNG_4 (0x4ull << CHA_ID_RNG_SHIFT) + +/* + * Message Digest + * LP256 = Low Power (MD5/SHA1/SHA224/SHA256 + HMAC) + * LP512 = Low Power (LP256 + SHA384/SHA512) + * HP = High Power (LP512 + SMAC) + */ +#define CHA_ID_MD_SHIFT 12 +#define CHA_ID_MD_MASK (0xfull << CHA_ID_MD_SHIFT) +#define CHA_ID_MD_LP256 (0x0ull << CHA_ID_MD_SHIFT) +#define CHA_ID_MD_LP512 (0x1ull << CHA_ID_MD_SHIFT) +#define CHA_ID_MD_HP (0x2ull << CHA_ID_MD_SHIFT) + +/* ARC4 Streamcipher */ +#define CHA_ID_ARC4_SHIFT 8 +#define CHA_ID_ARC4_MASK (0xfull << CHA_ID_ARC4_SHIFT) +#define CHA_ID_ARC4_LP (0x0ull << CHA_ID_ARC4_SHIFT) +#define CHA_ID_ARC4_HP (0x1ull << CHA_ID_ARC4_SHIFT) + +/* DES Blockcipher Accelerator */ +#define CHA_ID_DES_SHIFT 4 +#define CHA_ID_DES_MASK (0xfull << CHA_ID_DES_SHIFT) + +/* + * AES Blockcipher + Combo Mode Accelerator + * LP = Low Power (includes ECB/CBC/CFB128/OFB/CTR/CCM/CMAC/XCBC-MAC) + * HP = High Power (LP + CBCXCBC/CTRXCBC/XTS/GCM) + * DIFFPWR = ORed in if differential-power-analysis resistance implemented + */ +#define CHA_ID_AES_SHIFT 0 +#define CHA_ID_AES_MASK (0xfull << CHA_ID_AES_SHIFT) +#define CHA_ID_AES_LP (0x3ull << CHA_ID_AES_SHIFT) +#define CHA_ID_AES_HP (0x4ull << CHA_ID_AES_SHIFT) +#define CHA_ID_AES_DIFFPWR (0x1ull << CHA_ID_AES_SHIFT) + + +/* * caam_perfmon - Performance Monitor/Secure Memory Status/ * CAAM Global Status/Component Version IDs * @@ -130,45 +212,8 @@ */ /* Number of DECOs */ -#define CHA_NUM_MS_DECONUM_SHIFT 24 -#define CHA_NUM_MS_DECONUM_MASK (0xfull << CHA_NUM_MS_DECONUM_SHIFT) - -/* CHA Version IDs */ -#define CHA_ID_LS_AES_SHIFT 0 -#define CHA_ID_LS_AES_MASK (0xfull << CHA_ID_LS_AES_SHIFT) - -#define CHA_ID_LS_DES_SHIFT 4 -#define CHA_ID_LS_DES_MASK (0xfull << CHA_ID_LS_DES_SHIFT) - -#define CHA_ID_LS_ARC4_SHIFT 8 -#define CHA_ID_LS_ARC4_MASK (0xfull << CHA_ID_LS_ARC4_SHIFT) - -#define CHA_ID_LS_MD_SHIFT 12 -#define CHA_ID_LS_MD_MASK (0xfull << CHA_ID_LS_MD_SHIFT) - -#define CHA_ID_LS_RNG_SHIFT 16 -#define CHA_ID_LS_RNG_MASK (0xfull << CHA_ID_LS_RNG_SHIFT) - -#define CHA_ID_LS_SNW8_SHIFT 20 -#define CHA_ID_LS_SNW8_MASK (0xfull << CHA_ID_LS_SNW8_SHIFT) - -#define CHA_ID_LS_KAS_SHIFT 24 -#define CHA_ID_LS_KAS_MASK (0xfull << CHA_ID_LS_KAS_SHIFT) - -#define CHA_ID_LS_PK_SHIFT 28 -#define CHA_ID_LS_PK_MASK (0xfull << CHA_ID_LS_PK_SHIFT) - -#define CHA_ID_MS_CRC_SHIFT 0 -#define CHA_ID_MS_CRC_MASK (0xfull << CHA_ID_MS_CRC_SHIFT) - -#define CHA_ID_MS_SNW9_SHIFT 4 -#define CHA_ID_MS_SNW9_MASK (0xfull << CHA_ID_MS_SNW9_SHIFT) - -#define CHA_ID_MS_DECO_SHIFT 24 -#define CHA_ID_MS_DECO_MASK (0xfull << CHA_ID_MS_DECO_SHIFT) - -#define CHA_ID_MS_JR_SHIFT 28 -#define CHA_ID_MS_JR_MASK (0xfull << CHA_ID_MS_JR_SHIFT) +#define CHA_NUM_DECONUM_SHIFT 56 +#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT) struct sec_vid { u16 ip_id; @@ -176,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 */ @@ -188,36 +237,89 @@ u64 rsvd[13]; /* CAAM Hardware Instantiation Parameters fa0-fbf */ - u32 cha_rev_ms; /* CRNR - CHA Rev No. Most significant half*/ - u32 cha_rev_ls; /* CRNR - CHA Rev No. Least significant half*/ -#define CTPR_MS_QI_SHIFT 25 -#define CTPR_MS_QI_MASK (0x1ull << CTPR_MS_QI_SHIFT) -#define CTPR_MS_VIRT_EN_INCL 0x00000001 -#define CTPR_MS_VIRT_EN_POR 0x00000002 -#define CTPR_MS_PG_SZ_MASK 0x10 -#define CTPR_MS_PG_SZ_SHIFT 4 - u32 comp_parms_ms; /* CTPR - Compile Parameters Register */ - u32 comp_parms_ls; /* CTPR - Compile Parameters Register */ - u64 rsvd1[2]; + u64 cha_rev; /* CRNR - CHA Revision Number */ +#define CTPR_QI_SHIFT 57 +#define CTPR_QI_MASK (0x1ull << CTPR_QI_SHIFT) + u64 comp_parms; /* CTPR - Compile Parameters Register */ + + /* 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 */ u32 ccb_id; /* CCBVID - CCB Version ID */ - u32 cha_id_ms; /* CHAVID - CHA Version ID Most Significant*/ - u32 cha_id_ls; /* CHAVID - CHA Version ID Least Significant*/ - u32 cha_num_ms; /* CHANUM - CHA Number Most Significant */ - u32 cha_num_ls; /* CHANUM - CHA Number Least Significant*/ - u32 caam_id_ms; /* CAAMVID - CAAM Version ID MS */ - u32 caam_id_ls; /* CAAMVID - CAAM Version ID LS */ -}; + u64 cha_id; /* CHAVID - CHA Version ID */ + u64 cha_num; /* CHANUM - CHA Number */ + 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 @@ -270,17 +372,7 @@ /* RNG4 TRNG test registers */ struct rng4tst { -#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */ -#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0 /* use von Neumann data in - both entropy shifter and - statistical checker */ -#define RTMCTL_SAMP_MODE_RAW_ES_SC 1 /* use raw data in both - entropy shifter and - statistical checker */ -#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_RAW_SC 2 /* use von Neumann data in - entropy shifter, raw data - in statistical checker */ -#define RTMCTL_SAMP_MODE_INVALID 3 /* invalid combination */ +#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */ u32 rtmctl; /* misc. control register */ u32 rtscmisc; /* statistical check misc. register */ u32 rtpkrrng; /* poker range register */ @@ -290,26 +382,22 @@ }; #define RTSDCTL_ENT_DLY_SHIFT 16 #define RTSDCTL_ENT_DLY_MASK (0xffff << RTSDCTL_ENT_DLY_SHIFT) -#define RTSDCTL_ENT_DLY_MIN 3200 -#define RTSDCTL_ENT_DLY_MAX 12800 u32 rtsdctl; /* seed control register */ union { u32 rtsblim; /* PRGM=1: sparse bit limit register */ u32 rttotsam; /* PRGM=0: total samples register */ }; u32 rtfrqmin; /* frequency count min. limit register */ -#define RTFRQMAX_DISABLE (1 << 20) union { u32 rtfrqmax; /* PRGM=1: freq. count max. limit register */ u32 rtfrqcnt; /* PRGM=0: freq. count register */ }; u32 rsvd1[40]; -#define RDSTA_SKVT 0x80000000 -#define RDSTA_SKVN 0x40000000 -#define RDSTA_IF0 0x00000001 -#define RDSTA_IF1 0x00000002 -#define RDSTA_IFMASK (RDSTA_IF1 | RDSTA_IF0) - u32 rdsta; +#define RDSTA_IF 0x00000003 /* state handle instantiated flags 0 and 1 */ +#define RDSTA_SKVN 0x40000000 /* Secure Key Valid Non-Test mode */ +#define RDSTA_SKVT 0x80000000 /* Secure Key Valid Test. non-test mode */ +#define RDSTA_TF 0x00000300 /* State handle instantiated Test-mode */ + u32 rdsta; /* DRNG status register */ u32 rsvd2[15]; }; @@ -340,12 +428,9 @@ /* Bus Access Configuration Section 010-11f */ /* Read/Writable */ struct masterid jr_mid[4]; /* JRxLIODNR - JobR LIODN setup */ - u32 rsvd3[11]; - u32 jrstart; /* JRSTART - Job Ring Start Register */ + u32 rsvd3[12]; struct masterid rtic_mid[4]; /* RTICxLIODNR - RTIC LIODN setup */ - u32 rsvd4[5]; - u32 deco_rsr; /* DECORSR - Deco Request Source */ - u32 rsvd11; + u32 rsvd4[7]; u32 deco_rq; /* DECORR - DECO Request */ struct partid deco_mid[5]; /* DECOxLIODNR - 1 per DECO */ u32 rsvd5[22]; @@ -386,11 +471,6 @@ #define MCFGR_DMA_RESET 0x10000000 #define MCFGR_LONG_PTR 0x00010000 /* Use >32-bit desc addressing */ #define SCFGR_RDBENABLE 0x00000400 -#define SCFGR_VIRT_EN 0x00008000 -#define DECORR_RQD0ENABLE 0x00000001 /* Enable DECO0 for direct access */ -#define DECORSR_JR0 0x00000001 /* JR to supply TZ, SDID, ICID */ -#define DECORSR_VALID 0x80000000 -#define DECORR_DEN0 0x00010000 /* DECO0 available for access*/ /* AXI read cache control */ #define MCFGR_ARCACHE_SHIFT 12 @@ -407,12 +487,6 @@ #define MCFGR_AXIPRI 0x00000008 /* Assert AXI priority sideband */ #define MCFGR_BURST_64 0x00000001 /* Max burst size */ -/* JRSTART register offsets */ -#define JRSTART_JR0_START 0x00000001 /* Start Job ring 0 */ -#define JRSTART_JR1_START 0x00000002 /* Start Job ring 1 */ -#define JRSTART_JR2_START 0x00000004 /* Start Job ring 2 */ -#define JRSTART_JR3_START 0x00000008 /* Start Job ring 3 */ - /* * caam_job_ring - direct job ring setup * 1-4 possible per instantiation, base + 1000/2000/3000/4000 @@ -455,7 +529,18 @@ u32 rsvd11; u32 jrcommand; /* JRCRx - JobR command */ - u32 rsvd12[932]; + u32 rsvd12[33]; + + /* Secure Memory Configuration - if you have it */ + u32 sm_cmd; /* SMCJRx - Secure memory command */ + u32 rsvd13; + u32 sm_status; /* SMCSJRx - Secure memory status */ + u32 rsvd14; + u32 sm_perm; /* SMAPJRx - Secure memory access perms */ + u32 sm_group2; /* SMAP2JRx - Secure memory access group 2 */ + u32 sm_group1; /* SMAP1JRx - Secure memory access group 1 */ + + u32 rsvd15[891]; /* Performance Monitor f00-fff */ struct caam_perfmon perfmon; @@ -578,6 +663,62 @@ #define JRCR_RESET 0x01 +/* secure memory command */ +#define SMC_PAGE_SHIFT 16 +#define SMC_PAGE_MASK (0xffff << SMC_PAGE_SHIFT) +#define SMC_PART_SHIFT 8 +#define SMC_PART_MASK (0x0f << SMC_PART_SHIFT) +#define SMC_CMD_SHIFT 0 +#define SMC_CMD_MASK (0x0f << SMC_CMD_SHIFT) + +#define SMC_CMD_ALLOC_PAGE 0x01 /* allocate page to this partition */ +#define SMC_CMD_DEALLOC_PAGE 0x02 /* deallocate page from partition */ +#define SMC_CMD_DEALLOC_PART 0x03 /* deallocate partition */ +#define SMC_CMD_PAGE_INQUIRY 0x05 /* find partition associate with page */ + +/* secure memory (command) status */ +#define SMCS_PAGE_SHIFT 16 +#define SMCS_PAGE_MASK (0x0fff << SMCS_PAGE_SHIFT) +#define SMCS_CMDERR_SHIFT 14 +#define SMCS_CMDERR_MASK (3 << SMCS_CMDERR_SHIFT) +#define SMCS_ALCERR_SHIFT 12 +#define SMCS_ALCERR_MASK (3 << SMCS_ALCERR_SHIFT) +#define SMCS_PGOWN_SHIFT 6 +#define SMCS_PGWON_MASK (3 << SMCS_PGOWN_SHIFT) +#define SMCS_PART_SHIFT 0 +#define SMCS_PART_MASK (0xf << SMCS_PART_SHIFT) + +#define SMCS_CMDERR_NONE 0 +#define SMCS_CMDERR_INCOMP 1 /* Command not yet complete */ +#define SMCS_CMDERR_SECFAIL 2 /* Security failure occurred */ +#define SMCS_CMDERR_OVERFLOW 3 /* Command overflow */ + +#define SMCS_ALCERR_NONE 0 +#define SMCS_ALCERR_PSPERR 1 /* Partion marked PSP (dealloc only) */ +#define SMCS_ALCERR_PAGEAVAIL 2 /* Page not available */ +#define SMCS_ALCERR_PARTOWN 3 /* Partition ownership error */ + +#define SMCS_PGOWN_AVAIL 0 /* Page is available */ +#define SMCS_PGOWN_NOEXIST 1 /* Page initializing or nonexistent */ +#define SMCS_PGOWN_NOOWN 2 /* Page owned by another processor */ +#define SMCS_PGOWN_OWNED 3 /* Page belongs to this processor */ + +/* secure memory access permissions */ +#define SMCS_PERM_KEYMOD_SHIFT 16 +#define SMCA_PERM_KEYMOD_MASK (0xff << SMCS_PERM_KEYMOD_SHIFT) +#define SMCA_PERM_CSP_ZERO 0x8000 /* Zero when deallocated or released */ +#define SMCA_PERM_PSP_LOCK 0x4000 /* Part./pages can't be deallocated */ +#define SMCA_PERM_PERM_LOCK 0x2000 /* Lock permissions */ +#define SMCA_PERM_GRP_LOCK 0x1000 /* Lock access groups */ +#define SMCA_PERM_RINGID_SHIFT 10 +#define SMCA_PERM_RINGID_MASK (3 << SMCA_PERM_RINGID_SHIFT) +#define SMCA_PERM_G2_BLOB 0x0080 /* Group 2 blob import/export */ +#define SMCA_PERM_G2_WRITE 0x0020 /* Group 2 write */ +#define SMCA_PERM_G2_READ 0x0010 /* Group 2 read */ +#define SMCA_PERM_G1_BLOB 0x0008 /* Group 1... */ +#define SMCA_PERM_G1_WRITE 0x0002 +#define SMCA_PERM_G1_READ 0x0001 + /* * caam_assurance - Assurance Controller View * base + 0x6000 padded out to 0x1000 @@ -746,7 +887,6 @@ u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */ u32 jr_ctl_lo; u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */ -#define DECO_OP_STATUS_HI_ERR_MASK 0xF00000FF u32 op_status_hi; /* DxOPSTA - DECO Operation Status */ u32 op_status_lo; u32 rsvd24[2]; @@ -760,21 +900,36 @@ struct deco_sg_table sctr_tbl[4]; /* DxSTR - Scatter Tables */ u32 rsvd29[48]; u32 descbuf[64]; /* DxDESB - Descriptor buffer */ - u32 rscvd30[193]; -#define DESC_DBG_DECO_STAT_HOST_ERR 0x00D00000 -#define DESC_DBG_DECO_STAT_VALID 0x80000000 -#define DESC_DBG_DECO_STAT_MASK 0x00F00000 - u32 desc_dbg; /* DxDDR - DECO Debug Register */ - u32 rsvd31[126]; -}; - -#define DECO_JQCR_WHL 0x20000000 -#define DECO_JQCR_FOUR 0x10000000 - -#define JR_BLOCK_NUMBER 1 -#define ASSURE_BLOCK_NUMBER 6 -#define QI_BLOCK_NUMBER 7 -#define DECO_BLOCK_NUMBER 8 -#define PG_SIZE_4K 0x1000 -#define PG_SIZE_64K 0x10000 + u32 rsvd30[320]; +}; + +/* + * Current top-level view of memory map is: + * + * 0x0000 - 0x0fff - CAAM Top-Level Control + * 0x1000 - 0x1fff - Job Ring 0 + * 0x2000 - 0x2fff - Job Ring 1 + * 0x3000 - 0x3fff - Job Ring 2 + * 0x4000 - 0x4fff - Job Ring 3 + * 0x5000 - 0x5fff - (unused) + * 0x6000 - 0x6fff - Assurance Controller + * 0x7000 - 0x7fff - Queue Interface + * 0x8000 - 0x8fff - DECO-CCB 0 + * 0x9000 - 0x9fff - DECO-CCB 1 + * 0xa000 - 0xafff - DECO-CCB 2 + * 0xb000 - 0xbfff - DECO-CCB 3 + * 0xc000 - 0xcfff - DECO-CCB 4 + * + * caam_full describes the full register view of CAAM if useful, + * although many configurations may choose to implement parts of + * the register map separately, in differing privilege regions + */ +struct caam_full { + struct caam_ctrl __iomem ctrl; + struct caam_job_ring jr[4]; + u64 rsvd[512]; + struct caam_assurance assure; + struct caam_queue_if qi; +}; + #endif /* REGS_H */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/secvio.c linux-4.1.13/drivers/crypto/caam/secvio.c --- linux-4.1.13.orig/drivers/crypto/caam/secvio.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/secvio.c 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,290 @@ + +/* + * SNVS Security Violation Handler + * Copyright (C) 2012-2015 Freescale Semiconductor, Inc., All Rights Reserved + */ + +#include "compat.h" +#include "intern.h" +#include "secvio.h" +#include "regs.h" + +/* + * These names are associated with each violation handler. + * The source names were taken from MX6, and are based on recommendations + * for most common SoCs. + */ +static const u8 *violation_src_name[] = { + "CAAM 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-4.1.13.orig/drivers/crypto/caam/secvio.h linux-4.1.13/drivers/crypto/caam/secvio.h --- linux-4.1.13.orig/drivers/crypto/caam/secvio.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/secvio.h 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,66 @@ + +/* + * CAAM Security Violation Handler + * Copyright (C) 2012-2014 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-4.1.13.orig/drivers/crypto/caam/sg_sw_sec4.h linux-4.1.13/drivers/crypto/caam/sg_sw_sec4.h --- linux-4.1.13.orig/drivers/crypto/caam/sg_sw_sec4.h 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/sg_sw_sec4.h 2015-11-30 17:56:13.552139590 +0100 @@ -1,7 +1,7 @@ /* * CAAM/SEC 4.x functions for using scatterlists in caam driver * - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. * */ @@ -91,13 +91,22 @@ { if (unlikely(chained)) { int i; + struct scatterlist *tsg = sg; + + /* We use a local copy of the sg pointer to avoid moving the + * head of the list pointed to by sg as we wall the list. + */ for (i = 0; i < nents; i++) { - dma_map_sg(dev, sg, 1, dir); - sg = sg_next(sg); + dma_map_sg(dev, tsg, 1, dir); + tsg = 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++) { @@ -116,3 +128,41 @@ } return nents; } + +/* Copy from len bytes of sg to dest, starting from beginning */ +static inline void sg_copy(u8 *dest, struct scatterlist *sg, unsigned int len) +{ + struct scatterlist *current_sg = sg; + int cpy_index = 0, next_cpy_index = current_sg->length; + + while (next_cpy_index < len) { + memcpy(dest + cpy_index, (u8 *) sg_virt(current_sg), + current_sg->length); + current_sg = sg_next(current_sg); + cpy_index = next_cpy_index; + next_cpy_index += current_sg->length; + } + if (cpy_index < len) + memcpy(dest + cpy_index, (u8 *) sg_virt(current_sg), + len - cpy_index); +} + +/* Copy sg data, from to_skip to end, to dest */ +static inline void sg_copy_part(u8 *dest, struct scatterlist *sg, + int to_skip, unsigned int end) +{ + struct scatterlist *current_sg = sg; + int sg_index, cpy_index; + + sg_index = current_sg->length; + while (sg_index <= to_skip) { + current_sg = sg_next(current_sg); + sg_index += current_sg->length; + } + cpy_index = sg_index - to_skip; + memcpy(dest, (u8 *) sg_virt(current_sg) + + current_sg->length - cpy_index, cpy_index); + current_sg = sg_next(current_sg); + if (end - sg_index) + sg_copy(dest + cpy_index, current_sg, end - sg_index); +} diff -Nur linux-4.1.13.orig/drivers/crypto/caam/sm.h linux-4.1.13/drivers/crypto/caam/sm.h --- linux-4.1.13.orig/drivers/crypto/caam/sm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/sm.h 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,88 @@ + +/* + * CAAM Secure Memory/Keywrap API Definitions + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + */ + +#ifndef SM_H +#define SM_H + + +/* Storage access permissions */ +#define SM_PERM_READ 0x01 +#define SM_PERM_WRITE 0x02 +#define SM_PERM_BLOB 0x03 + + +/* Keystore maintenance functions */ +void sm_init_keystore(struct device *dev); +u32 sm_detect_keystore_units(struct device *dev); +int sm_establish_keystore(struct device *dev, u32 unit); +void sm_release_keystore(struct device *dev, u32 unit); +void caam_sm_shutdown(struct platform_device *pdev); +int caam_sm_example_init(struct platform_device *pdev); + +/* Keystore accessor functions */ +extern int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, + u32 *slot); +extern int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot); +extern int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot, + const u8 *key_data, u32 key_length); +extern int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot, + u32 key_length, u8 *key_data); +extern int sm_keystore_slot_encapsulate(struct device *dev, u32 unit, + u32 inslot, u32 outslot, u16 secretlen, + u8 *keymod, u16 keymodlen); +extern int sm_keystore_slot_decapsulate(struct device *dev, u32 unit, + u32 inslot, u32 outslot, u16 secretlen, + u8 *keymod, u16 keymodlen); + +/* Data structure to hold per-slot information */ +struct keystore_data_slot_info { + u8 allocated; /* Track slot assignments */ + u32 key_length; /* Size of the key */ +}; + +/* Data structure to hold keystore information */ +struct keystore_data { + void *base_address; /* Base of the Secure Partition */ + u32 slot_count; /* Number of slots in the keystore */ + struct keystore_data_slot_info *slot; /* Per-slot information */ +}; + +/* store the detected attributes of a secure memory page */ +struct sm_page_descriptor { + u16 phys_pagenum; /* may be discontiguous */ + u16 own_part; /* Owning partition */ + void *pg_base; /* Calculated virtual address */ + struct keystore_data *ksdata; +}; + +struct caam_drv_private_sm { + struct device *parentdev; /* this ends up as the controller */ + struct device *smringdev; /* ring that owns this instance */ + spinlock_t kslock ____cacheline_aligned; + + /* Default parameters for geometry */ + u32 max_pages; /* maximum pages this instance can support */ + u32 top_partition; /* highest partition number in this instance */ + u32 top_page; /* highest page number in this instance */ + u32 page_size; /* page size */ + u32 slot_size; /* selected size of each storage block */ + + /* Partition/Page Allocation Map */ + u32 localpages; /* Number of pages we can access */ + struct sm_page_descriptor *pagedesc; /* Allocated per-page */ + + /* Installed handlers for keystore access */ + int (*data_init)(struct device *dev, u32 unit); + void (*data_cleanup)(struct device *dev, u32 unit); + int (*slot_alloc)(struct device *dev, u32 unit, u32 size, u32 *slot); + int (*slot_dealloc)(struct device *dev, u32 unit, u32 slot); + void *(*slot_get_address)(struct device *dev, u32 unit, u32 handle); + u32 (*slot_get_base)(struct device *dev, u32 unit, u32 handle); + u32 (*slot_get_offset)(struct device *dev, u32 unit, u32 handle); + u32 (*slot_get_slot_size)(struct device *dev, u32 unit, u32 handle); +}; + +#endif /* SM_H */ diff -Nur linux-4.1.13.orig/drivers/crypto/caam/sm_store.c linux-4.1.13/drivers/crypto/caam/sm_store.c --- linux-4.1.13.orig/drivers/crypto/caam/sm_store.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/sm_store.c 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,896 @@ + +/* + * CAAM Secure Memory Storage Interface + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + * + * Loosely based on the SHW Keystore API for SCC/SCC2 + * Experimental implementation and NOT intended for upstream use. Expect + * this interface to be amended significantly in the future once it becomes + * integrated into live applications. + * + * Known issues: + * + * - Executes one instance of an secure memory "driver". This is tied to the + * fact that job rings can't run as standalone instances in the present + * configuration. + * + * - It does not expose a userspace interface. The value of a userspace + * interface for access to secrets is a point for further architectural + * discussion. + * + * - Partition/permission management is not part of this interface. It + * depends on some level of "knowledge" agreed upon between bootloader, + * provisioning applications, and OS-hosted software (which uses this + * driver). + * + * - No means of identifying the location or purpose of secrets managed by + * this interface exists; "slot location" and format of a given secret + * needs to be agreed upon between bootloader, provisioner, and OS-hosted + * application. + */ + +#include "compat.h" +#include "regs.h" +#include "jr.h" +#include "desc.h" +#include "intern.h" +#include "error.h" +#include "sm.h" + +#ifdef SM_DEBUG_CONT +void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + u32 i, *smdata; + + dev_info(dev, "physical page %d content at 0x%08x\n", + pgdesc->phys_pagenum, pgdesc->pg_base); + smdata = pgdesc->pg_base; + for (i = 0; i < (smpriv->page_size / sizeof(u32)); i += 4) + dev_info(dev, "[0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", + (u32)&smdata[i], smdata[i], smdata[i+1], smdata[i+2], + smdata[i+3]); +} +#endif + +/* + * Construct a secure memory blob encapsulation job descriptor + * + * - desc pointer to hold new (to be allocated) pointer to the generated + * descriptor for later use. Calling thread can kfree the + * descriptor after execution. + * - keymod Physical pointer to key modifier (contiguous piece). + * - keymodsz Size of key modifier in bytes (should normally be 8). + * - secretbuf Physical pointer (within an accessible secure memory page) + * of the secret to be encapsulated. + * - outbuf Physical pointer (within an accessible secure memory page) + * of the encapsulated output. This will be larger than the + * input secret because of the added encapsulation data. + * - secretsz Size of input secret, in bytes. + * - auth If nonzero, use AES-CCM for encapsulation, else use ECB + * + * Note: this uses 32-bit pointers at present + */ +#define INITIAL_DESCSZ 16 /* size of tmp buffer for descriptor const. */ +static int blob_encap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz, + dma_addr_t secretbuf, dma_addr_t outbuf, + u16 secretsz, bool auth) +{ + u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; + u16 dsize, idx; + + memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); + idx = 1; + + /* Load key modifier */ + tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY | + ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) | + (keymodsz & LDST_LEN_MASK); + + tmpdesc[idx++] = (u32)keymod; + + /* Encapsulate to secure memory */ + tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz; + tmpdesc[idx++] = (u32)secretbuf; + + /* Add space for BKEK and MAC tag */ + tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + (32 + 16)); + + tmpdesc[idx++] = (u32)outbuf; + tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB | + OP_PCL_BLOB_PTXT_SECMEM; + if (auth) + tmpdesc[idx] |= OP_PCL_BLOB_EKT; + + idx++; + tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK); + dsize = idx * sizeof(u32); + + tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA); + if (tdesc == NULL) + return 0; + + memcpy(tdesc, tmpdesc, dsize); + *desc = tdesc; + return dsize; +} + +/* + * Construct a secure memory blob decapsulation job descriptor + * + * - desc pointer to hold new (to be allocated) pointer to the generated + * descriptor for later use. Calling thread can kfree the + * descriptor after execution. + * - keymod Physical pointer to key modifier (contiguous piece). + * - keymodsz Size of key modifier in bytes (should normally be 16). + * - blobbuf Physical pointer (within an accessible secure memory page) + * of the blob to be decapsulated. + * - outbuf Physical pointer (within an accessible secure memory page) + * of the decapsulated output. + * - secretsz Size of input blob, in bytes. + * - auth If nonzero, assume AES-CCM for decapsulation, else use ECB + * + * Note: this uses 32-bit pointers at present + */ +static int blob_decap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz, + dma_addr_t blobbuf, dma_addr_t outbuf, + u16 blobsz, bool auth) +{ + u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; + u16 dsize, idx; + + memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); + idx = 1; + + /* Load key modifier */ + tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY | + ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) | + (keymodsz & LDST_LEN_MASK); + + tmpdesc[idx++] = (u32)keymod; + + /* Compensate BKEK + MAC tag */ + tmpdesc[idx++] = CMD_SEQ_IN_PTR | (blobsz + 32 + 16); + + tmpdesc[idx++] = (u32)blobbuf; + tmpdesc[idx++] = CMD_SEQ_OUT_PTR | blobsz; + tmpdesc[idx++] = (u32)outbuf; + + /* Decapsulate from secure memory partition to black blob */ + tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB | + OP_PCL_BLOB_PTXT_SECMEM | OP_PCL_BLOB_BLACK; + if (auth) + tmpdesc[idx] |= OP_PCL_BLOB_EKT; + + idx++; + tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK); + dsize = idx * sizeof(u32); + + tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA); + if (tdesc == NULL) + return 0; + + memcpy(tdesc, tmpdesc, dsize); + *desc = tdesc; + return dsize; +} + +/* + * Pseudo-synchronous ring access functions for carrying out key + * encapsulation and decapsulation + */ + +struct sm_key_job_result { + int error; + struct completion completion; +}; + +void sm_key_job_done(struct device *dev, u32 *desc, u32 err, void *context) +{ + struct sm_key_job_result *res = context; + + res->error = err; /* save off the error for postprocessing */ + complete(&res->completion); /* mark us complete */ +} + +static int sm_key_job(struct device *ksdev, u32 *jobdesc) +{ + struct sm_key_job_result testres; + struct caam_drv_private_sm *kspriv; + int rtn = 0; + + kspriv = dev_get_drvdata(ksdev); + + init_completion(&testres.completion); + + rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, sm_key_job_done, + &testres); + if (!rtn) { + wait_for_completion_interruptible(&testres.completion); + rtn = testres.error; + } + return rtn; +} + +/* + * Following section establishes the default methods for keystore access + * They are NOT intended for use external to this module + * + * In the present version, these are the only means for the higher-level + * interface to deal with the mechanics of accessing the phyiscal keystore + */ + + +int slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; + u32 i; +#ifdef SM_DEBUG + dev_info(dev, "slot_alloc(): requesting slot for %d bytes\n", size); +#endif + + if (size > smpriv->slot_size) + return -EKEYREJECTED; + + for (i = 0; i < ksdata->slot_count; i++) { + if (ksdata->slot[i].allocated == 0) { + ksdata->slot[i].allocated = 1; + (*slot) = i; +#ifdef SM_DEBUG + dev_info(dev, "slot_alloc(): new slot %d allocated\n", + *slot); +#endif + return 0; + } + } + + return -ENOSPC; +} +EXPORT_SYMBOL(slot_alloc); + +int slot_dealloc(struct device *dev, u32 unit, u32 slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; + u8 __iomem *slotdata; + +#ifdef SM_DEBUG + dev_info(dev, "slot_dealloc(): releasing slot %d\n", slot); +#endif + if (slot >= ksdata->slot_count) + return -EINVAL; + slotdata = ksdata->base_address + slot * smpriv->slot_size; + + if (ksdata->slot[slot].allocated == 1) { + /* Forcibly overwrite the data from the keystore */ + memset(ksdata->base_address + slot * smpriv->slot_size, 0, + smpriv->slot_size); + + ksdata->slot[slot].allocated = 0; +#ifdef SM_DEBUG + dev_info(dev, "slot_dealloc(): slot %d released\n", slot); +#endif + return 0; + } + + return -EINVAL; +} +EXPORT_SYMBOL(slot_dealloc); + +void *slot_get_address(struct device *dev, u32 unit, u32 slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; + + if (slot >= ksdata->slot_count) + return NULL; + +#ifdef SM_DEBUG + dev_info(dev, "slot_get_address(): slot %d is 0x%08x\n", slot, + (u32)ksdata->base_address + slot * smpriv->slot_size); +#endif + + return ksdata->base_address + slot * smpriv->slot_size; +} + +u32 slot_get_base(struct device *dev, u32 unit, u32 slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; + + /* + * There could potentially be more than one secure partition object + * associated with this keystore. For now, there is just one. + */ + + (void)slot; + +#ifdef SM_DEBUG + dev_info(dev, "slot_get_base(): slot %d = 0x%08x\n", + slot, (u32)ksdata->base_address); +#endif + + return (u32)(ksdata->base_address); +} + +u32 slot_get_offset(struct device *dev, u32 unit, u32 slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; + + if (slot >= ksdata->slot_count) + return -EINVAL; + +#ifdef SM_DEBUG + dev_info(dev, "slot_get_offset(): slot %d = %d\n", slot, + slot * smpriv->slot_size); +#endif + + return slot * smpriv->slot_size; +} + +u32 slot_get_slot_size(struct device *dev, u32 unit, u32 slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + + +#ifdef SM_DEBUG + dev_info(dev, "slot_get_slot_size(): slot %d = %d\n", slot, + smpriv->slot_size); +#endif + /* All slots are the same size in the default implementation */ + return smpriv->slot_size; +} + + + +int kso_init_data(struct device *dev, u32 unit) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + int retval = -EINVAL; + struct keystore_data *keystore_data = NULL; + u32 slot_count; + u32 keystore_data_size; + + /* + * Calculate the required size of the keystore data structure, based + * on the number of keys that can fit in the partition. + */ + slot_count = smpriv->page_size / smpriv->slot_size; +#ifdef SM_DEBUG + dev_info(dev, "kso_init_data: %d slots initializing\n", slot_count); +#endif + + keystore_data_size = sizeof(struct keystore_data) + + slot_count * + sizeof(struct keystore_data_slot_info); + + keystore_data = kzalloc(keystore_data_size, GFP_KERNEL); + + if (keystore_data == NULL) { + retval = -ENOSPC; + goto out; + } + +#ifdef SM_DEBUG + dev_info(dev, "kso_init_data: keystore data size = %d\n", + keystore_data_size); +#endif + + /* + * Place the slot information structure directly after the keystore data + * structure. + */ + keystore_data->slot = (struct keystore_data_slot_info *) + (keystore_data + 1); + keystore_data->slot_count = slot_count; + + smpriv->pagedesc[unit].ksdata = keystore_data; + smpriv->pagedesc[unit].ksdata->base_address = + smpriv->pagedesc[unit].pg_base; + + retval = 0; + +out: + if (retval != 0) + if (keystore_data != NULL) + kfree(keystore_data); + + + return retval; +} + +void kso_cleanup_data(struct device *dev, u32 unit) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + struct keystore_data *keystore_data = NULL; + + if (smpriv->pagedesc[unit].ksdata != NULL) + keystore_data = smpriv->pagedesc[unit].ksdata; + + /* Release the allocated keystore management data */ + kfree(smpriv->pagedesc[unit].ksdata); + + return; +} + + + +/* + * Keystore management section + */ + +void sm_init_keystore(struct device *dev) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + + smpriv->data_init = kso_init_data; + smpriv->data_cleanup = kso_cleanup_data; + smpriv->slot_alloc = slot_alloc; + smpriv->slot_dealloc = slot_dealloc; + smpriv->slot_get_address = slot_get_address; + smpriv->slot_get_base = slot_get_base; + smpriv->slot_get_offset = slot_get_offset; + smpriv->slot_get_slot_size = slot_get_slot_size; +#ifdef SM_DEBUG + dev_info(dev, "sm_init_keystore(): handlers installed\n"); +#endif +} +EXPORT_SYMBOL(sm_init_keystore); + +/* Return available pages/units */ +u32 sm_detect_keystore_units(struct device *dev) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + + return smpriv->localpages; +} +EXPORT_SYMBOL(sm_detect_keystore_units); + +/* + * Do any keystore specific initializations + */ +int sm_establish_keystore(struct device *dev, u32 unit) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + +#ifdef SM_DEBUG + dev_info(dev, "sm_establish_keystore(): unit %d initializing\n", unit); +#endif + + if (smpriv->data_init == NULL) + return -EINVAL; + + /* Call the data_init function for any user setup */ + return smpriv->data_init(dev, unit); +} +EXPORT_SYMBOL(sm_establish_keystore); + +void sm_release_keystore(struct device *dev, u32 unit) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + +#ifdef SM_DEBUG + dev_info(dev, "sm_establish_keystore(): unit %d releasing\n", unit); +#endif + if ((smpriv != NULL) && (smpriv->data_cleanup != NULL)) + smpriv->data_cleanup(dev, unit); + + return; +} +EXPORT_SYMBOL(sm_release_keystore); + +/* + * Subsequent interfacce (sm_keystore_*) forms the accessor interfacce to + * the keystore + */ +int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + int retval = -EINVAL; + + spin_lock(&smpriv->kslock); + + if ((smpriv->slot_alloc == NULL) || + (smpriv->pagedesc[unit].ksdata == NULL)) + goto out; + + retval = smpriv->slot_alloc(dev, unit, size, slot); + +out: + spin_unlock(&smpriv->kslock); + return retval; +} +EXPORT_SYMBOL(sm_keystore_slot_alloc); + +int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + int retval = -EINVAL; + + spin_lock(&smpriv->kslock); + + if ((smpriv->slot_alloc == NULL) || + (smpriv->pagedesc[unit].ksdata == NULL)) + goto out; + + retval = smpriv->slot_dealloc(dev, unit, slot); +out: + spin_unlock(&smpriv->kslock); + return retval; +} +EXPORT_SYMBOL(sm_keystore_slot_dealloc); + +int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot, + const u8 *key_data, u32 key_length) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + int retval = -EINVAL; + u32 slot_size; + u32 i; + u8 __iomem *slot_location; + + spin_lock(&smpriv->kslock); + + slot_size = smpriv->slot_get_slot_size(dev, unit, slot); + + if (key_length > slot_size) { + retval = -EFBIG; + goto out; + } + + slot_location = smpriv->slot_get_address(dev, unit, slot); + + for (i = 0; i < key_length; i++) + slot_location[i] = key_data[i]; + + retval = 0; + +out: + spin_unlock(&smpriv->kslock); + return retval; +} +EXPORT_SYMBOL(sm_keystore_slot_load); + +int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot, + u32 key_length, u8 *key_data) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + int retval = -EINVAL; + u8 __iomem *slot_addr; + u32 slot_size; + + spin_lock(&smpriv->kslock); + + slot_addr = smpriv->slot_get_address(dev, unit, slot); + slot_size = smpriv->slot_get_slot_size(dev, unit, slot); + + if (key_length > slot_size) { + retval = -EKEYREJECTED; + goto out; + } + + memcpy(key_data, slot_addr, key_length); + retval = 0; + +out: + spin_unlock(&smpriv->kslock); + return retval; +} +EXPORT_SYMBOL(sm_keystore_slot_read); + +int sm_keystore_slot_encapsulate(struct device *dev, u32 unit, u32 inslot, + u32 outslot, u16 secretlen, u8 *keymod, + u16 keymodlen) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + int retval = 0; + u32 slot_length, dsize, jstat; + u32 __iomem *encapdesc = NULL; + u8 __iomem *lkeymod, *inpslotaddr, *outslotaddr; + dma_addr_t keymod_dma; + + /* Ensure that the full blob will fit in the key slot */ + slot_length = smpriv->slot_get_slot_size(dev, unit, outslot); + if ((secretlen + 48) > slot_length) + goto out; + + /* Get the base addresses of both keystore slots */ + inpslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, inslot); + outslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, outslot); + + /* Build the key modifier */ + lkeymod = kmalloc(keymodlen, GFP_KERNEL | GFP_DMA); + memcpy(lkeymod, keymod, keymodlen); + keymod_dma = dma_map_single(dev, lkeymod, keymodlen, DMA_TO_DEVICE); + dma_sync_single_for_device(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); + + /* Build the encapsulation job descriptor */ + dsize = blob_encap_desc(&encapdesc, keymod_dma, keymodlen, + __pa(inpslotaddr), __pa(outslotaddr), + secretlen, 0); + if (!dsize) { + dev_err(dev, "can't alloc an encap descriptor\n"); + retval = -ENOMEM; + goto out; + } + jstat = sm_key_job(dev, encapdesc); + + dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); + kfree(encapdesc); + +out: + return retval; + +} +EXPORT_SYMBOL(sm_keystore_slot_encapsulate); + +int sm_keystore_slot_decapsulate(struct device *dev, u32 unit, u32 inslot, + u32 outslot, u16 secretlen, u8 *keymod, + u16 keymodlen) +{ + struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); + int retval = 0; + u32 slot_length, dsize, jstat; + u32 __iomem *decapdesc = NULL; + u8 __iomem *lkeymod, *inpslotaddr, *outslotaddr; + dma_addr_t keymod_dma; + + /* Ensure that the decap data will fit in the key slot */ + slot_length = smpriv->slot_get_slot_size(dev, unit, outslot); + if (secretlen > slot_length) + goto out; + + /* Get the base addresses of both keystore slots */ + inpslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, inslot); + outslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, outslot); + + /* Build the key modifier */ + lkeymod = kmalloc(keymodlen, GFP_KERNEL | GFP_DMA); + memcpy(lkeymod, keymod, keymodlen); + keymod_dma = dma_map_single(dev, lkeymod, keymodlen, DMA_TO_DEVICE); + dma_sync_single_for_device(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); + + /* Build the decapsulation job descriptor */ + dsize = blob_decap_desc(&decapdesc, keymod_dma, keymodlen, + __pa(inpslotaddr), __pa(outslotaddr), + secretlen, 0); + if (!dsize) { + dev_err(dev, "can't alloc a decap descriptor\n"); + retval = -ENOMEM; + goto out; + } + jstat = sm_key_job(dev, decapdesc); + + dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); + kfree(decapdesc); + +out: + return retval; + +} +EXPORT_SYMBOL(sm_keystore_slot_decapsulate); + + +/* + * Initialization/shutdown subsystem + * Assumes statically-invoked startup/shutdown from the controller driver + * for the present time, to be reworked when a device tree becomes + * available. This code will not modularize in present form. + * + * Also, simply uses ring 0 for execution at the present + */ + +int caam_sm_startup(struct platform_device *pdev) +{ + struct device *ctrldev, *smdev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_sm *smpriv; + struct caam_drv_private_jr *jrpriv; /* need this for reg page */ + struct platform_device *sm_pdev; + struct sm_page_descriptor *lpagedesc; + u32 page, pgstat, lpagect, detectedpage; + + struct device_node *np; + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + + /* + * Set up the private block for secure memory + * Only one instance is possible + */ + smpriv = kzalloc(sizeof(struct caam_drv_private_sm), GFP_KERNEL); + if (smpriv == NULL) { + dev_err(ctrldev, "can't alloc private mem for secure memory\n"); + return -ENOMEM; + } + smpriv->parentdev = ctrldev; /* copy of parent dev is handy */ + + /* Create the dev */ +#ifdef CONFIG_OF + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm"); + sm_pdev = of_platform_device_create(np, "caam_sm", ctrldev); +#else + sm_pdev = platform_device_register_data(ctrldev, "caam_sm", 0, + smpriv, + sizeof(struct caam_drv_private_sm)); +#endif + if (sm_pdev == NULL) { + kfree(smpriv); + return -EINVAL; + } + smdev = &sm_pdev->dev; + dev_set_drvdata(smdev, smpriv); + ctrlpriv->smdev = smdev; + + /* + * Collect configuration limit data for reference + * This batch comes from the partition data/vid registers in perfmon + */ + smpriv->max_pages = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart) + & SMPART_MAX_NUMPG_MASK) >> + SMPART_MAX_NUMPG_SHIFT) + 1; + smpriv->top_partition = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart) + & SMPART_MAX_PNUM_MASK) >> + SMPART_MAX_PNUM_SHIFT) + 1; + smpriv->top_page = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart) + & SMPART_MAX_PG_MASK) >> SMPART_MAX_PG_SHIFT) + 1; + smpriv->page_size = 1024 << ((rd_reg32(&ctrlpriv->ctrl->perfmon.smvid) + & SMVID_PG_SIZE_MASK) >> SMVID_PG_SIZE_SHIFT); + smpriv->slot_size = 1 << CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE; + +#ifdef SM_DEBUG + dev_info(smdev, "max pages = %d, top partition = %d\n", + smpriv->max_pages, smpriv->top_partition); + dev_info(smdev, "top page = %d, page size = %d (total = %d)\n", + smpriv->top_page, smpriv->page_size, + smpriv->top_page * smpriv->page_size); + dev_info(smdev, "selected slot size = %d\n", smpriv->slot_size); +#endif + + /* + * Now probe for partitions/pages to which we have access. Note that + * these have likely been set up by a bootloader or platform + * provisioning application, so we have to assume that we "inherit" + * a configuration and work within the constraints of what it might be. + * + * Assume use of the zeroth ring in the present iteration (until + * we can divorce the controller and ring drivers, and then assign + * an SM instance to any ring instance). + */ + smpriv->smringdev = ctrlpriv->jrdev[0]; + jrpriv = dev_get_drvdata(smpriv->smringdev); + lpagect = 0; + lpagedesc = kzalloc(sizeof(struct sm_page_descriptor) + * smpriv->max_pages, GFP_KERNEL); + if (lpagedesc == NULL) { + kfree(smpriv); + return -ENOMEM; + } + + for (page = 0; page < smpriv->max_pages; page++) { + wr_reg32(&jrpriv->rregs->sm_cmd, + ((page << SMC_PAGE_SHIFT) & SMC_PAGE_MASK) | + (SMC_CMD_PAGE_INQUIRY & SMC_CMD_MASK)); + pgstat = rd_reg32(&jrpriv->rregs->sm_status); + if (((pgstat & SMCS_PGWON_MASK) >> SMCS_PGOWN_SHIFT) + == SMCS_PGOWN_OWNED) { /* our page? */ + lpagedesc[page].phys_pagenum = + (pgstat & SMCS_PAGE_MASK) >> SMCS_PAGE_SHIFT; + lpagedesc[page].own_part = + (pgstat & SMCS_PART_SHIFT) >> SMCS_PART_MASK; + lpagedesc[page].pg_base = ctrlpriv->sm_base + + ((smpriv->page_size * page) / sizeof(u32)); + lpagect++; +#ifdef SM_DEBUG + dev_info(smdev, + "physical page %d, owning partition = %d\n", + lpagedesc[page].phys_pagenum, + lpagedesc[page].own_part); +#endif + } + } + + smpriv->pagedesc = kzalloc(sizeof(struct sm_page_descriptor) * lpagect, + GFP_KERNEL); + if (smpriv->pagedesc == NULL) { + kfree(lpagedesc); + kfree(smpriv); + return -ENOMEM; + } + smpriv->localpages = lpagect; + + detectedpage = 0; + for (page = 0; page < smpriv->max_pages; page++) { + if (lpagedesc[page].pg_base != NULL) { /* e.g. live entry */ + memcpy(&smpriv->pagedesc[detectedpage], + &lpagedesc[page], + sizeof(struct sm_page_descriptor)); +#ifdef SM_DEBUG_CONT + sm_show_page(smdev, &smpriv->pagedesc[detectedpage]); +#endif + detectedpage++; + } + } + + kfree(lpagedesc); + + sm_init_keystore(smdev); + + return 0; +} + +void caam_sm_shutdown(struct platform_device *pdev) +{ + struct device *ctrldev, *smdev; + struct caam_drv_private *priv; + struct caam_drv_private_sm *smpriv; + + ctrldev = &pdev->dev; + priv = dev_get_drvdata(ctrldev); + smdev = priv->smdev; + smpriv = dev_get_drvdata(smdev); + + kfree(smpriv->pagedesc); + kfree(smpriv); +} +EXPORT_SYMBOL(caam_sm_shutdown); +#ifdef CONFIG_OF +static void __exit caam_sm_exit(void) +{ + struct device_node *dev_node; + struct platform_device *pdev; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return; + } + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return; + + of_node_put(dev_node); + + caam_sm_shutdown(pdev); + + return; +} + +static int __init caam_sm_init(void) +{ + struct device_node *dev_node; + struct platform_device *pdev; + + /* + * Do of_find_compatible_node() then of_find_device_by_node() + * once a functional device tree is available + */ + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return -ENODEV; + } + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return -ENODEV; + + of_node_get(dev_node); + + caam_sm_startup(pdev); + + return 0; +} + +module_init(caam_sm_init); +module_exit(caam_sm_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore"); +MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); +#endif diff -Nur linux-4.1.13.orig/drivers/crypto/caam/sm_test.c linux-4.1.13/drivers/crypto/caam/sm_test.c --- linux-4.1.13.orig/drivers/crypto/caam/sm_test.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/sm_test.c 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,844 @@ +/* + * Secure Memory / Keystore Exemplification Module + * Copyright (C) 2013 Freescale Semiconductor, Inc. All Rights Reserved + * + * Serves as a functional example, and as a self-contained unit test for + * the functionality contained in sm_store.c. + * + * The example function, caam_sm_example_init(), runs a thread that: + * + * - initializes a set of fixed keys + * - stores one copy in clear buffers + * - stores them again in secure memory + * - extracts stored keys back out for use + * - intializes 3 data buffers for a test: + * (1) containing cleartext + * (2) to hold ciphertext encrypted with an extracted black key + * (3) to hold extracted cleartext decrypted with an equivalent clear key + * + * The function then builds simple job descriptors that reference the key + * material and buffers as initialized, and executes an encryption job + * with a black key, and a decryption job using a the same key held in the + * clear. The output of the decryption job is compared to the original + * cleartext; if they don't compare correctly, one can assume a key problem + * exists, where the function will exit with an error. + * + * This module can use a substantial amount of refactoring, which may occur + * after the API gets some mileage. Furthermore, expect this module to + * eventually disappear once the API is integrated into "real" software. + */ + +#include "compat.h" +#include "intern.h" +#include "desc.h" +#include "error.h" +#include "jr.h" +#include "sm.h" + +static u8 skeymod[] = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 +}; +static u8 symkey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f +}; + +static u8 symdata[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x0f, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static int mk_job_desc(u32 *desc, dma_addr_t key, u16 keysz, dma_addr_t indata, + dma_addr_t outdata, u16 sz, u32 cipherdir, u32 keymode) +{ + desc[1] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK) | keymode; + desc[2] = (u32)key; + desc[3] = CMD_OPERATION | OP_TYPE_CLASS1_ALG | OP_ALG_AAI_ECB | + cipherdir; + desc[4] = CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1 | sz; + desc[5] = (u32)indata; + desc[6] = CMD_FIFO_STORE | FIFOST_TYPE_MESSAGE_DATA | sz; + desc[7] = (u32)outdata; + + desc[0] = CMD_DESC_HDR | HDR_ONE | (8 & HDR_DESCLEN_MASK); + return 8 * sizeof(u32); +} + +struct exec_test_result { + int error; + struct completion completion; +}; + +void exec_test_done(struct device *dev, u32 *desc, u32 err, void *context) +{ + struct exec_test_result *res = context; + + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + res->error = err; + complete(&res->completion); +} + +static int exec_test_job(struct device *ksdev, u32 *jobdesc) +{ + struct exec_test_result testres; + struct caam_drv_private_sm *kspriv; + int rtn = 0; + + kspriv = dev_get_drvdata(ksdev); + + init_completion(&testres.completion); + + rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, exec_test_done, + &testres); + if (!rtn) { + wait_for_completion_interruptible(&testres.completion); + rtn = testres.error; + } + return rtn; +} + + +int caam_sm_example_init(struct platform_device *pdev) +{ + struct device *ctrldev, *ksdev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_sm *kspriv; + u32 unit, units, jdescsz; + int stat, jstat, rtnval = 0; + u8 __iomem *syminp, *symint, *symout = NULL; + dma_addr_t syminp_dma, symint_dma, symout_dma; + u8 __iomem *black_key_des, *black_key_aes128; + u8 __iomem *black_key_aes256; + dma_addr_t black_key_des_dma, black_key_aes128_dma; + dma_addr_t black_key_aes256_dma; + u8 __iomem *clear_key_des, *clear_key_aes128, *clear_key_aes256; + dma_addr_t clear_key_des_dma, clear_key_aes128_dma; + dma_addr_t clear_key_aes256_dma; + u32 __iomem *jdesc; + u32 keyslot_des, keyslot_aes128, keyslot_aes256 = 0; + + jdesc = NULL; + black_key_des = black_key_aes128 = black_key_aes256 = NULL; + clear_key_des = clear_key_aes128 = clear_key_aes256 = NULL; + + /* We can lose this cruft once we can get a pdev by name */ + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + ksdev = ctrlpriv->smdev; + kspriv = dev_get_drvdata(ksdev); + if (kspriv == NULL) + return -ENODEV; + + /* Now that we have the dev for the single SM instance, connect */ +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test_init() running\n"); +#endif + /* Probe to see what keystores are available to us */ + units = sm_detect_keystore_units(ksdev); + if (!units) + dev_err(ksdev, "caam_sm_test: no keystore units available\n"); + + /* + * MX6 bootloader stores some stuff in unit 0, so let's + * use 1 or above + */ + if (units < 2) { + dev_err(ksdev, "caam_sm_test: insufficient keystore units\n"); + return -ENODEV; + } + unit = 1; + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: %d keystore units available\n", units); +#endif + + /* Initialize/Establish Keystore */ + sm_establish_keystore(ksdev, unit); /* Initalize store in #1 */ + + /* + * Top of main test thread + */ + + /* Allocate test data blocks (input, intermediate, output) */ + syminp = kmalloc(256, GFP_KERNEL | GFP_DMA); + symint = kmalloc(256, GFP_KERNEL | GFP_DMA); + symout = kmalloc(256, GFP_KERNEL | GFP_DMA); + if ((syminp == NULL) || (symint == NULL) || (symout == NULL)) { + rtnval = -ENOMEM; + dev_err(ksdev, "caam_sm_test: can't get test data buffers\n"); + goto freemem; + } + + /* Allocate storage for 3 black keys: encapsulated 8, 16, 32 */ + black_key_des = kmalloc(16, GFP_KERNEL | GFP_DMA); /* padded to 16... */ + black_key_aes128 = kmalloc(16, GFP_KERNEL | GFP_DMA); + black_key_aes256 = kmalloc(16, GFP_KERNEL | GFP_DMA); + if ((black_key_des == NULL) || (black_key_aes128 == NULL) || + (black_key_aes256 == NULL)) { + rtnval = -ENOMEM; + dev_err(ksdev, "caam_sm_test: can't black key buffers\n"); + goto freemem; + } + + clear_key_des = kmalloc(8, GFP_KERNEL | GFP_DMA); + clear_key_aes128 = kmalloc(16, GFP_KERNEL | GFP_DMA); + clear_key_aes256 = kmalloc(32, GFP_KERNEL | GFP_DMA); + if ((clear_key_des == NULL) || (clear_key_aes128 == NULL) || + (clear_key_aes256 == NULL)) { + rtnval = -ENOMEM; + dev_err(ksdev, "caam_sm_test: can't get clear key buffers\n"); + goto freemem; + } + + /* Allocate storage for job descriptor */ + jdesc = kmalloc(8 * sizeof(u32), GFP_KERNEL | GFP_DMA); + if (jdesc == NULL) { + rtnval = -ENOMEM; + dev_err(ksdev, "caam_sm_test: can't get descriptor buffers\n"); + goto freemem; + } + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: all buffers allocated\n"); +#endif + + /* Load up input data block, clear outputs */ + memcpy(syminp, symdata, 256); + memset(symint, 0, 256); + memset(symout, 0, 256); +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + syminp[0], syminp[1], syminp[2], syminp[3], + syminp[4], syminp[5], syminp[6], syminp[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[0], symint[1], symint[2], symint[3], + symint[4], symint[5], symint[6], symint[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symout[0], symout[1], symout[2], symout[3], + symout[4], symout[5], symout[6], symout[7]); + + dev_info(ksdev, "caam_sm_test: data buffers initialized\n"); +#endif + + /* Load up clear keys */ + memcpy(clear_key_des, symkey, 8); + memcpy(clear_key_aes128, symkey, 16); + memcpy(clear_key_aes256, symkey, 32); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: all clear keys loaded\n"); +#endif + + /* + * Place clear keys in keystore. + * All the interesting stuff happens here. + */ + /* 8 bit DES key */ + stat = sm_keystore_slot_alloc(ksdev, unit, 8, &keyslot_des); + if (stat) + goto freemem; +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: 8 byte key slot in %d\n", keyslot_des); +#endif + stat = sm_keystore_slot_load(ksdev, unit, keyslot_des, clear_key_des, + 8); + if (stat) { +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: can't load 8 byte key in %d\n", + keyslot_des); +#endif + sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); + goto freemem; + } + + /* 16 bit AES key */ + stat = sm_keystore_slot_alloc(ksdev, unit, 16, &keyslot_aes128); + if (stat) { + sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); + goto freemem; + } +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: 16 byte key slot in %d\n", + keyslot_aes128); +#endif + stat = sm_keystore_slot_load(ksdev, unit, keyslot_aes128, + clear_key_aes128, 16); + if (stat) { +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: can't load 16 byte key in %d\n", + keyslot_aes128); +#endif + sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); + sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); + goto freemem; + } + + /* 32 bit AES key */ + stat = sm_keystore_slot_alloc(ksdev, unit, 32, &keyslot_aes256); + if (stat) { + sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); + sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); + goto freemem; + } +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: 32 byte key slot in %d\n", + keyslot_aes256); +#endif + stat = sm_keystore_slot_load(ksdev, unit, keyslot_aes256, + clear_key_aes256, 32); + if (stat) { +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: can't load 32 byte key in %d\n", + keyslot_aes128); +#endif + sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes256); + sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); + sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); + goto freemem; + } + + /* Encapsulate all keys as SM blobs */ + stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_des, + keyslot_des, 8, skeymod, 8); + if (stat) { + dev_info(ksdev, "caam_sm_test: can't encapsulate DES key\n"); + goto freekeys; + } + + stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_aes128, + keyslot_aes128, 16, skeymod, 8); + if (stat) { + dev_info(ksdev, "caam_sm_test: can't encapsulate AES128 key\n"); + goto freekeys; + } + + stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_aes256, + keyslot_aes256, 32, skeymod, 8); + if (stat) { + dev_info(ksdev, "caam_sm_test: can't encapsulate AES256 key\n"); + goto freekeys; + } + + /* Now decapsulate as black key blobs */ + stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_des, + keyslot_des, 8, skeymod, 8); + if (stat) { + dev_info(ksdev, "caam_sm_test: can't decapsulate DES key\n"); + goto freekeys; + } + + stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_aes128, + keyslot_aes128, 16, skeymod, 8); + if (stat) { + dev_info(ksdev, "caam_sm_test: can't decapsulate AES128 key\n"); + goto freekeys; + } + + stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_aes256, + keyslot_aes256, 32, skeymod, 8); + if (stat) { + dev_info(ksdev, "caam_sm_test: can't decapsulate AES128 key\n"); + goto freekeys; + } + + /* Extract 8/16/32 byte black keys */ + sm_keystore_slot_read(ksdev, unit, keyslot_des, 8, black_key_des); + sm_keystore_slot_read(ksdev, unit, keyslot_aes128, 16, + black_key_aes128); + sm_keystore_slot_read(ksdev, unit, keyslot_aes256, 32, + black_key_aes256); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: all black keys extracted\n"); +#endif + + /* DES encrypt using 8 byte black key */ + black_key_des_dma = dma_map_single(ksdev, black_key_des, 8, + DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, black_key_des_dma, 8, DMA_TO_DEVICE); + syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE); + symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE); + + jdescsz = mk_job_desc(jdesc, black_key_des_dma, 8, syminp_dma, + symint_dma, 256, + OP_ALG_ENCRYPT | OP_ALG_ALGSEL_DES, 0); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "jobdesc:\n"); + dev_info(ksdev, "0x%08x\n", jdesc[0]); + dev_info(ksdev, "0x%08x\n", jdesc[1]); + dev_info(ksdev, "0x%08x\n", jdesc[2]); + dev_info(ksdev, "0x%08x\n", jdesc[3]); + dev_info(ksdev, "0x%08x\n", jdesc[4]); + dev_info(ksdev, "0x%08x\n", jdesc[5]); + dev_info(ksdev, "0x%08x\n", jdesc[6]); + dev_info(ksdev, "0x%08x\n", jdesc[7]); +#endif + + jstat = exec_test_job(ksdev, jdesc); + + dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE); + dma_unmap_single(ksdev, black_key_des_dma, 8, DMA_TO_DEVICE); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "input block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + syminp[0], syminp[1], syminp[2], syminp[3], + syminp[4], syminp[5], syminp[6], syminp[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + syminp[8], syminp[9], syminp[10], syminp[11], + syminp[12], syminp[13], syminp[14], syminp[15]); + dev_info(ksdev, "intermediate block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[0], symint[1], symint[2], symint[3], + symint[4], symint[5], symint[6], symint[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[8], symint[9], symint[10], symint[11], + symint[12], symint[13], symint[14], symint[15]); + dev_info(ksdev, "caam_sm_test: encrypt cycle with 8 byte key\n"); +#endif + + /* DES decrypt using 8 byte clear key */ + clear_key_des_dma = dma_map_single(ksdev, clear_key_des, 8, + DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, clear_key_des_dma, 8, DMA_TO_DEVICE); + symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE); + symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE); + + jdescsz = mk_job_desc(jdesc, clear_key_des_dma, 8, symint_dma, + symout_dma, 256, + OP_ALG_DECRYPT | OP_ALG_ALGSEL_DES, 0); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "jobdesc:\n"); + dev_info(ksdev, "0x%08x\n", jdesc[0]); + dev_info(ksdev, "0x%08x\n", jdesc[1]); + dev_info(ksdev, "0x%08x\n", jdesc[2]); + dev_info(ksdev, "0x%08x\n", jdesc[3]); + dev_info(ksdev, "0x%08x\n", jdesc[4]); + dev_info(ksdev, "0x%08x\n", jdesc[5]); + dev_info(ksdev, "0x%08x\n", jdesc[6]); + dev_info(ksdev, "0x%08x\n", jdesc[7]); +#endif + + jstat = exec_test_job(ksdev, jdesc); + + dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE); + dma_unmap_single(ksdev, clear_key_des_dma, 8, DMA_TO_DEVICE); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "intermediate block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[0], symint[1], symint[2], symint[3], + symint[4], symint[5], symint[6], symint[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[8], symint[9], symint[10], symint[11], + symint[12], symint[13], symint[14], symint[15]); + dev_info(ksdev, "decrypted block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symout[0], symout[1], symout[2], symout[3], + symout[4], symout[5], symout[6], symout[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symout[8], symout[9], symout[10], symout[11], + symout[12], symout[13], symout[14], symout[15]); + dev_info(ksdev, "caam_sm_test: decrypt cycle with 8 byte key\n"); +#endif + + /* Check result */ + if (memcmp(symout, syminp, 256)) { + dev_info(ksdev, "caam_sm_test: 8-byte key test mismatch\n"); + rtnval = -1; + goto freekeys; + } else + dev_info(ksdev, "caam_sm_test: 8-byte key test match OK\n"); + + /* AES-128 encrypt using 16 byte black key */ + black_key_aes128_dma = dma_map_single(ksdev, black_key_aes128, 16, + DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, black_key_aes128_dma, 16, + DMA_TO_DEVICE); + syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE); + symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE); + + jdescsz = mk_job_desc(jdesc, black_key_aes128_dma, 16, syminp_dma, + symint_dma, 256, + OP_ALG_ENCRYPT | OP_ALG_ALGSEL_AES, 0); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "jobdesc:\n"); + dev_info(ksdev, "0x%08x\n", jdesc[0]); + dev_info(ksdev, "0x%08x\n", jdesc[1]); + dev_info(ksdev, "0x%08x\n", jdesc[2]); + dev_info(ksdev, "0x%08x\n", jdesc[3]); + dev_info(ksdev, "0x%08x\n", jdesc[4]); + dev_info(ksdev, "0x%08x\n", jdesc[5]); + dev_info(ksdev, "0x%08x\n", jdesc[6]); + dev_info(ksdev, "0x%08x\n", jdesc[7]); +#endif + + jstat = exec_test_job(ksdev, jdesc); + + dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE); + dma_unmap_single(ksdev, black_key_aes128_dma, 16, DMA_TO_DEVICE); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "input block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + syminp[0], syminp[1], syminp[2], syminp[3], + syminp[4], syminp[5], syminp[6], syminp[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + syminp[8], syminp[9], syminp[10], syminp[11], + syminp[12], syminp[13], syminp[14], syminp[15]); + dev_info(ksdev, "intermediate block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[0], symint[1], symint[2], symint[3], + symint[4], symint[5], symint[6], symint[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[8], symint[9], symint[10], symint[11], + symint[12], symint[13], symint[14], symint[15]); + dev_info(ksdev, "caam_sm_test: encrypt cycle with 16 byte key\n"); +#endif + + /* AES-128 decrypt using 16 byte clear key */ + clear_key_aes128_dma = dma_map_single(ksdev, clear_key_aes128, 16, + DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, clear_key_aes128_dma, 16, + DMA_TO_DEVICE); + symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE); + symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE); + + jdescsz = mk_job_desc(jdesc, clear_key_aes128_dma, 16, symint_dma, + symout_dma, 256, + OP_ALG_DECRYPT | OP_ALG_ALGSEL_AES, 0); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "jobdesc:\n"); + dev_info(ksdev, "0x%08x\n", jdesc[0]); + dev_info(ksdev, "0x%08x\n", jdesc[1]); + dev_info(ksdev, "0x%08x\n", jdesc[2]); + dev_info(ksdev, "0x%08x\n", jdesc[3]); + dev_info(ksdev, "0x%08x\n", jdesc[4]); + dev_info(ksdev, "0x%08x\n", jdesc[5]); + dev_info(ksdev, "0x%08x\n", jdesc[6]); + dev_info(ksdev, "0x%08x\n", jdesc[7]); +#endif + jstat = exec_test_job(ksdev, jdesc); + + dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE); + dma_unmap_single(ksdev, clear_key_aes128_dma, 16, DMA_TO_DEVICE); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "intermediate block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[0], symint[1], symint[2], symint[3], + symint[4], symint[5], symint[6], symint[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[8], symint[9], symint[10], symint[11], + symint[12], symint[13], symint[14], symint[15]); + dev_info(ksdev, "decrypted block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symout[0], symout[1], symout[2], symout[3], + symout[4], symout[5], symout[6], symout[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symout[8], symout[9], symout[10], symout[11], + symout[12], symout[13], symout[14], symout[15]); + dev_info(ksdev, "caam_sm_test: decrypt cycle with 16 byte key\n"); +#endif + + /* Check result */ + if (memcmp(symout, syminp, 256)) { + dev_info(ksdev, "caam_sm_test: 16-byte key test mismatch\n"); + rtnval = -1; + goto freekeys; + } else + dev_info(ksdev, "caam_sm_test: 16-byte key test match OK\n"); + + /* AES-256 encrypt using 32 byte black key */ + black_key_aes256_dma = dma_map_single(ksdev, black_key_aes256, 32, + DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, black_key_aes256_dma, 32, + DMA_TO_DEVICE); + syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE); + symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE); + + jdescsz = mk_job_desc(jdesc, black_key_aes256_dma, 32, syminp_dma, + symint_dma, 256, + OP_ALG_ENCRYPT | OP_ALG_ALGSEL_AES, 0); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "jobdesc:\n"); + dev_info(ksdev, "0x%08x\n", jdesc[0]); + dev_info(ksdev, "0x%08x\n", jdesc[1]); + dev_info(ksdev, "0x%08x\n", jdesc[2]); + dev_info(ksdev, "0x%08x\n", jdesc[3]); + dev_info(ksdev, "0x%08x\n", jdesc[4]); + dev_info(ksdev, "0x%08x\n", jdesc[5]); + dev_info(ksdev, "0x%08x\n", jdesc[6]); + dev_info(ksdev, "0x%08x\n", jdesc[7]); +#endif + + jstat = exec_test_job(ksdev, jdesc); + + dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE); + dma_unmap_single(ksdev, black_key_aes256_dma, 32, DMA_TO_DEVICE); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "input block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + syminp[0], syminp[1], syminp[2], syminp[3], + syminp[4], syminp[5], syminp[6], syminp[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + syminp[8], syminp[9], syminp[10], syminp[11], + syminp[12], syminp[13], syminp[14], syminp[15]); + dev_info(ksdev, "intermediate block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[0], symint[1], symint[2], symint[3], + symint[4], symint[5], symint[6], symint[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[8], symint[9], symint[10], symint[11], + symint[12], symint[13], symint[14], symint[15]); + dev_info(ksdev, "caam_sm_test: encrypt cycle with 32 byte key\n"); +#endif + + /* AES-256 decrypt using 32-byte black key */ + clear_key_aes256_dma = dma_map_single(ksdev, clear_key_aes256, 32, + DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, clear_key_aes256_dma, 32, + DMA_TO_DEVICE); + symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE); + dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE); + symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE); + + jdescsz = mk_job_desc(jdesc, clear_key_aes256_dma, 32, symint_dma, + symout_dma, 256, + OP_ALG_DECRYPT | OP_ALG_ALGSEL_AES, 0); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "jobdesc:\n"); + dev_info(ksdev, "0x%08x\n", jdesc[0]); + dev_info(ksdev, "0x%08x\n", jdesc[1]); + dev_info(ksdev, "0x%08x\n", jdesc[2]); + dev_info(ksdev, "0x%08x\n", jdesc[3]); + dev_info(ksdev, "0x%08x\n", jdesc[4]); + dev_info(ksdev, "0x%08x\n", jdesc[5]); + dev_info(ksdev, "0x%08x\n", jdesc[6]); + dev_info(ksdev, "0x%08x\n", jdesc[7]); +#endif + + jstat = exec_test_job(ksdev, jdesc); + + dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE); + dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE); + dma_unmap_single(ksdev, clear_key_aes256_dma, 32, DMA_TO_DEVICE); + +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "intermediate block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[0], symint[1], symint[2], symint[3], + symint[4], symint[5], symint[6], symint[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symint[8], symint[9], symint[10], symint[11], + symint[12], symint[13], symint[14], symint[15]); + dev_info(ksdev, "decrypted block:\n"); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symout[0], symout[1], symout[2], symout[3], + symout[4], symout[5], symout[6], symout[7]); + dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ + "0x%02x 0x%02x 0x%02x 0x%02x\n", + symout[8], symout[9], symout[10], symout[11], + symout[12], symout[13], symout[14], symout[15]); + dev_info(ksdev, "caam_sm_test: decrypt cycle with 32 byte key\n"); +#endif + + /* Check result */ + if (memcmp(symout, syminp, 256)) { + dev_info(ksdev, "caam_sm_test: 32-byte key test mismatch\n"); + rtnval = -1; + goto freekeys; + } else + dev_info(ksdev, "caam_sm_test: 32-byte key test match OK\n"); + + + /* Remove 8/16/32 byte keys from keystore */ +freekeys: + stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); + if (stat) + dev_info(ksdev, "caam_sm_test: can't release slot %d\n", + keyslot_des); + + stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); + if (stat) + dev_info(ksdev, "caam_sm_test: can't release slot %d\n", + keyslot_aes128); + + stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes256); + if (stat) + dev_info(ksdev, "caam_sm_test: can't release slot %d\n", + keyslot_aes256); + + + /* Free resources */ +freemem: +#ifdef SM_TEST_DETAIL + dev_info(ksdev, "caam_sm_test: cleaning up\n"); +#endif + kfree(syminp); + kfree(symint); + kfree(symout); + kfree(clear_key_des); + kfree(clear_key_aes128); + kfree(clear_key_aes256); + kfree(black_key_des); + kfree(black_key_aes128); + kfree(black_key_aes256); + kfree(jdesc); + + /* Disconnect from keystore and leave */ + sm_release_keystore(ksdev, unit); + + return rtnval; +} +EXPORT_SYMBOL(caam_sm_example_init); + +void caam_sm_example_shutdown(void) +{ + /* unused in present version */ + struct device_node *dev_node; + struct platform_device *pdev; + + /* + * Do of_find_compatible_node() then of_find_device_by_node() + * once a functional device tree is available + */ + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return; + } + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return; + + of_node_get(dev_node); + +} + +static int __init caam_sm_test_init(void) +{ + struct device_node *dev_node; + struct platform_device *pdev; + + /* + * Do of_find_compatible_node() then of_find_device_by_node() + * once a functional device tree is available + */ + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return -ENODEV; + } + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return -ENODEV; + + of_node_put(dev_node); + + caam_sm_example_init(pdev); + + return 0; +} + + +/* Module-based initialization needs to wait for dev tree */ +#ifdef CONFIG_OF +module_init(caam_sm_test_init); +module_exit(caam_sm_example_shutdown); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL CAAM Keystore Usage Example"); +MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); +#endif diff -Nur linux-4.1.13.orig/drivers/crypto/caam/snvsregs.h linux-4.1.13/drivers/crypto/caam/snvsregs.h --- linux-4.1.13.orig/drivers/crypto/caam/snvsregs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/crypto/caam/snvsregs.h 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,237 @@ +/* + * SNVS hardware register-level view + * + * Copyright (C) 2012-2014 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-4.1.13.orig/drivers/dma/imx-sdma.c linux-4.1.13/drivers/dma/imx-sdma.c --- linux-4.1.13.orig/drivers/dma/imx-sdma.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/dma/imx-sdma.c 2015-11-30 17:56:13.552139590 +0100 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -232,6 +233,14 @@ struct sdma_engine; +enum sdma_mode { + SDMA_MODE_INVALID = 0, + SDMA_MODE_LOOP, + SDMA_MODE_NORMAL, + SDMA_MODE_P2P, + SDMA_MODE_NO_BD, +}; + /** * struct sdma_channel - housekeeping for a SDMA channel * @@ -244,6 +253,7 @@ * @word_size peripheral access size * @buf_tail ID of the buffer that was processed * @num_bd max NUM_BD. number of descriptors currently handling + * @bd_iram flag indicating the memory location of buffer descriptor */ struct sdma_channel { struct sdma_engine *sdma; @@ -258,12 +268,16 @@ unsigned int period_len; struct sdma_buffer_descriptor *bd; dma_addr_t bd_phys; + bool bd_iram; unsigned int pc_from_device, pc_to_device; - unsigned long flags; - dma_addr_t per_address; + unsigned int device_to_device; + unsigned int other_script; + enum sdma_mode mode; + dma_addr_t per_address, per_address2; unsigned long event_mask[2]; unsigned long watermark_level; u32 shp_addr, per_addr; + u32 data_addr1, data_addr2; struct dma_chan chan; spinlock_t lock; struct dma_async_tx_descriptor desc; @@ -271,11 +285,8 @@ 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) - #define MAX_DMA_CHANNELS 32 #define MXC_SDMA_DEFAULT_PRIORITY 1 #define MXC_SDMA_MIN_PRIORITY 1 @@ -327,6 +338,7 @@ spinlock_t channel_0_lock; u32 script_number; struct sdma_script_start_addrs *script_addrs; + struct gen_pool *iram_pool; const struct sdma_driver_data *drvdata; }; @@ -546,12 +558,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); @@ -568,7 +582,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; } @@ -654,14 +671,31 @@ sdmac->desc.callback(sdmac->desc.callback_param); } +static void sdma_handle_other_intr(struct sdma_channel *sdmac) +{ + if (sdmac->desc.callback) + sdmac->desc.callback(sdmac->desc.callback_param); +} + static void sdma_tasklet(unsigned long data) { struct sdma_channel *sdmac = (struct sdma_channel *) data; + struct sdma_engine *sdma = sdmac->sdma; - if (sdmac->flags & IMX_DMA_SG_LOOP) + switch (sdmac->mode) { + case SDMA_MODE_LOOP: sdma_handle_channel_loop(sdmac); - else + break; + case SDMA_MODE_NORMAL: mxc_sdma_handle_channel_normal(sdmac); + break; + case SDMA_MODE_NO_BD: + sdma_handle_other_intr(sdmac); + break; + default: + dev_err(sdma->dev, "invalid SDMA MODE!\n"); + break; + } } static irqreturn_t sdma_int_handler(int irq, void *dev_id) @@ -678,7 +712,7 @@ int channel = fls(stat) - 1; struct sdma_channel *sdmac = &sdma->channel[channel]; - if (sdmac->flags & IMX_DMA_SG_LOOP) + if (sdmac->mode & SDMA_MODE_LOOP) sdma_update_channel_loop(sdmac); tasklet_schedule(&sdmac->tasklet); @@ -702,9 +736,12 @@ * two peripherals or memory-to-memory transfers */ int per_2_per = 0, emi_2_emi = 0; + int other = 0; sdmac->pc_from_device = 0; sdmac->pc_to_device = 0; + sdmac->device_to_device = 0; + sdmac->other_script = 0; switch (peripheral_type) { case IMX_DMATYPE_MEMORY: @@ -733,7 +770,6 @@ case IMX_DMATYPE_CSPI: 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; @@ -751,11 +787,6 @@ emi_2_per = sdma->script_addrs->mcu_2_shp_addr; break; case IMX_DMATYPE_ASRC: - per_2_emi = sdma->script_addrs->asrc_2_mcu_addr; - emi_2_per = sdma->script_addrs->asrc_2_mcu_addr; - per_2_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; @@ -774,12 +805,17 @@ case IMX_DMATYPE_IPU_MEMORY: emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; break; + case IMX_DMATYPE_HDMI: + other = sdma->script_addrs->hdmi_dma_addr; + break; default: break; } sdmac->pc_from_device = per_2_emi; sdmac->pc_to_device = emi_2_per; + sdmac->device_to_device = per_2_per; + sdmac->other_script = other; } static int sdma_load_context(struct sdma_channel *sdmac) @@ -792,11 +828,14 @@ int ret; unsigned long flags; - if (sdmac->direction == DMA_DEV_TO_MEM) { + if (sdmac->direction == DMA_DEV_TO_MEM) load_address = sdmac->pc_from_device; - } else { + else if (sdmac->direction == DMA_DEV_TO_DEV) + load_address = sdmac->device_to_device; + else if (sdmac->direction == DMA_MEM_TO_DEV) load_address = sdmac->pc_to_device; - } + else + load_address = sdmac->other_script; if (load_address < 0) return load_address; @@ -816,11 +855,16 @@ /* Send by context the event mask,base address for peripheral * and watermark level */ - context->gReg[0] = sdmac->event_mask[1]; - context->gReg[1] = sdmac->event_mask[0]; - context->gReg[2] = sdmac->per_addr; - context->gReg[6] = sdmac->shp_addr; - context->gReg[7] = sdmac->watermark_level; + if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) { + context->gReg[4] = sdmac->data_addr1; + context->gReg[6] = sdmac->data_addr2; + } else { + context->gReg[0] = sdmac->event_mask[1]; + context->gReg[1] = sdmac->event_mask[0]; + context->gReg[2] = sdmac->per_addr; + context->gReg[6] = sdmac->shp_addr; + context->gReg[7] = sdmac->watermark_level; + } bd0->mode.command = C0_SETDM; bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; @@ -854,6 +898,7 @@ static int sdma_config_channel(struct dma_chan *chan) { struct sdma_channel *sdmac = to_sdma_chan(chan); + struct imx_dma_data *data = sdmac->chan.private; int ret; sdma_disable_channel(chan); @@ -862,12 +907,19 @@ sdmac->event_mask[1] = 0; sdmac->shp_addr = 0; sdmac->per_addr = 0; + sdmac->data_addr1 = 0; + sdmac->data_addr2 = 0; - if (sdmac->event_id0) { + if (sdmac->event_id0 >= 0) { if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events) return -EINVAL; sdma_event_enable(sdmac, sdmac->event_id0); } + if (sdmac->event_id1) { + if (sdmac->event_id1 >= sdmac->sdma->drvdata->num_events) + return -EINVAL; + sdma_event_enable(sdmac, sdmac->event_id1); + } switch (sdmac->peripheral_type) { case IMX_DMATYPE_DSP: @@ -887,19 +939,75 @@ (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { /* Handle multiple event channels differently */ if (sdmac->event_id1) { - sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32); - if (sdmac->event_id1 > 31) - __set_bit(31, &sdmac->watermark_level); - sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32); - if (sdmac->event_id0 > 31) - __set_bit(30, &sdmac->watermark_level); + if (sdmac->event_id0 > 31) { + sdmac->event_mask[0] |= 0; + __set_bit(28, &sdmac->watermark_level); + sdmac->event_mask[1] |= + BIT(sdmac->event_id0 % 32); + } else { + sdmac->event_mask[1] |= 0; + sdmac->event_mask[0] |= + BIT(sdmac->event_id0 % 32); + } + if (sdmac->event_id1 > 31) { + sdmac->event_mask[0] |= 0; + __set_bit(29, &sdmac->watermark_level); + sdmac->event_mask[1] |= + BIT(sdmac->event_id1 % 32); + } else { + sdmac->event_mask[1] |= 0; + sdmac->event_mask[0] |= + BIT(sdmac->event_id1 % 32); + } + /* BIT 11: + * 1 : Source on SPBA + * 0 : Source on AIPS + */ + __set_bit(11, &sdmac->watermark_level); + /* BIT 12: + * 1 : Destination on SPBA + * 0 : Destination on AIPS + */ + __set_bit(12, &sdmac->watermark_level); + __set_bit(31, &sdmac->watermark_level); + /* BIT 31: + * 1 : Amount of samples to be transferred is + * unknown and script will keep on transferring + * samples as long as both events are detected + * and script must be manually stopped by the + * application. + * 0 : The amount of samples to be is equal to + * the count field of mode word + * */ + __set_bit(25, &sdmac->watermark_level); + __clear_bit(24, &sdmac->watermark_level); } else { - __set_bit(sdmac->event_id0, sdmac->event_mask); + if (sdmac->event_id0 > 31) { + sdmac->event_mask[0] = 0; + sdmac->event_mask[1] |= + BIT(sdmac->event_id0 % 32); + } else { + sdmac->event_mask[0] |= + BIT(sdmac->event_id0 % 32); + sdmac->event_mask[1] = 0; + } } /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; /* Address */ - sdmac->shp_addr = sdmac->per_address; + if (sdmac->direction == DMA_DEV_TO_DEV) { + sdmac->shp_addr = sdmac->per_address2; + sdmac->per_addr = sdmac->per_address; + } else if (sdmac->direction == DMA_TRANS_NONE) { + if (sdmac->peripheral_type != IMX_DMATYPE_HDMI || + !data->data_addr1 || !data->data_addr2) + return -EINVAL; + sdmac->data_addr1 = *(u32 *)data->data_addr1; + sdmac->data_addr2 = *(u32 *)data->data_addr2; + sdmac->watermark_level = 0; + } else { + sdmac->shp_addr = sdmac->per_address; + } } else { sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ } @@ -931,13 +1039,19 @@ int channel = sdmac->channel; int ret = -EBUSY; - sdmac->bd = dma_zalloc_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); + sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys; sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; @@ -987,6 +1101,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); @@ -1004,6 +1119,9 @@ /* txd.flags will be overwritten in prep funcs */ sdmac->desc.flags = DMA_CTRL_ACK; + /* Set SDMA channel mode to unvalid to avoid misconfig */ + sdmac->mode = SDMA_MODE_INVALID; + return 0; } @@ -1014,7 +1132,7 @@ sdma_disable_channel(chan); - if (sdmac->event_id0) + if (sdmac->event_id0 >= 0) sdma_event_disable(sdmac, sdmac->event_id0); if (sdmac->event_id1) sdma_event_disable(sdmac, sdmac->event_id1); @@ -1024,7 +1142,10 @@ sdma_set_channel_priority(sdmac, 0); - dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); + if (sdmac->bd_iram) + gen_pool_free(sdma->iram_pool, (unsigned long)sdmac->bd, PAGE_SIZE); + else + dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); clk_disable(sdma->clk_ipg); clk_disable(sdma->clk_ahb); @@ -1045,7 +1166,7 @@ return NULL; sdmac->status = DMA_IN_PROGRESS; - sdmac->flags = 0; + sdmac->mode = SDMA_MODE_NORMAL; sdmac->buf_tail = 0; @@ -1134,13 +1255,13 @@ 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, - unsigned long flags) + unsigned long flags, void *context) { 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); @@ -1152,12 +1273,33 @@ sdmac->buf_tail = 0; sdmac->period_len = period_len; - sdmac->flags |= IMX_DMA_SG_LOOP; sdmac->direction = direction; + + switch (sdmac->direction) { + case DMA_DEV_TO_DEV: + sdmac->mode = SDMA_MODE_P2P; + break; + case DMA_TRANS_NONE: + sdmac->mode = SDMA_MODE_NO_BD; + break; + case DMA_MEM_TO_DEV: + case DMA_DEV_TO_MEM: + sdmac->mode = SDMA_MODE_LOOP; + break; + default: + dev_err(sdma->dev, "invalid SDMA direction %d\n", direction); + return NULL; + } + ret = sdma_load_context(sdmac); if (ret) goto err_out; + if (period_len) + num_periods = buf_len / period_len; + else + return &sdmac->desc; + if (num_periods > NUM_BD) { dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", channel, num_periods, NUM_BD); @@ -1216,7 +1358,16 @@ { struct sdma_channel *sdmac = to_sdma_chan(chan); - if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { + if (dmaengine_cfg->direction == DMA_DEV_TO_DEV) { + sdmac->per_address = dmaengine_cfg->src_addr; + sdmac->per_address2 = dmaengine_cfg->dst_addr; + sdmac->watermark_level = 0; + sdmac->watermark_level |= + dmaengine_cfg->src_maxburst; + sdmac->watermark_level |= + dmaengine_cfg->dst_maxburst << 16; + sdmac->word_size = dmaengine_cfg->dst_addr_width; + } else if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { sdmac->per_address = dmaengine_cfg->src_addr; sdmac->watermark_level = dmaengine_cfg->src_maxburst * dmaengine_cfg->src_addr_width; @@ -1238,7 +1389,7 @@ struct sdma_channel *sdmac = to_sdma_chan(chan); u32 residue; - if (sdmac->flags & IMX_DMA_SG_LOOP) + if (sdmac->mode & SDMA_MODE_LOOP) residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; else residue = sdmac->chn_count - sdmac->chn_real_count; @@ -1286,8 +1437,7 @@ unsigned short *ram_code; if (!fw) { - dev_info(sdma->dev, "external firmware not found, using ROM firmware\n"); - /* In this case we just use the ROM firmware. */ + dev_err(sdma->dev, "firmware not found\n"); return; } @@ -1302,7 +1452,10 @@ goto err_firmware; switch (header->version_major) { case 1: - sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + if (header->version_minor > 0) + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; + else + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; break; case 2: sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; @@ -1337,7 +1490,7 @@ release_firmware(fw); } -static int sdma_get_firmware(struct sdma_engine *sdma, +static int __init sdma_get_firmware(struct sdma_engine *sdma, const char *fw_name) { int ret; @@ -1349,9 +1502,9 @@ return ret; } -static int sdma_init(struct sdma_engine *sdma) +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); @@ -1360,14 +1513,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 + @@ -1419,14 +1575,12 @@ 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; - sdmac->data = *data; - chan->private = &sdmac->data; + chan->private = data; return true; } @@ -1444,11 +1598,12 @@ data.dma_request = dma_spec->args[0]; data.peripheral_type = dma_spec->args[1]; data.priority = dma_spec->args[2]; + data.dma_request2 = 0; return dma_request_channel(mask, sdma_filter_fn, &data); } -static int sdma_probe(struct platform_device *pdev) +static int __init sdma_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(sdma_dt_ids, &pdev->dev); @@ -1547,6 +1702,11 @@ &sdma->dma_device.channels); } + if (np) + sdma->iram_pool = of_get_named_gen_pool(np, "iram", 0); + if (!sdma->iram_pool) + dev_warn(&pdev->dev, "no iram assigned, using external mem\n"); + ret = sdma_init(sdma); if (ret) goto err_init; @@ -1583,7 +1743,7 @@ sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources; 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_cyclic = (void*)sdma_prep_dma_cyclic; sdma->dma_device.device_config = sdma_config; sdma->dma_device.device_terminate_all = sdma_disable_channel; sdma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); @@ -1594,8 +1754,6 @@ sdma->dma_device.dev->dma_parms = &sdma->dma_parms; dma_set_max_seg_size(sdma->dma_device.dev, 65535); - platform_set_drvdata(pdev, sdma); - ret = dma_async_device_register(&sdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); @@ -1647,10 +1805,13 @@ }, .id_table = sdma_devtypes, .remove = sdma_remove, - .probe = sdma_probe, }; -module_platform_driver(sdma_driver); +static int __init sdma_module_init(void) +{ + return platform_driver_probe(&sdma_driver, sdma_probe); +} +module_init(sdma_module_init); MODULE_AUTHOR("Sascha Hauer, Pengutronix "); MODULE_DESCRIPTION("i.MX SDMA driver"); diff -Nur linux-4.1.13.orig/drivers/gpu/drm/Kconfig linux-4.1.13/drivers/gpu/drm/Kconfig --- linux-4.1.13.orig/drivers/gpu/drm/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/gpu/drm/Kconfig 2015-11-30 17:56:13.552139590 +0100 @@ -217,3 +217,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig" source "drivers/gpu/drm/imx/Kconfig" + +source "drivers/gpu/drm/vivante/Kconfig" diff -Nur linux-4.1.13.orig/drivers/gpu/drm/Makefile linux-4.1.13/drivers/gpu/drm/Makefile --- linux-4.1.13.orig/drivers/gpu/drm/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/gpu/drm/Makefile 2015-11-30 17:56:13.552139590 +0100 @@ -67,6 +67,7 @@ obj-$(CONFIG_DRM_TEGRA) += tegra/ obj-$(CONFIG_DRM_STI) += sti/ obj-$(CONFIG_DRM_IMX) += imx/ +obj-$(CONFIG_DRM_VIVANTE) += vivante/ obj-y += i2c/ obj-y += panel/ obj-y += bridge/ diff -Nur linux-4.1.13.orig/drivers/gpu/drm/vivante/Kconfig linux-4.1.13/drivers/gpu/drm/vivante/Kconfig --- linux-4.1.13.orig/drivers/gpu/drm/vivante/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/drm/vivante/Kconfig 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,6 @@ +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. diff -Nur linux-4.1.13.orig/drivers/gpu/drm/vivante/Makefile linux-4.1.13/drivers/gpu/drm/vivante/Makefile --- linux-4.1.13.orig/drivers/gpu/drm/vivante/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/drm/vivante/Makefile 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,29 @@ +############################################################################## +# +# Copyright (C) 2005 - 2013 by Vivante Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the license, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +############################################################################## + + +# +# Makefile for the drm device driver. This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. + +ccflags-y := -Iinclude/drm +vivante-y := vivante_drv.o + +obj-$(CONFIG_DRM_VIVANTE) += vivante.o diff -Nur linux-4.1.13.orig/drivers/gpu/drm/vivante/vivante_drv.c linux-4.1.13/drivers/gpu/drm/vivante/vivante_drv.c --- linux-4.1.13.orig/drivers/gpu/drm/vivante/vivante_drv.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/drm/vivante/vivante_drv.c 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,112 @@ +/**************************************************************************** +* +* 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_legacy_mmap, + .poll = drm_poll, + .llseek = noop_llseek, +}; + +static struct drm_driver driver = { +// .driver_features = DRIVER_RENDER, + .fops = &viv_driver_fops, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) + .set_busid = drm_platform_set_busid, +#endif + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; + +static int __init vivante_init(void) +{ + int retcode; + + pplatformdev = platform_device_register_simple(platformdevicename, + -1, NULL, 0); + if (pplatformdev == NULL) + printk(KERN_ERR"Platform device is null\n"); + + retcode = drm_platform_init(&driver, pplatformdev); + + return retcode; +} + +static void __exit vivante_exit(void) +{ + if (pplatformdev) { + platform_device_unregister(pplatformdev); + pplatformdev = NULL; + } +} + +module_init(vivante_init); +module_exit(vivante_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); diff -Nur linux-4.1.13.orig/drivers/gpu/drm/vivante/vivante_drv.h linux-4.1.13/drivers/gpu/drm/vivante/vivante_drv.h --- linux-4.1.13.orig/drivers/gpu/drm/vivante/vivante_drv.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/drm/vivante/vivante_drv.h 2015-11-30 17:56:13.552139590 +0100 @@ -0,0 +1,69 @@ +/**************************************************************************** +* +* 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: + */ + +#include +#include + +#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-4.1.13.orig/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h linux-4.1.13/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h --- linux-4.1.13.orig/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/allocator/default/gc_hal_kernel_allocator_array.h 2015-11-30 17:56:13.556139323 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h linux-4.1.13/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h --- linux-4.1.13.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_array.h 2015-11-30 17:56:13.556139323 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c linux-4.1.13/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c --- linux-4.1.13.orig/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/allocator/freescale/gc_hal_kernel_allocator_cma.c 2015-11-30 17:56:13.556139323 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.c linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_context.c --- linux-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_context.c 2015-11-30 17:56:13.556139323 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.h linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_context.h --- linux-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_context.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_context.h 2015-11-30 17:56:13.556139323 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c --- linux-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.c 2015-11-30 17:56:13.560139057 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h --- linux-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_hardware.h 2015-11-30 17:56:13.560139057 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c --- linux-4.1.13.orig/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/arch/gc_hal_kernel_recorder.c 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c --- linux-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.c 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h --- linux-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_command_vg.h 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c --- linux-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.c 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h --- linux-4.1.13.orig/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/archvg/gc_hal_kernel_hardware_vg.h 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/config linux-4.1.13/drivers/gpu/galcore/config --- linux-4.1.13.orig/drivers/gpu/galcore/config 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/config 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_allocator.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_allocator.c 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_allocator.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_allocator.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_allocator.h 2015-11-30 17:56:13.564138792 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel.c 2015-11-30 17:56:13.568138526 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_command.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_command.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_command.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_command.c 2015-11-30 17:56:13.568138526 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_command_vg.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_command_vg.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_command_vg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_command_vg.c 2015-11-30 17:56:13.572138258 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_db.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_db.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_db.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_db.c 2015-11-30 17:56:13.572138258 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debug.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debug.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debug.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debug.c 2015-11-30 17:56:13.572138258 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debugfs.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debugfs.c 2015-11-30 17:56:13.572138258 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debugfs.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debugfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debugfs.h 2015-11-30 17:56:13.572138258 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debug.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debug.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_debug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_debug.h 2015-11-30 17:56:13.572138258 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_device.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_device.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_device.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_device.c 2015-11-30 17:56:13.576137991 +0100 @@ -0,0 +1,1938 @@ +/**************************************************************************** +* +* 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, + 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; + + 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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_device.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_device.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_device.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_device.h 2015-11-30 17:56:13.576137991 +0100 @@ -0,0 +1,185 @@ +/**************************************************************************** +* +* 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 +{ + /* 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, + OUT gckGALDEVICE *Device + ); + +gceSTATUS gckGALDEVICE_Destroy( + IN gckGALDEVICE Device + ); + +#endif /* __gc_hal_kernel_device_h_ */ diff -Nur linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_event.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_event.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_event.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_event.c 2015-11-30 17:56:13.576137991 +0100 @@ -0,0 +1,2859 @@ +/**************************************************************************** +* +* 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); + + /* Set signal. */ + if (gcmUINT64_TO_PTR(record->info.u.Signal.process) == gcvNULL) + { + /* Kernel signal. */ + gcmkERR_BREAK( + gckOS_Signal(Event->os, + signal, + gcvTRUE)); + } + else + { + /* 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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel.h 2015-11-30 17:56:13.576137991 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_interrupt_vg.c 2015-11-30 17:56:13.576137991 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_iommu.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_iommu.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_iommu.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_iommu.c 2015-11-30 17:56:13.576137991 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_linux.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_linux.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_linux.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_linux.c 2015-11-30 17:56:13.576137991 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_linux.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_linux.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_linux.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_linux.h 2015-11-30 17:56:13.576137991 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_math.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_math.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_math.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_math.c 2015-11-30 17:56:13.576137991 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_mmu.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_mmu.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_mmu.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_mmu.c 2015-11-30 17:56:13.580137725 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_mmu_vg.c 2015-11-30 17:56:13.580137725 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_os.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_os.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_os.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_os.c 2015-11-30 17:56:13.580137725 +0100 @@ -0,0 +1,8062 @@ +/**************************************************************************** +* +* 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(gcvNULL, + 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(gcvNULL, +#else + addr = dma_alloc_writecombine(gcvNULL, +#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( + gcvNULL, + 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(gcvNULL, + 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(gcvNULL, +#else + dma_free_writecombine(gcvNULL, +#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( + gcvNULL, + (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( + gcvNULL, + (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( + gcvNULL, + (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. +*/ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + 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(_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); + } + + 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. +*/ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + 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(_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); + } + + 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; + + gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d", + Os, Signal, (gctINT32)(gctUINTPTR_T)Process); + + /* Map the signal into kernel space. */ + gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal)); + + /* Signal. */ + status = gckOS_Signal(Os, signal, gcvTRUE); + + /* Unmap the signal */ + gcmkVERIFY_OK(gckOS_UnmapSignal(Os, Signal)); + + gcmkFOOTER(); + return status; + +OnError: + /* 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_DestroySignal(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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_os.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_os.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_os.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_os.h 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_platform.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_platform.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_platform.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_platform.h 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_power.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_power.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_power.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_power.c 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_precomp.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_precomp.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_precomp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_precomp.h 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_probe.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_probe.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_probe.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_probe.c 2015-11-30 17:56:13.584137459 +0100 @@ -0,0 +1,1252 @@ +/**************************************************************************** +* +* 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(void) +{ + 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, + &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(); + + 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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_sync.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_sync.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_sync.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_sync.c 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_sync.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_sync.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_sync.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_sync.h 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_vg.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_vg.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_vg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_vg.c 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_vg.h linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_vg.h --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_vg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_vg.h 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_video_memory.c linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_video_memory.c --- linux-4.1.13.orig/drivers/gpu/galcore/gc_hal_kernel_video_memory.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/gc_hal_kernel_video_memory.c 2015-11-30 17:56:13.584137459 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/aqHal.h linux-4.1.13/drivers/gpu/galcore/inc/aqHal.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/aqHal.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/aqHal.h 2015-11-30 17:56:13.584137459 +0100 @@ -0,0 +1 @@ +#include "HAL/gc_hal.h" diff -Nur linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_base.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_base.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_base.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_base.h 2015-11-30 17:56:13.588137194 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_driver.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_driver.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_driver.h 2015-11-30 17:56:13.588137194 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_driver_vg.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_driver_vg.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_driver_vg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_driver_vg.h 2015-11-30 17:56:13.588137194 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_dump.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_dump.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_dump.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_dump.h 2015-11-30 17:56:13.588137194 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_eglplatform.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_eglplatform.h 2015-11-30 17:56:13.588137194 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_eglplatform_type.h 2015-11-30 17:56:13.588137194 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_engine.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_engine.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_engine.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_engine.h 2015-11-30 17:56:13.588137194 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_engine_vg.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_engine_vg.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_engine_vg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_engine_vg.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_enum.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_enum.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_enum.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_enum.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_kernel_buffer.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_mem.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_mem.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_mem.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_mem.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_options.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_options.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_options.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_options.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_profiler.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_profiler.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_profiler.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_profiler.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_raster.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_raster.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_raster.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_raster.h 2015-11-30 17:56:13.592136927 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_rename.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_rename.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_rename.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_rename.h 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_statistics.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_statistics.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_statistics.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_statistics.h 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_types.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_types.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_types.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_types.h 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_version.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_version.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_version.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_version.h 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_vg.h linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_vg.h --- linux-4.1.13.orig/drivers/gpu/galcore/inc/gc_hal_vg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/inc/gc_hal_vg.h 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/gpu/galcore/Kbuild linux-4.1.13/drivers/gpu/galcore/Kbuild --- linux-4.1.13.orig/drivers/gpu/galcore/Kbuild 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/Kbuild 2015-11-30 17:56:13.596136660 +0100 @@ -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_MXC_GPU_VIV_V5) += galcore.o + +galcore-objs := $(OBJS) + +endif diff -Nur linux-4.1.13.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c linux-4.1.13/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c --- linux-4.1.13.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.c 2015-11-30 17:56:13.596136660 +0100 @@ -0,0 +1,693 @@ +/**************************************************************************** +* +* 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_IMX_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_IMX_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-4.1.13.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config linux-4.1.13/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config --- linux-4.1.13.orig/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/gpu/galcore/platform/freescale/gc_hal_kernel_platform_imx6q14.config 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/Kconfig linux-4.1.13/drivers/Kconfig --- linux-4.1.13.orig/drivers/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/Kconfig 2015-11-30 17:56:13.596136660 +0100 @@ -182,4 +182,6 @@ source "drivers/android/Kconfig" +source "drivers/mxc/Kconfig" + endmenu diff -Nur linux-4.1.13.orig/drivers/Makefile linux-4.1.13/drivers/Makefile --- linux-4.1.13.orig/drivers/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/Makefile 2015-11-30 17:56:13.596136660 +0100 @@ -165,3 +165,4 @@ obj-$(CONFIG_THUNDERBOLT) += thunderbolt/ obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/ obj-$(CONFIG_ANDROID) += android/ +obj-y += mxc/ diff -Nur linux-4.1.13.orig/drivers/media/pci/Kconfig linux-4.1.13/drivers/media/pci/Kconfig --- linux-4.1.13.orig/drivers/media/pci/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/pci/Kconfig 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/media/pci/Makefile linux-4.1.13/drivers/media/pci/Makefile --- linux-4.1.13.orig/drivers/media/pci/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/pci/Makefile 2015-11-30 17:56:13.596136660 +0100 @@ -27,3 +27,4 @@ obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_STA2X11_VIP) += sta2x11/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ +obj-$(CONFIG_VIDEO_TW6869) += tw6869/ diff -Nur linux-4.1.13.orig/drivers/media/pci/tw6869/Kconfig linux-4.1.13/drivers/media/pci/tw6869/Kconfig --- linux-4.1.13.orig/drivers/media/pci/tw6869/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/pci/tw6869/Kconfig 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/media/pci/tw6869/Makefile linux-4.1.13/drivers/media/pci/tw6869/Makefile --- linux-4.1.13.orig/drivers/media/pci/tw6869/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/pci/tw6869/Makefile 2015-11-30 17:56:13.596136660 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_TW6869) += tw6869.o diff -Nur linux-4.1.13.orig/drivers/media/pci/tw6869/tw6869.c linux-4.1.13/drivers/media/pci/tw6869/tw6869.c --- linux-4.1.13.orig/drivers/media/pci/tw6869/tw6869.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/pci/tw6869/tw6869.c 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/media/pci/tw6869/tw6869.h linux-4.1.13/drivers/media/pci/tw6869/tw6869.h --- linux-4.1.13.orig/drivers/media/pci/tw6869/tw6869.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/pci/tw6869/tw6869.h 2015-11-30 17:56:13.596136660 +0100 @@ -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-4.1.13.orig/drivers/media/platform/Kconfig linux-4.1.13/drivers/media/platform/Kconfig --- linux-4.1.13.orig/drivers/media/platform/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/Kconfig 2015-11-30 17:56:13.596136660 +0100 @@ -114,6 +114,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 + select VIDEO_V4L2_INT_DEVICE + ---help--- + This is the video4linux2 capture driver based on i.MX video-in module. + +source "drivers/media/platform/mxc/capture/Kconfig" +source "drivers/media/platform/mxc/output/Kconfig" source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" diff -Nur linux-4.1.13.orig/drivers/media/platform/Makefile linux-4.1.13/drivers/media/platform/Makefile --- linux-4.1.13.orig/drivers/media/platform/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/Makefile 2015-11-30 17:56:13.596136660 +0100 @@ -50,4 +50,7 @@ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ +obj-y += mxc/capture/ +obj-y += mxc/output/ + ccflags-y += -I$(srctree)/drivers/media/i2c diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/capture/adv7180.c linux-4.1.13/drivers/media/platform/mxc/capture/adv7180.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/adv7180.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/adv7180.c 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,1344 @@ +/* + * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file adv7180.c + * + * @brief Analog Device ADV7180 video decoder functions + * + * @ingroup Camera + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" + +#define ADV7180_VOLTAGE_ANALOG 1800000 +#define ADV7180_VOLTAGE_DIGITAL_CORE 1800000 +#define ADV7180_VOLTAGE_DIGITAL_IO 3300000 +#define ADV7180_VOLTAGE_PLL 1800000 + +static struct regulator *dvddio_regulator; +static struct regulator *dvdd_regulator; +static struct regulator *avdd_regulator; +static struct regulator *pvdd_regulator; +static int pwn_gpio; + +static int adv7180_probe(struct i2c_client *adapter, + const struct i2c_device_id *id); +static int adv7180_detach(struct i2c_client *client); + +static const struct i2c_device_id adv7180_id[] = { + {"adv7180", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, adv7180_id); + +static struct i2c_driver adv7180_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7180", + }, + .probe = adv7180_probe, + .remove = adv7180_detach, + .id_table = adv7180_id, +}; + +/*! + * Maintains the information on the current state of the sensor. + */ +struct sensor { + struct sensor_data sen; + v4l2_std_id std_id; +} adv7180_data; + + +/*! List of input video formats supported. The video formats is corresponding + * with v4l2 id in video_fmt_t + */ +typedef enum { + ADV7180_NTSC = 0, /*!< Locked on (M) NTSC video signal. */ + ADV7180_PAL, /*!< (B, G, H, I, N)PAL video signal. */ + ADV7180_NOT_LOCKED, /*!< Not locked on a signal. */ +} video_fmt_idx; + +/*! Number of video standards supported (including 'not locked' signal). */ +#define ADV7180_STD_MAX (ADV7180_PAL + 1) + +/*! Video format structure. */ +typedef struct { + int v4l2_id; /*!< Video for linux ID. */ + char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */ + u16 raw_width; /*!< Raw width. */ + u16 raw_height; /*!< Raw height. */ + u16 active_width; /*!< Active width. */ + u16 active_height; /*!< Active height. */ +} video_fmt_t; + +/*! Description of video formats supported. + * + * PAL: raw=720x625, active=720x576. + * NTSC: raw=720x525, active=720x480. + */ +static video_fmt_t video_fmts[] = { + { /*! NTSC */ + .v4l2_id = V4L2_STD_NTSC, + .name = "NTSC", + .raw_width = 720, /* SENS_FRM_WIDTH */ + .raw_height = 525, /* SENS_FRM_HEIGHT */ + .active_width = 720, /* ACT_FRM_WIDTH plus 1 */ + .active_height = 480, /* ACT_FRM_WIDTH plus 1 */ + }, + { /*! (B, G, H, I, N) PAL */ + .v4l2_id = V4L2_STD_PAL, + .name = "PAL", + .raw_width = 720, + .raw_height = 625, + .active_width = 720, + .active_height = 576, + }, + { /*! Unlocked standard */ + .v4l2_id = V4L2_STD_ALL, + .name = "Autodetect", + .raw_width = 720, + .raw_height = 625, + .active_width = 720, + .active_height = 576, + }, +}; + +/*!* Standard index of ADV7180. */ +static video_fmt_idx video_idx = ADV7180_PAL; + +/*! @brief This mutex is used to provide mutual exclusion. + * + * Create a mutex that can be used to provide mutually exclusive + * read/write access to the globally accessible data structures + * and variables that were defined above. + */ +static DEFINE_MUTEX(mutex); + +#define IF_NAME "adv7180" +#define ADV7180_INPUT_CTL 0x00 /* Input Control */ +#define ADV7180_STATUS_1 0x10 /* Status #1 */ +#define ADV7180_BRIGHTNESS 0x0a /* Brightness */ +#define ADV7180_IDENT 0x11 /* IDENT */ +#define ADV7180_VSYNC_FIELD_CTL_1 0x31 /* VSYNC Field Control #1 */ +#define ADV7180_MANUAL_WIN_CTL 0x3d /* Manual Window Control */ +#define ADV7180_SD_SATURATION_CB 0xe3 /* SD Saturation Cb */ +#define ADV7180_SD_SATURATION_CR 0xe4 /* SD Saturation Cr */ +#define ADV7180_PWR_MNG 0x0f /* Power Management */ + +/* supported controls */ +/* This hasn't been fully implemented yet. + * This is how it should work, though. */ +static struct v4l2_queryctrl adv7180_qctrl[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, /* check this value */ + .maximum = 255, /* check this value */ + .step = 1, /* check this value */ + .default_value = 127, /* check this value */ + .flags = 0, + }, { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, /* check this value */ + .maximum = 255, /* check this value */ + .step = 0x1, /* check this value */ + .default_value = 127, /* check this value */ + .flags = 0, + } +}; + +static inline void adv7180_power_down(int enable) +{ + gpio_set_value_cansleep(pwn_gpio, !enable); + msleep(2); +} + +static int adv7180_regulator_enable(struct device *dev) +{ + int ret = 0; + + dvddio_regulator = devm_regulator_get(dev, "DOVDD"); + + if (!IS_ERR(dvddio_regulator)) { + regulator_set_voltage(dvddio_regulator, + ADV7180_VOLTAGE_DIGITAL_IO, + ADV7180_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(dvddio_regulator); + if (ret) { + dev_err(dev, "set io voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set io voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get io voltage\n"); + } + + dvdd_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(dvdd_regulator)) { + regulator_set_voltage(dvdd_regulator, + ADV7180_VOLTAGE_DIGITAL_CORE, + ADV7180_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(dvdd_regulator); + if (ret) { + dev_err(dev, "set core voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set core voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get core voltage\n"); + } + + avdd_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(avdd_regulator)) { + regulator_set_voltage(avdd_regulator, + ADV7180_VOLTAGE_ANALOG, + ADV7180_VOLTAGE_ANALOG); + ret = regulator_enable(avdd_regulator); + if (ret) { + dev_err(dev, "set analog voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set analog voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get analog voltage\n"); + } + + pvdd_regulator = devm_regulator_get(dev, "PVDD"); + if (!IS_ERR(pvdd_regulator)) { + regulator_set_voltage(pvdd_regulator, + ADV7180_VOLTAGE_PLL, + ADV7180_VOLTAGE_PLL); + ret = regulator_enable(pvdd_regulator); + if (ret) { + dev_err(dev, "set pll voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set pll voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get pll voltage\n"); + } + + return ret; +} + + +/*********************************************************************** + * I2C transfert. + ***********************************************************************/ + +/*! Read one register from a ADV7180 i2c slave device. + * + * @param *reg register in the device we wish to access. + * + * @return 0 if success, an error code otherwise. + */ +static inline int adv7180_read(u8 reg) +{ + int val; + + val = i2c_smbus_read_byte_data(adv7180_data.sen.i2c_client, reg); + if (val < 0) { + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:read reg error: reg=%2x\n", __func__, reg); + return -1; + } + return val; +} + +/*! Write one register of a ADV7180 i2c slave device. + * + * @param *reg register in the device we wish to access. + * + * @return 0 if success, an error code otherwise. + */ +static int adv7180_write_reg(u8 reg, u8 val) +{ + s32 ret; + + ret = i2c_smbus_write_byte_data(adv7180_data.sen.i2c_client, reg, val); + if (ret < 0) { + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:write reg error:reg=%2x,val=%2x\n", __func__, + reg, val); + return -1; + } + return 0; +} + +/*********************************************************************** + * mxc_v4l2_capture interface. + ***********************************************************************/ + +/*! + * Return attributes of current video standard. + * Since this device autodetects the current standard, this function also + * sets the values that need to be changed if the standard changes. + * There is no set std equivalent function. + * + * @return None. + */ +static void adv7180_get_std(v4l2_std_id *std) +{ + int tmp; + int idx; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n"); + + /* Read the AD_RESULT to get the detect output video standard */ + tmp = adv7180_read(ADV7180_STATUS_1) & 0x70; + + mutex_lock(&mutex); + if (tmp == 0x40) { + /* PAL */ + *std = V4L2_STD_PAL; + idx = ADV7180_PAL; + } else if (tmp == 0) { + /*NTSC*/ + *std = V4L2_STD_NTSC; + idx = ADV7180_NTSC; + } else { + *std = V4L2_STD_ALL; + idx = ADV7180_NOT_LOCKED; + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "Got invalid video standard!\n"); + } + mutex_unlock(&mutex); + + /* This assumes autodetect which this device uses. */ + if (*std != adv7180_data.std_id) { + video_idx = idx; + adv7180_data.std_id = *std; + adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width; + adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height; + } +} + +/*********************************************************************** + * IOCTL Functions from v4l2_int_ioctl_desc. + ***********************************************************************/ + +/*! + * ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num + * s: pointer to standard V4L2 device structure + * p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure + * + * Gets slave interface parameters. + * Calculates the required xclk value to support the requested + * clock parameters in p. This value is returned in the p + * parameter. + * + * vidioc_int_g_ifparm returns platform-specific information about the + * interface settings used by the sensor. + * + * Called on open. + */ +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_ifparm\n"); + + if (s == NULL) { + pr_err(" ERROR!! no slave device set!\n"); + return -1; + } + + /* Initialize structure to 0s then set any non-0 values. */ + memset(p, 0, sizeof(*p)); + p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */ + p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.nobt_hs_inv = 1; + p->u.bt656.bt_sync_correct = 1; + + /* ADV7180 has a dedicated clock so no clock settings needed. */ + + return 0; +} + +/*! + * Sets the camera power. + * + * s pointer to the camera device + * on if 1, power is to be turned on. 0 means power is to be turned off + * + * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num + * @s: pointer to standard V4L2 device structure + * @on: power state to which device is to be set + * + * Sets devices power state to requrested state, if possible. + * This is called on open, close, suspend and resume. + */ +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct sensor *sensor = s->priv; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_s_power\n"); + + if (on && !sensor->sen.on) { + if (adv7180_write_reg(ADV7180_PWR_MNG, 0x04) != 0) + return -EIO; + + /* + * FIXME:Additional 400ms to wait the chip to be stable? + * This is a workaround for preview scrolling issue. + */ + msleep(400); + } else if (!on && sensor->sen.on) { + if (adv7180_write_reg(ADV7180_PWR_MNG, 0x24) != 0) + return -EIO; + } + + sensor->sen.on = on; + + return 0; +} + +/*! + * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_parm\n"); + + switch (a->type) { + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->sen.streamcap.capability; + cparm->timeperframe = sensor->sen.streamcap.timeperframe; + cparm->capturemode = sensor->sen.streamcap.capturemode; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + break; + + default: + pr_debug("ioctl_g_parm:type is unknown %d\n", a->type); + break; + } + + return 0; +} + +/*! + * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + * + * This driver cannot change these settings. + */ +static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_parm\n"); + + switch (a->type) { + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + break; + } + + return 0; +} + +/*! + * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap + * @s: pointer to standard V4L2 device structure + * @f: pointer to standard V4L2 v4l2_format structure + * + * Returns the sensor's current pixel format in the v4l2_format + * parameter. + */ +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + struct sensor *sensor = s->priv; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_fmt_cap\n"); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" Returning size of %dx%d\n", + sensor->sen.pix.width, sensor->sen.pix.height); + f->fmt.pix = sensor->sen.pix; + break; + + case V4L2_BUF_TYPE_PRIVATE: { + v4l2_std_id std; + adv7180_get_std(&std); + f->fmt.pix.pixelformat = (u32)std; + } + break; + + default: + f->fmt.pix = sensor->sen.pix; + break; + } + + return 0; +} + +/*! + * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl + * @s: pointer to standard V4L2 device structure + * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure + * + * If the requested control is supported, returns the control information + * from the video_control[] array. Otherwise, returns -EINVAL if the + * control is not supported. + */ +static int ioctl_queryctrl(struct v4l2_int_device *s, + struct v4l2_queryctrl *qc) +{ + int i; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_queryctrl\n"); + + for (i = 0; i < ARRAY_SIZE(adv7180_qctrl); i++) + if (qc->id && qc->id == adv7180_qctrl[i].id) { + memcpy(qc, &(adv7180_qctrl[i]), + sizeof(*qc)); + return 0; + } + + return -EINVAL; +} + +/*! + * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure + * + * If the requested control is supported, returns the control's current + * value from the video_control[] array. Otherwise, returns -EINVAL + * if the control is not supported. + */ +static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int ret = 0; + int sat = 0; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n"); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BRIGHTNESS\n"); + adv7180_data.sen.brightness = adv7180_read(ADV7180_BRIGHTNESS); + vc->value = adv7180_data.sen.brightness; + break; + case V4L2_CID_CONTRAST: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_CONTRAST\n"); + vc->value = adv7180_data.sen.contrast; + break; + case V4L2_CID_SATURATION: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_SATURATION\n"); + sat = adv7180_read(ADV7180_SD_SATURATION_CB); + adv7180_data.sen.saturation = sat; + vc->value = adv7180_data.sen.saturation; + break; + case V4L2_CID_HUE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HUE\n"); + vc->value = adv7180_data.sen.hue; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTO_WHITE_BALANCE\n"); + break; + case V4L2_CID_DO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_DO_WHITE_BALANCE\n"); + break; + case V4L2_CID_RED_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_RED_BALANCE\n"); + vc->value = adv7180_data.sen.red; + break; + case V4L2_CID_BLUE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BLUE_BALANCE\n"); + vc->value = adv7180_data.sen.blue; + break; + case V4L2_CID_GAMMA: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAMMA\n"); + break; + case V4L2_CID_EXPOSURE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_EXPOSURE\n"); + vc->value = adv7180_data.sen.ae_mode; + break; + case V4L2_CID_AUTOGAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTOGAIN\n"); + break; + case V4L2_CID_GAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAIN\n"); + break; + case V4L2_CID_HFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HFLIP\n"); + break; + case V4L2_CID_VFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_VFLIP\n"); + break; + default: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " Default case\n"); + vc->value = 0; + ret = -EPERM; + break; + } + + return ret; +} + +/*! + * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure + * + * If the requested control is supported, sets the control's current + * value in HW (and updates the video_control[] array). Otherwise, + * returns -EINVAL if the control is not supported. + */ +static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int retval = 0; + u8 tmp; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n"); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BRIGHTNESS\n"); + tmp = vc->value; + adv7180_write_reg(ADV7180_BRIGHTNESS, tmp); + adv7180_data.sen.brightness = vc->value; + break; + case V4L2_CID_CONTRAST: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_CONTRAST\n"); + break; + case V4L2_CID_SATURATION: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_SATURATION\n"); + tmp = vc->value; + adv7180_write_reg(ADV7180_SD_SATURATION_CB, tmp); + adv7180_write_reg(ADV7180_SD_SATURATION_CR, tmp); + adv7180_data.sen.saturation = vc->value; + break; + case V4L2_CID_HUE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HUE\n"); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTO_WHITE_BALANCE\n"); + break; + case V4L2_CID_DO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_DO_WHITE_BALANCE\n"); + break; + case V4L2_CID_RED_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_RED_BALANCE\n"); + break; + case V4L2_CID_BLUE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BLUE_BALANCE\n"); + break; + case V4L2_CID_GAMMA: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAMMA\n"); + break; + case V4L2_CID_EXPOSURE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_EXPOSURE\n"); + break; + case V4L2_CID_AUTOGAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTOGAIN\n"); + break; + case V4L2_CID_GAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAIN\n"); + break; + case V4L2_CID_HFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HFLIP\n"); + break; + case V4L2_CID_VFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_VFLIP\n"); + break; + default: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " Default case\n"); + retval = -EPERM; + break; + } + + return retval; +} + +/*! + * ioctl_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_framesizes(struct v4l2_int_device *s, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index >= 1) + return -EINVAL; + + fsize->discrete.width = video_fmts[video_idx].active_width; + fsize->discrete.height = video_fmts[video_idx].active_height; + + return 0; +} + +/*! + * ioctl_g_chip_ident - V4L2 sensor interface handler for + * VIDIOC_DBG_G_CHIP_IDENT ioctl + * @s: pointer to standard V4L2 device structure + * @id: pointer to int + * + * Return 0. + */ +static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) +{ + ((struct v4l2_dbg_chip_ident *)id)->match.type = + V4L2_CHIP_MATCH_I2C_DRIVER; + strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, + "adv7180_decoder"); + ((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_ADV7180; + + return 0; +} + +/*! + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT + * @s: pointer to standard V4L2 device structure + */ +static int ioctl_init(struct v4l2_int_device *s) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_init\n"); + return 0; +} + +/*! + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device structure + * + * Initialise the device when slave attaches to the master. + */ +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_dev_init\n"); + return 0; +} + +/*! + * This structure defines all the ioctls for this module. + */ +static struct v4l2_int_ioctl_desc adv7180_ioctl_desc[] = { + + {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init}, + + /*! + * Delinitialise the dev. at slave detach. + * The complement of ioctl_dev_init. + */ +/* {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */ + + {vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power}, + {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm}, +/* {vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */ +/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */ + {vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init}, + + /*! + * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type. + */ +/* {vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */ + + /*! + * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. + * This ioctl is used to negotiate the image capture size and + * pixel format without actually making it take effect. + */ +/* {vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */ + + {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap}, + + /*! + * If the requested format is supported, configures the HW to use that + * format, returns error code if format not supported or HW can't be + * correctly configured. + */ +/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */ + + {vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm}, + {vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm}, + {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func*)ioctl_queryctrl}, + {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func*)ioctl_g_ctrl}, + {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func*)ioctl_s_ctrl}, + {vidioc_int_enum_framesizes_num, + (v4l2_int_ioctl_func *) ioctl_enum_framesizes}, + {vidioc_int_g_chip_ident_num, + (v4l2_int_ioctl_func *)ioctl_g_chip_ident}, +}; + +static struct v4l2_int_slave adv7180_slave = { + .ioctls = adv7180_ioctl_desc, + .num_ioctls = ARRAY_SIZE(adv7180_ioctl_desc), +}; + +static struct v4l2_int_device adv7180_int_device = { + .module = THIS_MODULE, + .name = "adv7180", + .type = v4l2_int_type_slave, + .u = { + .slave = &adv7180_slave, + }, +}; + + +/*********************************************************************** + * I2C client and driver. + ***********************************************************************/ + +/*! ADV7180 Reset function. + * + * @return None. + */ +static void adv7180_hard_reset(bool cvbs) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "In adv7180:adv7180_hard_reset\n"); + + if (cvbs) { + /* Set CVBS input on AIN1 */ + adv7180_write_reg(ADV7180_INPUT_CTL, 0x00); + } else { + /* + * Set YPbPr input on AIN1,4,5 and normal + * operations(autodection of all stds). + */ + adv7180_write_reg(ADV7180_INPUT_CTL, 0x09); + } + + /* Datasheet recommends */ + adv7180_write_reg(0x01, 0xc8); + adv7180_write_reg(0x02, 0x04); + adv7180_write_reg(0x03, 0x00); + adv7180_write_reg(0x04, 0x45); + adv7180_write_reg(0x05, 0x00); + adv7180_write_reg(0x06, 0x02); + adv7180_write_reg(0x07, 0x7F); + adv7180_write_reg(0x08, 0x80); + adv7180_write_reg(0x0A, 0x00); + adv7180_write_reg(0x0B, 0x00); + adv7180_write_reg(0x0C, 0x36); + adv7180_write_reg(0x0D, 0x7C); + adv7180_write_reg(0x0E, 0x00); + adv7180_write_reg(0x0F, 0x00); + adv7180_write_reg(0x13, 0x00); + adv7180_write_reg(0x14, 0x12); + adv7180_write_reg(0x15, 0x00); + adv7180_write_reg(0x16, 0x00); + adv7180_write_reg(0x17, 0x01); + adv7180_write_reg(0x18, 0x93); + adv7180_write_reg(0xF1, 0x19); + adv7180_write_reg(0x1A, 0x00); + adv7180_write_reg(0x1B, 0x00); + adv7180_write_reg(0x1C, 0x00); + adv7180_write_reg(0x1D, 0x40); + adv7180_write_reg(0x1E, 0x00); + adv7180_write_reg(0x1F, 0x00); + adv7180_write_reg(0x20, 0x00); + adv7180_write_reg(0x21, 0x00); + adv7180_write_reg(0x22, 0x00); + adv7180_write_reg(0x23, 0xC0); + adv7180_write_reg(0x24, 0x00); + adv7180_write_reg(0x25, 0x00); + adv7180_write_reg(0x26, 0x00); + adv7180_write_reg(0x27, 0x58); + adv7180_write_reg(0x28, 0x00); + adv7180_write_reg(0x29, 0x00); + adv7180_write_reg(0x2A, 0x00); + adv7180_write_reg(0x2B, 0xE1); + adv7180_write_reg(0x2C, 0xAE); + adv7180_write_reg(0x2D, 0xF4); + adv7180_write_reg(0x2E, 0x00); + adv7180_write_reg(0x2F, 0xF0); + adv7180_write_reg(0x30, 0x00); + adv7180_write_reg(0x31, 0x12); + adv7180_write_reg(0x32, 0x41); + adv7180_write_reg(0x33, 0x84); + adv7180_write_reg(0x34, 0x00); + adv7180_write_reg(0x35, 0x02); + adv7180_write_reg(0x36, 0x00); + adv7180_write_reg(0x37, 0x01); + adv7180_write_reg(0x38, 0x80); + adv7180_write_reg(0x39, 0xC0); + adv7180_write_reg(0x3A, 0x10); + adv7180_write_reg(0x3B, 0x05); + adv7180_write_reg(0x3C, 0x58); + adv7180_write_reg(0x3D, 0xB2); + adv7180_write_reg(0x3E, 0x64); + adv7180_write_reg(0x3F, 0xE4); + adv7180_write_reg(0x40, 0x90); + adv7180_write_reg(0x41, 0x01); + adv7180_write_reg(0x42, 0x7E); + adv7180_write_reg(0x43, 0xA4); + adv7180_write_reg(0x44, 0xFF); + adv7180_write_reg(0x45, 0xB6); + adv7180_write_reg(0x46, 0x12); + adv7180_write_reg(0x48, 0x00); + adv7180_write_reg(0x49, 0x00); + adv7180_write_reg(0x4A, 0x00); + adv7180_write_reg(0x4B, 0x00); + adv7180_write_reg(0x4C, 0x00); + adv7180_write_reg(0x4D, 0xEF); + adv7180_write_reg(0x4E, 0x08); + adv7180_write_reg(0x4F, 0x08); + adv7180_write_reg(0x50, 0x08); + adv7180_write_reg(0x51, 0x24); + adv7180_write_reg(0x52, 0x0B); + adv7180_write_reg(0x53, 0x4E); + adv7180_write_reg(0x54, 0x80); + adv7180_write_reg(0x55, 0x00); + adv7180_write_reg(0x56, 0x10); + adv7180_write_reg(0x57, 0x00); + adv7180_write_reg(0x58, 0x00); + adv7180_write_reg(0x59, 0x00); + adv7180_write_reg(0x5A, 0x00); + adv7180_write_reg(0x5B, 0x00); + adv7180_write_reg(0x5C, 0x00); + adv7180_write_reg(0x5D, 0x00); + adv7180_write_reg(0x5E, 0x00); + adv7180_write_reg(0x5F, 0x00); + adv7180_write_reg(0x60, 0x00); + adv7180_write_reg(0x61, 0x00); + adv7180_write_reg(0x62, 0x20); + adv7180_write_reg(0x63, 0x00); + adv7180_write_reg(0x64, 0x00); + adv7180_write_reg(0x65, 0x00); + adv7180_write_reg(0x66, 0x00); + adv7180_write_reg(0x67, 0x03); + adv7180_write_reg(0x68, 0x01); + adv7180_write_reg(0x69, 0x00); + adv7180_write_reg(0x6A, 0x00); + adv7180_write_reg(0x6B, 0xC0); + adv7180_write_reg(0x6C, 0x00); + adv7180_write_reg(0x6D, 0x00); + adv7180_write_reg(0x6E, 0x00); + adv7180_write_reg(0x6F, 0x00); + adv7180_write_reg(0x70, 0x00); + adv7180_write_reg(0x71, 0x00); + adv7180_write_reg(0x72, 0x00); + adv7180_write_reg(0x73, 0x10); + adv7180_write_reg(0x74, 0x04); + adv7180_write_reg(0x75, 0x01); + adv7180_write_reg(0x76, 0x00); + adv7180_write_reg(0x77, 0x3F); + adv7180_write_reg(0x78, 0xFF); + adv7180_write_reg(0x79, 0xFF); + adv7180_write_reg(0x7A, 0xFF); + adv7180_write_reg(0x7B, 0x1E); + adv7180_write_reg(0x7C, 0xC0); + adv7180_write_reg(0x7D, 0x00); + adv7180_write_reg(0x7E, 0x00); + adv7180_write_reg(0x7F, 0x00); + adv7180_write_reg(0x80, 0x00); + adv7180_write_reg(0x81, 0xC0); + adv7180_write_reg(0x82, 0x04); + adv7180_write_reg(0x83, 0x00); + adv7180_write_reg(0x84, 0x0C); + adv7180_write_reg(0x85, 0x02); + adv7180_write_reg(0x86, 0x03); + adv7180_write_reg(0x87, 0x63); + adv7180_write_reg(0x88, 0x5A); + adv7180_write_reg(0x89, 0x08); + adv7180_write_reg(0x8A, 0x10); + adv7180_write_reg(0x8B, 0x00); + adv7180_write_reg(0x8C, 0x40); + adv7180_write_reg(0x8D, 0x00); + adv7180_write_reg(0x8E, 0x40); + adv7180_write_reg(0x8F, 0x00); + adv7180_write_reg(0x90, 0x00); + adv7180_write_reg(0x91, 0x50); + adv7180_write_reg(0x92, 0x00); + adv7180_write_reg(0x93, 0x00); + adv7180_write_reg(0x94, 0x00); + adv7180_write_reg(0x95, 0x00); + adv7180_write_reg(0x96, 0x00); + adv7180_write_reg(0x97, 0xF0); + adv7180_write_reg(0x98, 0x00); + adv7180_write_reg(0x99, 0x00); + adv7180_write_reg(0x9A, 0x00); + adv7180_write_reg(0x9B, 0x00); + adv7180_write_reg(0x9C, 0x00); + adv7180_write_reg(0x9D, 0x00); + adv7180_write_reg(0x9E, 0x00); + adv7180_write_reg(0x9F, 0x00); + adv7180_write_reg(0xA0, 0x00); + adv7180_write_reg(0xA1, 0x00); + adv7180_write_reg(0xA2, 0x00); + adv7180_write_reg(0xA3, 0x00); + adv7180_write_reg(0xA4, 0x00); + adv7180_write_reg(0xA5, 0x00); + adv7180_write_reg(0xA6, 0x00); + adv7180_write_reg(0xA7, 0x00); + adv7180_write_reg(0xA8, 0x00); + adv7180_write_reg(0xA9, 0x00); + adv7180_write_reg(0xAA, 0x00); + adv7180_write_reg(0xAB, 0x00); + adv7180_write_reg(0xAC, 0x00); + adv7180_write_reg(0xAD, 0x00); + adv7180_write_reg(0xAE, 0x60); + adv7180_write_reg(0xAF, 0x00); + adv7180_write_reg(0xB0, 0x00); + adv7180_write_reg(0xB1, 0x60); + adv7180_write_reg(0xB2, 0x1C); + adv7180_write_reg(0xB3, 0x54); + adv7180_write_reg(0xB4, 0x00); + adv7180_write_reg(0xB5, 0x00); + adv7180_write_reg(0xB6, 0x00); + adv7180_write_reg(0xB7, 0x13); + adv7180_write_reg(0xB8, 0x03); + adv7180_write_reg(0xB9, 0x33); + adv7180_write_reg(0xBF, 0x02); + adv7180_write_reg(0xC0, 0x00); + adv7180_write_reg(0xC1, 0x00); + adv7180_write_reg(0xC2, 0x00); + adv7180_write_reg(0xC3, 0x00); + adv7180_write_reg(0xC4, 0x00); + adv7180_write_reg(0xC5, 0x81); + adv7180_write_reg(0xC6, 0x00); + adv7180_write_reg(0xC7, 0x00); + adv7180_write_reg(0xC8, 0x00); + adv7180_write_reg(0xC9, 0x04); + adv7180_write_reg(0xCC, 0x69); + adv7180_write_reg(0xCD, 0x00); + adv7180_write_reg(0xCE, 0x01); + adv7180_write_reg(0xCF, 0xB4); + adv7180_write_reg(0xD0, 0x00); + adv7180_write_reg(0xD1, 0x10); + adv7180_write_reg(0xD2, 0xFF); + adv7180_write_reg(0xD3, 0xFF); + adv7180_write_reg(0xD4, 0x7F); + adv7180_write_reg(0xD5, 0x7F); + adv7180_write_reg(0xD6, 0x3E); + adv7180_write_reg(0xD7, 0x08); + adv7180_write_reg(0xD8, 0x3C); + adv7180_write_reg(0xD9, 0x08); + adv7180_write_reg(0xDA, 0x3C); + adv7180_write_reg(0xDB, 0x9B); + adv7180_write_reg(0xDC, 0xAC); + adv7180_write_reg(0xDD, 0x4C); + adv7180_write_reg(0xDE, 0x00); + adv7180_write_reg(0xDF, 0x00); + adv7180_write_reg(0xE0, 0x14); + adv7180_write_reg(0xE1, 0x80); + adv7180_write_reg(0xE2, 0x80); + adv7180_write_reg(0xE3, 0x80); + adv7180_write_reg(0xE4, 0x80); + adv7180_write_reg(0xE5, 0x25); + adv7180_write_reg(0xE6, 0x44); + adv7180_write_reg(0xE7, 0x63); + adv7180_write_reg(0xE8, 0x65); + adv7180_write_reg(0xE9, 0x14); + adv7180_write_reg(0xEA, 0x63); + adv7180_write_reg(0xEB, 0x55); + adv7180_write_reg(0xEC, 0x55); + adv7180_write_reg(0xEE, 0x00); + adv7180_write_reg(0xEF, 0x4A); + adv7180_write_reg(0xF0, 0x44); + adv7180_write_reg(0xF1, 0x0C); + adv7180_write_reg(0xF2, 0x32); + adv7180_write_reg(0xF3, 0x00); + adv7180_write_reg(0xF4, 0x3F); + adv7180_write_reg(0xF5, 0xE0); + adv7180_write_reg(0xF6, 0x69); + adv7180_write_reg(0xF7, 0x10); + adv7180_write_reg(0xF8, 0x00); + adv7180_write_reg(0xF9, 0x03); + adv7180_write_reg(0xFA, 0xFA); + adv7180_write_reg(0xFB, 0x40); +} + +/*! ADV7180 I2C attach function. + * + * @param *adapter struct i2c_adapter *. + * + * @return Error code indicating success or failure. + */ + +/*! + * ADV7180 I2C probe function. + * Function set in i2c_driver struct. + * Called by insmod. + * + * @param *adapter I2C adapter descriptor. + * + * @return Error code indicating success or failure. + */ +static int adv7180_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rev_id; + int ret = 0; + u32 cvbs = true; + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + + printk(KERN_ERR"DBG sensor data is at %p\n", &adv7180_data); + + /* ov5640 pinctrl */ + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) { + dev_err(dev, "setup pinctrl failed\n"); + return PTR_ERR(pinctrl); + } + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_err(dev, "no sensor pwdn pin available\n"); + return -ENODEV; + } + ret = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "adv7180_pwdn"); + if (ret < 0) { + dev_err(dev, "no power pin available!\n"); + return ret; + } + + adv7180_regulator_enable(dev); + + adv7180_power_down(0); + + msleep(1); + + /* Set initial values for the sensor struct. */ + memset(&adv7180_data, 0, sizeof(adv7180_data)); + adv7180_data.sen.i2c_client = client; + adv7180_data.sen.streamcap.timeperframe.denominator = 30; + adv7180_data.sen.streamcap.timeperframe.numerator = 1; + adv7180_data.std_id = V4L2_STD_ALL; + video_idx = ADV7180_NOT_LOCKED; + adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width; + adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height; + adv7180_data.sen.pix.pixelformat = V4L2_PIX_FMT_UYVY; /* YUV422 */ + adv7180_data.sen.pix.priv = 1; /* 1 is used to indicate TV in */ + adv7180_data.sen.on = true; + + adv7180_data.sen.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(adv7180_data.sen.sensor_clk)) { + dev_err(dev, "get mclk failed\n"); + return PTR_ERR(adv7180_data.sen.sensor_clk); + } + + ret = of_property_read_u32(dev->of_node, "mclk", + &adv7180_data.sen.mclk); + if (ret) { + dev_err(dev, "mclk frequency is invalid\n"); + return ret; + } + + ret = of_property_read_u32( + dev->of_node, "mclk_source", + (u32 *) &(adv7180_data.sen.mclk_source)); + if (ret) { + dev_err(dev, "mclk_source invalid\n"); + return ret; + } + + ret = of_property_read_u32(dev->of_node, "csi_id", + &(adv7180_data.sen.csi)); + if (ret) { + dev_err(dev, "csi_id invalid\n"); + return ret; + } + + clk_prepare_enable(adv7180_data.sen.sensor_clk); + + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:adv7180 probe i2c address is 0x%02X\n", + __func__, adv7180_data.sen.i2c_client->addr); + + /*! Read the revision ID of the tvin chip */ + rev_id = adv7180_read(ADV7180_IDENT); + dev_dbg(dev, + "%s:Analog Device adv7%2X0 detected!\n", __func__, + rev_id); + + ret = of_property_read_u32(dev->of_node, "cvbs", &(cvbs)); + if (ret) { + dev_err(dev, "cvbs setting is not found\n"); + cvbs = true; + } + + /*! ADV7180 initialization. */ + adv7180_hard_reset(cvbs); + + pr_debug(" type is %d (expect %d)\n", + adv7180_int_device.type, v4l2_int_type_slave); + pr_debug(" num ioctls is %d\n", + adv7180_int_device.u.slave->num_ioctls); + + /* This function attaches this structure to the /dev/video0 device. + * The pointer in priv points to the adv7180_data structure here.*/ + adv7180_int_device.priv = &adv7180_data; + ret = v4l2_int_device_register(&adv7180_int_device); + + clk_disable_unprepare(adv7180_data.sen.sensor_clk); + + return ret; +} + +/*! + * ADV7180 I2C detach function. + * Called on rmmod. + * + * @param *client struct i2c_client*. + * + * @return Error code indicating success or failure. + */ +static int adv7180_detach(struct i2c_client *client) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:Removing %s video decoder @ 0x%02X from adapter %s\n", + __func__, IF_NAME, client->addr << 1, client->adapter->name); + + /* Power down via i2c */ + adv7180_write_reg(ADV7180_PWR_MNG, 0x24); + + if (dvddio_regulator) + regulator_disable(dvddio_regulator); + + if (dvdd_regulator) + regulator_disable(dvdd_regulator); + + if (avdd_regulator) + regulator_disable(avdd_regulator); + + if (pvdd_regulator) + regulator_disable(pvdd_regulator); + + v4l2_int_device_unregister(&adv7180_int_device); + + return 0; +} + +/*! + * ADV7180 init function. + * Called on insmod. + * + * @return Error code indicating success or failure. + */ +static __init int adv7180_init(void) +{ + u8 err = 0; + + pr_debug("In adv7180_init\n"); + + /* Tells the i2c driver what functions to call for this driver. */ + err = i2c_add_driver(&adv7180_i2c_driver); + if (err != 0) + pr_err("%s:driver registration failed, error=%d\n", + __func__, err); + + return err; +} + +/*! + * ADV7180 cleanup function. + * Called on rmmod. + * + * @return Error code indicating success or failure. + */ +static void __exit adv7180_clean(void) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_clean\n"); + i2c_del_driver(&adv7180_i2c_driver); +} + +module_init(adv7180_init); +module_exit(adv7180_clean); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver"); +MODULE_LICENSE("GPL"); diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/capture/csi_v4l2_capture.c linux-4.1.13/drivers/media/platform/mxc/capture/csi_v4l2_capture.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/csi_v4l2_capture.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/csi_v4l2_capture.c 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,2047 @@ +/* + * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file drivers/media/video/mxc/capture/csi_v4l2_capture.c + * This file is derived from mxc_v4l2_capture.c + * + * @brief Video For Linux 2 capture driver + * + * @ingroup MXC_V4L2_CAPTURE + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "fsl_csi.h" + +static int video_nr = -1; +static cam_data *g_cam; +static int req_buf_number; + +static int csi_v4l2_master_attach(struct v4l2_int_device *slave); +static void csi_v4l2_master_detach(struct v4l2_int_device *slave); +static u8 camera_power(cam_data *cam, bool cameraOn); +struct v4l2_crop crop_current; +struct v4l2_window win_current; + +/*! Information about this driver. */ +static struct v4l2_int_master csi_v4l2_master = { + .attach = csi_v4l2_master_attach, + .detach = csi_v4l2_master_detach, +}; + +static struct v4l2_int_device csi_v4l2_int_device = { + .module = THIS_MODULE, + .name = "csi_v4l2_cap", + .type = v4l2_int_type_master, + .u = { + .master = &csi_v4l2_master, + }, +}; + +static struct v4l2_queryctrl pxp_controls[] = { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Rotation", + .minimum = 0, + .maximum = 270, + .step = 90, + .default_value = 0, + .flags = 0, + }, +}; + +/* Callback function triggered after PxP receives an EOF interrupt */ +static void pxp_dma_done(void *arg) +{ + struct pxp_tx_desc *tx_desc = to_tx_desc(arg); + struct dma_chan *chan = tx_desc->txd.chan; + struct pxp_channel *pxp_chan = to_pxp_channel(chan); + cam_data *cam = pxp_chan->client; + + /* This call will signal wait_for_completion_timeout() */ + complete(&cam->pxp_tx_cmpl); +} + +static bool chan_filter(struct dma_chan *chan, void *arg) +{ + if (imx_dma_is_pxp(chan)) + return true; + else + return false; +} + +/* Function to request PXP DMA channel */ +static int pxp_chan_init(cam_data *cam) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + + /* Request a free channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_PRIVATE, mask); + chan = dma_request_channel(mask, chan_filter, NULL); + if (!chan) { + pr_err("Unsuccessfully request channel!\n"); + return -EBUSY; + } + + cam->pxp_chan = to_pxp_channel(chan); + cam->pxp_chan->client = cam; + + init_completion(&cam->pxp_tx_cmpl); + + return 0; +} + +/* + * Function to call PxP DMA driver and send our new V4L2 buffer + * through the PxP. + * Note: This is a blocking call, so upon return the PxP tx should be complete. + */ +static int pxp_process_update(cam_data *cam) +{ + dma_cookie_t cookie; + struct scatterlist *sg = cam->sg; + struct dma_chan *dma_chan; + struct pxp_tx_desc *desc; + struct dma_async_tx_descriptor *txd; + struct pxp_config_data *pxp_conf = &cam->pxp_conf; + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + int i, ret; + int length; + + pr_debug("Starting PxP Send Buffer\n"); + + /* First, check to see that we have acquired a PxP Channel object */ + if (cam->pxp_chan == NULL) { + /* + * PxP Channel has not yet been created and initialized, + * so let's go ahead and try + */ + ret = pxp_chan_init(cam); + if (ret) { + /* + * PxP channel init failed, and we can't use the + * PxP until the PxP DMA driver has loaded, so we abort + */ + pr_err("PxP chan init failed\n"); + return -ENODEV; + } + } + + /* + * Init completion, so that we can be properly informed of + * the completion of the PxP task when it is done. + */ + init_completion(&cam->pxp_tx_cmpl); + + dma_chan = &cam->pxp_chan->dma_chan; + + txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2, + DMA_TO_DEVICE, + DMA_PREP_INTERRUPT, + NULL); + if (!txd) { + pr_err("Error preparing a DMA transaction descriptor.\n"); + return -EIO; + } + + txd->callback_param = txd; + txd->callback = pxp_dma_done; + + /* + * Configure PxP for processing of new v4l2 buf + */ + pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_UYVY; + pxp_conf->s0_param.color_key = -1; + pxp_conf->s0_param.color_key_enable = false; + pxp_conf->s0_param.width = cam->v2f.fmt.pix.width; + pxp_conf->s0_param.height = cam->v2f.fmt.pix.height; + + pxp_conf->ol_param[0].combine_enable = false; + + proc_data->srect.top = 0; + proc_data->srect.left = 0; + proc_data->srect.width = pxp_conf->s0_param.width; + proc_data->srect.height = pxp_conf->s0_param.height; + + if (crop_current.c.top != 0) + proc_data->srect.top = crop_current.c.top; + if (crop_current.c.left != 0) + proc_data->srect.left = crop_current.c.left; + if (crop_current.c.width != 0) + proc_data->srect.width = crop_current.c.width; + if (crop_current.c.height != 0) + proc_data->srect.height = crop_current.c.height; + + proc_data->drect.left = 0; + proc_data->drect.top = 0; + proc_data->drect.width = proc_data->srect.width; + proc_data->drect.height = proc_data->srect.height; + + if (win_current.w.left != 0) + proc_data->drect.left = win_current.w.left; + if (win_current.w.top != 0) + proc_data->drect.top = win_current.w.top; + if (win_current.w.width != 0) + proc_data->drect.width = win_current.w.width; + if (win_current.w.height != 0) + proc_data->drect.height = win_current.w.height; + + pr_debug("srect l: %d, t: %d, w: %d, h: %d; " + "drect l: %d, t: %d, w: %d, h: %d\n", + proc_data->srect.left, proc_data->srect.top, + proc_data->srect.width, proc_data->srect.height, + proc_data->drect.left, proc_data->drect.top, + proc_data->drect.width, proc_data->drect.height); + + pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565; + pxp_conf->out_param.width = proc_data->drect.width; + pxp_conf->out_param.height = proc_data->drect.height; + + if (cam->rotation % 180) + pxp_conf->out_param.stride = pxp_conf->out_param.height; + else + pxp_conf->out_param.stride = pxp_conf->out_param.width; + + desc = to_tx_desc(txd); + length = desc->len; + for (i = 0; i < length; i++) { + if (i == 0) {/* S0 */ + memcpy(&desc->proc_data, proc_data, + sizeof(struct pxp_proc_data)); + pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]); + memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param, + sizeof(struct pxp_layer_param)); + } else if (i == 1) { + pxp_conf->out_param.paddr = sg_dma_address(&sg[1]); + memcpy(&desc->layer_param.out_param, + &pxp_conf->out_param, + sizeof(struct pxp_layer_param)); + } + + desc = desc->next; + } + + /* Submitting our TX starts the PxP processing task */ + cookie = txd->tx_submit(txd); + if (cookie < 0) { + pr_err("Error sending FB through PxP\n"); + return -EIO; + } + + cam->txd = txd; + + /* trigger PxP */ + dma_async_issue_pending(dma_chan); + + return 0; +} + +static int pxp_complete_update(cam_data *cam) +{ + int ret; + /* + * Wait for completion event, which will be set + * through our TX callback function. + */ + ret = wait_for_completion_timeout(&cam->pxp_tx_cmpl, HZ / 10); + if (ret <= 0) { + pr_warning("PxP operation failed due to %s\n", + ret < 0 ? "user interrupt" : "timeout"); + dma_release_channel(&cam->pxp_chan->dma_chan); + cam->pxp_chan = NULL; + return ret ? : -ETIMEDOUT; + } + + dma_release_channel(&cam->pxp_chan->dma_chan); + cam->pxp_chan = NULL; + + pr_debug("TX completed\n"); + + return 0; +} + +/*! + * Camera V4l2 callback function. + * + * @param mask u32 + * @param dev void device structure + * + * @return none + */ +static void camera_callback(u32 mask, void *dev) +{ + struct mxc_v4l_frame *done_frame; + struct mxc_v4l_frame *ready_frame; + cam_data *cam; + + cam = (cam_data *) dev; + if (cam == NULL) + return; + + spin_lock(&cam->queue_int_lock); + spin_lock(&cam->dqueue_int_lock); + if (!list_empty(&cam->working_q)) { + done_frame = list_entry(cam->working_q.next, + struct mxc_v4l_frame, queue); + + if (done_frame->csi_buf_num != cam->ping_pong_csi) + goto next; + + if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { + done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE; + done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; + + /* Added to the done queue */ + list_del(cam->working_q.next); + list_add_tail(&done_frame->queue, &cam->done_q); + cam->enc_counter++; + wake_up_interruptible(&cam->enc_queue); + } else { + pr_err("ERROR: v4l2 capture: %s: " + "buffer not queued\n", __func__); + } + } + +next: + if (!list_empty(&cam->ready_q)) { + ready_frame = list_entry(cam->ready_q.next, + struct mxc_v4l_frame, queue); + list_del(cam->ready_q.next); + list_add_tail(&ready_frame->queue, &cam->working_q); + + __raw_writel(ready_frame->paddress, + cam->ping_pong_csi == 1 ? CSI_CSIDMASA_FB1 : + CSI_CSIDMASA_FB2); + ready_frame->csi_buf_num = cam->ping_pong_csi; + } else { + __raw_writel(cam->dummy_frame.paddress, + cam->ping_pong_csi == 1 ? CSI_CSIDMASA_FB1 : + CSI_CSIDMASA_FB2); + } + spin_unlock(&cam->dqueue_int_lock); + spin_unlock(&cam->queue_int_lock); + + return; +} + +/*! + * Make csi ready for capture image. + * + * @param cam structure cam_data * + * + * @return status 0 success + */ +static int csi_cap_image(cam_data *cam) +{ + unsigned int value; + + value = __raw_readl(CSI_CSICR3); + __raw_writel(value | BIT_FRMCNT_RST, CSI_CSICR3); + value = __raw_readl(CSI_CSISR); + __raw_writel(value, CSI_CSISR); + + return 0; +} + +/*************************************************************************** + * Functions for handling Frame buffers. + **************************************************************************/ + +/*! + * Free frame buffers + * + * @param cam Structure cam_data * + * + * @return status 0 success. + */ +static int csi_free_frame_buf(cam_data *cam) +{ + int i; + + pr_debug("MVC: In %s\n", __func__); + + for (i = 0; i < FRAME_NUM; i++) { + if (cam->frame[i].vaddress != 0) { + dma_free_coherent(0, cam->frame[i].buffer.length, + cam->frame[i].vaddress, + cam->frame[i].paddress); + cam->frame[i].vaddress = 0; + } + } + + if (cam->dummy_frame.vaddress != 0) { + dma_free_coherent(0, cam->dummy_frame.buffer.length, + cam->dummy_frame.vaddress, + cam->dummy_frame.paddress); + cam->dummy_frame.vaddress = 0; + } + + return 0; +} + +/*! + * Allocate frame buffers + * + * @param cam Structure cam_data * + * @param count int number of buffer need to allocated + * + * @return status -0 Successfully allocated a buffer, -ENOBUFS failed. + */ +static int csi_allocate_frame_buf(cam_data *cam, int count) +{ + int i; + + pr_debug("In MVC:%s- size=%d\n", + __func__, cam->v2f.fmt.pix.sizeimage); + for (i = 0; i < count; i++) { + cam->frame[i].vaddress = dma_alloc_coherent(0, PAGE_ALIGN + (cam->v2f.fmt. + pix.sizeimage), + &cam->frame[i]. + paddress, + GFP_DMA | + GFP_KERNEL); + if (cam->frame[i].vaddress == 0) { + pr_err("ERROR: v4l2 capture: " + "%s failed.\n", __func__); + csi_free_frame_buf(cam); + return -ENOBUFS; + } + cam->frame[i].buffer.index = i; + cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; + cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cam->frame[i].buffer.length = cam->v2f.fmt.pix.sizeimage; + cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP; + cam->frame[i].buffer.m.offset = cam->frame[i].paddress; + cam->frame[i].index = i; + cam->frame[i].csi_buf_num = 0; + } + + return 0; +} + +/*! + * Free frame buffers status + * + * @param cam Structure cam_data * + * + * @return none + */ +static void csi_free_frames(cam_data *cam) +{ + int i; + + pr_debug("In MVC: %s\n", __func__); + + for (i = 0; i < FRAME_NUM; i++) + cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; + + cam->enc_counter = 0; + INIT_LIST_HEAD(&cam->ready_q); + INIT_LIST_HEAD(&cam->working_q); + INIT_LIST_HEAD(&cam->done_q); + + return; +} + +/*! + * Return the buffer status + * + * @param cam Structure cam_data * + * @param buf Structure v4l2_buffer * + * + * @return status 0 success, EINVAL failed. + */ +static int csi_v4l2_buffer_status(cam_data *cam, struct v4l2_buffer *buf) +{ + pr_debug("In MVC: %s\n", __func__); + + if (buf->index < 0 || buf->index >= FRAME_NUM) { + pr_err("ERROR: v4l2 capture: %s buffers " + "not allocated\n", __func__); + return -EINVAL; + } + + memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf)); + + return 0; +} + +static int csi_v4l2_release_bufs(cam_data *cam) +{ + pr_debug("In MVC:csi_v4l2_release_bufs\n"); + return 0; +} + +static int csi_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf) +{ + pr_debug("In MVC:csi_v4l2_prepare_bufs\n"); + + if (buf->index < 0 || buf->index >= FRAME_NUM || buf->length < + cam->v2f.fmt.pix.sizeimage) { + pr_err("ERROR: v4l2 capture: csi_v4l2_prepare_bufs buffers " + "not allocated,index=%d, length=%d\n", buf->index, + buf->length); + return -EINVAL; + } + + cam->frame[buf->index].buffer.index = buf->index; + cam->frame[buf->index].buffer.flags = V4L2_BUF_FLAG_MAPPED; + cam->frame[buf->index].buffer.length = buf->length; + cam->frame[buf->index].buffer.m.offset = cam->frame[buf->index].paddress + = buf->m.offset; + cam->frame[buf->index].buffer.type = buf->type; + cam->frame[buf->index].buffer.memory = V4L2_MEMORY_USERPTR; + cam->frame[buf->index].index = buf->index; + + return 0; +} + +/*! + * Indicates whether the palette is supported. + * + * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_UYVY or V4L2_PIX_FMT_YUV420 + * + * @return 0 if failed + */ +static inline int valid_mode(u32 palette) +{ + return (palette == V4L2_PIX_FMT_RGB565) || + (palette == V4L2_PIX_FMT_YUYV) || + (palette == V4L2_PIX_FMT_UYVY) || (palette == V4L2_PIX_FMT_YUV420); +} + +/*! + * Start stream I/O + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int csi_streamon(cam_data *cam) +{ + struct mxc_v4l_frame *frame; + unsigned long flags; + unsigned long val; + int timeout, timeout2; + + pr_debug("In MVC: %s\n", __func__); + + if (NULL == cam) { + pr_err("ERROR: v4l2 capture: %s cam parameter is NULL\n", + __func__); + return -1; + } + cam->dummy_frame.vaddress = dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->dummy_frame.paddress, + GFP_DMA | GFP_KERNEL); + if (cam->dummy_frame.vaddress == 0) { + pr_err("ERROR: v4l2 capture: Allocate dummy frame " + "failed.\n"); + return -ENOBUFS; + } + cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; + cam->dummy_frame.buffer.length = cam->v2f.fmt.pix.sizeimage; + cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; + + spin_lock_irqsave(&cam->queue_int_lock, flags); + /* move the frame from readyq to workingq */ + if (list_empty(&cam->ready_q)) { + pr_err("ERROR: v4l2 capture: %s: " + "ready_q queue empty\n", __func__); + spin_unlock_irqrestore(&cam->queue_int_lock, flags); + return -1; + } + frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); + list_del(cam->ready_q.next); + list_add_tail(&frame->queue, &cam->working_q); + __raw_writel(frame->paddress, CSI_CSIDMASA_FB1); + frame->csi_buf_num = 1; + + if (list_empty(&cam->ready_q)) { + pr_err("ERROR: v4l2 capture: %s: " + "ready_q queue empty\n", __func__); + spin_unlock_irqrestore(&cam->queue_int_lock, flags); + return -1; + } + frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); + list_del(cam->ready_q.next); + list_add_tail(&frame->queue, &cam->working_q); + __raw_writel(frame->paddress, CSI_CSIDMASA_FB2); + frame->csi_buf_num = 2; + spin_unlock_irqrestore(&cam->queue_int_lock, flags); + + cam->capture_pid = current->pid; + cam->capture_on = true; + csi_cap_image(cam); + + local_irq_save(flags); + for (timeout = 1000000; timeout > 0; timeout--) { + if (__raw_readl(CSI_CSISR) & BIT_SOF_INT) { + val = __raw_readl(CSI_CSICR3); + __raw_writel(val | BIT_DMA_REFLASH_RFF, CSI_CSICR3); + for (timeout2 = 1000000; timeout2 > 0; timeout2--) { + if (__raw_readl(CSI_CSICR3) & + BIT_DMA_REFLASH_RFF) + cpu_relax(); + else + break; + } + if (timeout2 <= 0) { + pr_err("timeout when wait for reflash done.\n"); + local_irq_restore(flags); + return -ETIME; + } + + csi_dmareq_rff_enable(); + csi_enable_int(1); + break; + } else + cpu_relax(); + } + if (timeout <= 0) { + pr_err("timeout when wait for SOF\n"); + local_irq_restore(flags); + return -ETIME; + } + local_irq_restore(flags); + + return 0; +} + +/*! + * Stop stream I/O + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int csi_streamoff(cam_data *cam) +{ + pr_debug("In MVC: %s\n", __func__); + + if (cam->capture_on == false) + return 0; + + csi_dmareq_rff_disable(); + csi_disable_int(); + cam->capture_on = false; + + /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */ + __raw_writel(0, CSI_CSIDMASA_FB1); + __raw_writel(0, CSI_CSIDMASA_FB2); + + csi_free_frames(cam); + csi_free_frame_buf(cam); + + return 0; +} + +/*! + * start the viewfinder job + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int start_preview(cam_data *cam) +{ + unsigned long fb_addr = (unsigned long)cam->v4l2_fb.base; + + __raw_writel(fb_addr, CSI_CSIDMASA_FB1); + __raw_writel(fb_addr, CSI_CSIDMASA_FB2); + __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, CSI_CSICR3); + + csi_enable_int(0); + + return 0; +} + +/*! + * shut down the viewfinder job + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int stop_preview(cam_data *cam) +{ + csi_disable_int(); + + /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */ + __raw_writel(0, CSI_CSIDMASA_FB1); + __raw_writel(0, CSI_CSIDMASA_FB2); + __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, CSI_CSICR3); + + return 0; +} + +/*************************************************************************** + * VIDIOC Functions. + **************************************************************************/ + +/*! + * + * @param cam structure cam_data * + * + * @param f structure v4l2_format * + * + * @return status 0 success, EINVAL failed + */ +static int csi_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f) +{ + int retval = 0; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + f->fmt.pix = cam->v2f.fmt.pix; + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + pr_debug(" type is V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); + f->fmt.win = cam->win; + break; + default: + pr_debug(" type is invalid\n"); + retval = -EINVAL; + } + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + + return retval; +} + +/*! + * V4L2 - csi_v4l2_s_fmt function + * + * @param cam structure cam_data * + * + * @param f structure v4l2_format * + * + * @return status 0 success, EINVAL failed + */ +static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) +{ + int retval = 0; + int size = 0; + int bytesperline = 0; + int *width, *height; + + pr_debug("In MVC: %s\n", __func__); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" type=V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + if (!valid_mode(f->fmt.pix.pixelformat)) { + pr_err("ERROR: v4l2 capture: %s: format " + "not supported\n", __func__); + return -EINVAL; + } + + /* Handle case where size requested is larger than cuurent + * camera setting. */ + if ((f->fmt.pix.width > cam->crop_bounds.width) + || (f->fmt.pix.height > cam->crop_bounds.height)) { + /* Need the logic here, calling vidioc_s_param if + * camera can change. */ + pr_debug("csi_v4l2_s_fmt size changed\n"); + } + if (cam->rotation % 180) { + height = &f->fmt.pix.width; + width = &f->fmt.pix.height; + } else { + width = &f->fmt.pix.width; + height = &f->fmt.pix.height; + } + + if ((cam->crop_bounds.width / *width > 8) || + ((cam->crop_bounds.width / *width == 8) && + (cam->crop_bounds.width % *width))) { + *width = cam->crop_bounds.width / 8; + if (*width % 8) + *width += 8 - *width % 8; + pr_err("ERROR: v4l2 capture: width exceeds limit " + "resize to %d.\n", *width); + } + + if ((cam->crop_bounds.height / *height > 8) || + ((cam->crop_bounds.height / *height == 8) && + (cam->crop_bounds.height % *height))) { + *height = cam->crop_bounds.height / 8; + if (*height % 8) + *height += 8 - *height % 8; + pr_err("ERROR: v4l2 capture: height exceeds limit " + "resize to %d.\n", *height); + } + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB565: + size = f->fmt.pix.width * f->fmt.pix.height * 2; + csi_init_format(V4L2_PIX_FMT_UYVY); + csi_set_16bit_imagpara(f->fmt.pix.width, + f->fmt.pix.height); + bytesperline = f->fmt.pix.width * 2; + break; + case V4L2_PIX_FMT_UYVY: + size = f->fmt.pix.width * f->fmt.pix.height * 2; + csi_init_format(f->fmt.pix.pixelformat); + csi_set_16bit_imagpara(f->fmt.pix.width, + f->fmt.pix.height); + bytesperline = f->fmt.pix.width * 2; + break; + case V4L2_PIX_FMT_YUYV: + size = f->fmt.pix.width * f->fmt.pix.height * 2; + csi_init_format(f->fmt.pix.pixelformat); + csi_set_16bit_imagpara(f->fmt.pix.width, + f->fmt.pix.height); + bytesperline = f->fmt.pix.width * 2; + break; + case V4L2_PIX_FMT_YUV420: + size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2; + csi_set_12bit_imagpara(f->fmt.pix.width, + f->fmt.pix.height); + bytesperline = f->fmt.pix.width; + break; + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_NV12: + default: + pr_debug(" case not supported\n"); + break; + } + + if (f->fmt.pix.bytesperline < bytesperline) + f->fmt.pix.bytesperline = bytesperline; + else + bytesperline = f->fmt.pix.bytesperline; + + if (f->fmt.pix.sizeimage < size) + f->fmt.pix.sizeimage = size; + else + size = f->fmt.pix.sizeimage; + + cam->v2f.fmt.pix = f->fmt.pix; + + if (cam->v2f.fmt.pix.priv != 0) { + if (copy_from_user(&cam->offset, + (void *)cam->v2f.fmt.pix.priv, + sizeof(cam->offset))) { + retval = -EFAULT; + break; + } + } + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); + cam->win = f->fmt.win; + win_current = f->fmt.win; + size = win_current.w.width * win_current.w.height * 2; + if (cam->v2f.fmt.pix.sizeimage < size) + cam->v2f.fmt.pix.sizeimage = size; + + break; + default: + retval = -EINVAL; + } + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + + return retval; +} + +/*! + * V4L2 - csi_v4l2_s_param function + * Allows setting of capturemode and frame rate. + * + * @param cam structure cam_data * + * @param parm structure v4l2_streamparm * + * + * @return status 0 success, EINVAL failed + */ +static int csi_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) +{ + struct v4l2_ifparm ifparm; + struct v4l2_format cam_fmt; + struct v4l2_streamparm currentparm; + int err = 0; + + pr_debug("In %s\n", __func__); + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pr_err(KERN_ERR "%s invalid type\n", __func__); + return -EINVAL; + } + + /* Stop the viewfinder */ + if (cam->overlay_on == true) + stop_preview(cam); + + currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* First check that this device can support the changes requested. */ + err = vidioc_int_g_parm(cam->sensor, ¤tparm); + if (err) { + pr_err("%s: vidioc_int_g_parm returned an error %d\n", + __func__, err); + goto exit; + } + + pr_debug(" Current capabilities are %x\n", + currentparm.parm.capture.capability); + pr_debug(" Current capturemode is %d change to %d\n", + currentparm.parm.capture.capturemode, + parm->parm.capture.capturemode); + pr_debug(" Current framerate is %d change to %d\n", + currentparm.parm.capture.timeperframe.denominator, + parm->parm.capture.timeperframe.denominator); + + err = vidioc_int_s_parm(cam->sensor, parm); + if (err) { + pr_err("%s: vidioc_int_s_parm returned an error %d\n", + __func__, err); + goto exit; + } + + vidioc_int_g_ifparm(cam->sensor, &ifparm); + cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); + pr_debug(" g_fmt_cap returns widthxheight of input as %d x %d\n", + cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); + + cam->crop_bounds.top = cam->crop_bounds.left = 0; + cam->crop_bounds.width = cam_fmt.fmt.pix.width; + cam->crop_bounds.height = cam_fmt.fmt.pix.height; + cam->crop_current.width = cam->crop_bounds.width; + cam->crop_current.height = cam->crop_bounds.height; + +exit: + return err; +} + +static int pxp_set_cstate(cam_data *cam, struct v4l2_control *vc) +{ + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + + if (vc->id == V4L2_CID_HFLIP) { + proc_data->hflip = vc->value; + } else if (vc->id == V4L2_CID_VFLIP) { + proc_data->vflip = vc->value; + } else if (vc->id == V4L2_CID_PRIVATE_BASE) { + if (vc->value % 90) + return -ERANGE; + proc_data->rotate = vc->value; + cam->rotation = vc->value; + } + + return 0; +} + +static int pxp_get_cstate(cam_data *cam, struct v4l2_control *vc) +{ + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + + if (vc->id == V4L2_CID_HFLIP) + vc->value = proc_data->hflip; + else if (vc->id == V4L2_CID_VFLIP) + vc->value = proc_data->vflip; + else if (vc->id == V4L2_CID_PRIVATE_BASE) + vc->value = proc_data->rotate; + + return 0; +} + + +/*! + * Dequeue one V4L capture buffer + * + * @param cam structure cam_data * + * @param buf structure v4l2_buffer * + * + * @return status 0 success, EINVAL invalid frame number + * ETIME timeout, ERESTARTSYS interrupted by user + */ +static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) +{ + int retval = 0; + struct mxc_v4l_frame *frame; + unsigned long lock_flags; + + if (!wait_event_interruptible_timeout(cam->enc_queue, + cam->enc_counter != 0, 10 * HZ)) { + pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue timeout " + "enc_counter %x\n", cam->enc_counter); + return -ETIME; + } else if (signal_pending(current)) { + pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue() " + "interrupt received\n"); + return -ERESTARTSYS; + } + + if (down_interruptible(&cam->busy_lock)) + return -EBUSY; + + spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags); + + if (list_empty(&cam->done_q)) { + spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); + up(&cam->busy_lock); + return -EINVAL; + } + + cam->enc_counter--; + + frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue); + list_del(cam->done_q.next); + + if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) { + frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE; + } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { + pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " + "Buffer not filled.\n"); + frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; + retval = -EINVAL; + } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) { + pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " + "Buffer not queued.\n"); + retval = -EINVAL; + } + + spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); + + buf->bytesused = cam->v2f.fmt.pix.sizeimage; + buf->index = frame->index; + buf->flags = frame->buffer.flags; + buf->m = cam->frame[frame->index].buffer.m; + + /* + * Note: + * If want to do preview on LCD, use PxP CSC to convert from UYVY + * to RGB565; but for encoding, usually we don't use RGB format. + */ + if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { + sg_dma_address(&cam->sg[0]) = buf->m.offset; + sg_dma_address(&cam->sg[1]) = + cam->frame[req_buf_number].paddress; + retval = pxp_process_update(cam); + if (retval) { + pr_err("Unable to submit PxP update task.\n"); + return retval; + } + pxp_complete_update(cam); + if (cam->frame[buf->index].vaddress) + memcpy(cam->frame[buf->index].vaddress, + cam->frame[req_buf_number].vaddress, + cam->v2f.fmt.pix.sizeimage); + } + up(&cam->busy_lock); + + return retval; +} + +/*! + * V4L interface - open function + * + * @param file structure file * + * + * @return status 0 success, ENODEV invalid device instance, + * ENODEV timeout, ERESTARTSYS interrupted by user + */ +static int csi_v4l_open(struct file *file) +{ + struct v4l2_ifparm ifparm; + struct v4l2_format cam_fmt; + struct video_device *dev = video_devdata(file); + cam_data *cam = video_get_drvdata(dev); + struct sensor_data *sensor; + int err = 0; + + pr_debug(" device name is %s\n", dev->name); + + if (!cam) { + pr_err("%s: Internal error, cam_data not found!\n", __func__); + return -EBADF; + } + + if (!cam->sensor) { + pr_err("%s: Internal error, camera is not found!\n", __func__); + return -EBADF; + } + + sensor = cam->sensor->priv; + if (!sensor) { + pr_err("%s: Internal error, sensor_data is not found!\n", __func__); + return -EBADF; + } + + down(&cam->busy_lock); + err = 0; + if (signal_pending(current)) + goto oops; + + if (cam->open_count++ == 0) { + wait_event_interruptible(cam->power_queue, + cam->low_power == false); + + cam->enc_counter = 0; + INIT_LIST_HEAD(&cam->ready_q); + INIT_LIST_HEAD(&cam->working_q); + INIT_LIST_HEAD(&cam->done_q); + + vidioc_int_g_ifparm(cam->sensor, &ifparm); + + cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + clk_prepare_enable(sensor->sensor_clk); + vidioc_int_s_power(cam->sensor, 1); + vidioc_int_init(cam->sensor); + vidioc_int_dev_init(cam->sensor); + } + + file->private_data = dev; + +oops: + up(&cam->busy_lock); + return err; +} + +/*! + * V4L interface - close function + * + * @param file struct file * + * + * @return 0 success + */ +static int csi_v4l_close(struct file *file) +{ + struct video_device *dev = video_devdata(file); + int err = 0; + cam_data *cam = video_get_drvdata(dev); + struct sensor_data *sensor; + + pr_debug("In MVC:%s\n", __func__); + + if (!cam) { + pr_err("%s: Internal error, cam_data not found!\n", __func__); + return -EBADF; + } + + if (!cam->sensor) { + pr_err("%s: Internal error, camera is not found!\n", __func__); + return -EBADF; + } + + sensor = cam->sensor->priv; + if (!sensor) { + pr_err("%s: Internal error, sensor_data is not found!\n", __func__); + return -EBADF; + } + + /* for the case somebody hit the ctrl C */ + if (cam->overlay_pid == current->pid) { + err = stop_preview(cam); + cam->overlay_on = false; + } + + if (--cam->open_count == 0) { + wait_event_interruptible(cam->power_queue, + cam->low_power == false); + file->private_data = NULL; + vidioc_int_s_power(cam->sensor, 0); + clk_disable_unprepare(sensor->sensor_clk); + } + + return err; +} + +/* + * V4L interface - read function + * + * @param file struct file * + * @param read buf char * + * @param count size_t + * @param ppos structure loff_t * + * + * @return bytes read + */ +static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int err = 0; + struct video_device *dev = video_devdata(file); + cam_data *cam = video_get_drvdata(dev); + + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + /* Stop the viewfinder */ + if (cam->overlay_on == true) + stop_preview(cam); + + if (cam->still_buf_vaddr == NULL) { + cam->still_buf_vaddr = dma_alloc_coherent(0, + PAGE_ALIGN + (cam->v2f.fmt. + pix.sizeimage), + &cam-> + still_buf[0], + GFP_DMA | GFP_KERNEL); + if (cam->still_buf_vaddr == NULL) { + pr_err("alloc dma memory failed\n"); + return -ENOMEM; + } + cam->still_counter = 0; + __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB2); + __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB1); + __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, + CSI_CSICR3); + __raw_writel(__raw_readl(CSI_CSISR), CSI_CSISR); + __raw_writel(__raw_readl(CSI_CSICR3) | BIT_FRMCNT_RST, + CSI_CSICR3); + csi_enable_int(1); + } + + wait_event_interruptible(cam->still_queue, cam->still_counter); + csi_disable_int(); + err = copy_to_user(buf, cam->still_buf_vaddr, + cam->v2f.fmt.pix.sizeimage); + + if (cam->still_buf_vaddr != NULL) { + dma_free_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + cam->still_buf_vaddr, cam->still_buf[0]); + cam->still_buf[0] = 0; + cam->still_buf_vaddr = NULL; + } + + if (cam->overlay_on == true) + start_preview(cam); + + up(&cam->busy_lock); + if (err < 0) + return err; + + return cam->v2f.fmt.pix.sizeimage - err; +} + +/*! + * V4L interface - ioctl function + * + * @param file struct file* + * + * @param ioctlnr unsigned int + * + * @param arg void* + * + * @return 0 success, ENODEV for invalid device instance, + * -1 for other errors. + */ +static long csi_v4l_do_ioctl(struct file *file, + unsigned int ioctlnr, void *arg) +{ + struct video_device *dev = video_devdata(file); + cam_data *cam = video_get_drvdata(dev); + int retval = 0; + unsigned long lock_flags; + + pr_debug("In MVC: %s, %x\n", __func__, ioctlnr); + wait_event_interruptible(cam->power_queue, cam->low_power == false); + /* make this _really_ smp-safe */ + if (ioctlnr != VIDIOC_DQBUF) + if (down_interruptible(&cam->busy_lock)) + return -EBUSY; + + switch (ioctlnr) { + /*! + * V4l2 VIDIOC_G_FMT ioctl + */ + case VIDIOC_G_FMT:{ + struct v4l2_format *gf = arg; + pr_debug(" case VIDIOC_G_FMT\n"); + retval = csi_v4l2_g_fmt(cam, gf); + break; + } + + /*! + * V4l2 VIDIOC_S_FMT ioctl + */ + case VIDIOC_S_FMT:{ + struct v4l2_format *sf = arg; + pr_debug(" case VIDIOC_S_FMT\n"); + retval = csi_v4l2_s_fmt(cam, sf); + vidioc_int_s_fmt_cap(cam->sensor, sf); + break; + } + + /*! + * V4l2 VIDIOC_OVERLAY ioctl + */ + case VIDIOC_OVERLAY:{ + int *on = arg; + pr_debug(" case VIDIOC_OVERLAY\n"); + if (*on) { + cam->overlay_on = true; + cam->overlay_pid = current->pid; + start_preview(cam); + } + if (!*on) { + stop_preview(cam); + cam->overlay_on = false; + } + break; + } + + /*! + * V4l2 VIDIOC_G_FBUF ioctl + */ + case VIDIOC_G_FBUF:{ + struct v4l2_framebuffer *fb = arg; + *fb = cam->v4l2_fb; + fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY; + break; + } + + /*! + * V4l2 VIDIOC_S_FBUF ioctl + */ + case VIDIOC_S_FBUF:{ + struct v4l2_framebuffer *fb = arg; + cam->v4l2_fb = *fb; + break; + } + + case VIDIOC_G_PARM:{ + struct v4l2_streamparm *parm = arg; + pr_debug(" case VIDIOC_G_PARM\n"); + vidioc_int_g_parm(cam->sensor, parm); + break; + } + + case VIDIOC_S_PARM:{ + struct v4l2_streamparm *parm = arg; + pr_debug(" case VIDIOC_S_PARM\n"); + retval = csi_v4l2_s_param(cam, parm); + break; + } + + case VIDIOC_QUERYCAP:{ + struct v4l2_capability *cap = arg; + pr_debug(" case VIDIOC_QUERYCAP\n"); + strcpy(cap->driver, "csi_v4l2"); + cap->version = KERNEL_VERSION(0, 1, 11); + cap->capabilities = V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_READWRITE; + cap->card[0] = '\0'; + cap->bus_info[0] = '\0'; + break; + } + + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *cap = arg; + + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { + retval = -EINVAL; + break; + } + cap->bounds = cam->crop_bounds; + cap->defrect = cam->crop_defrect; + break; + } + case VIDIOC_S_CROP: + { + struct v4l2_crop *crop = arg; + struct v4l2_rect *b = &cam->crop_bounds; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + retval = -EINVAL; + break; + } + + crop->c.top = (crop->c.top < b->top) ? b->top + : crop->c.top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height - 1; + if (crop->c.height > b->top + b->height - crop->c.top) + crop->c.height = + b->top + b->height - crop->c.top; + + crop->c.left = (crop->c.left < b->left) ? b->left + : crop->c.left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width - 1; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = + b->left - crop->c.left + b->width; + + crop->c.width -= crop->c.width % 8; + crop->c.height -= crop->c.height % 8; + + crop_current.c = crop->c; + + break; + } + case VIDIOC_G_CROP: + { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + retval = -EINVAL; + break; + } + crop->c = crop_current.c; + + break; + + } + case VIDIOC_REQBUFS: { + struct v4l2_requestbuffers *req = arg; + pr_debug(" case VIDIOC_REQBUFS\n"); + + if (req->count > FRAME_NUM) { + pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " + "not enough buffers\n"); + req->count = FRAME_NUM; + } + + if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " + "wrong buffer type\n"); + retval = -EINVAL; + break; + } + + csi_streamoff(cam); + if (req->memory & V4L2_MEMORY_MMAP) { + csi_free_frame_buf(cam); + retval = csi_allocate_frame_buf(cam, req->count + 1); + req_buf_number = req->count; + } + break; + } + + case VIDIOC_QUERYBUF: { + struct v4l2_buffer *buf = arg; + int index = buf->index; + pr_debug(" case VIDIOC_QUERYBUF\n"); + + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + retval = -EINVAL; + break; + } + + if (buf->memory & V4L2_MEMORY_MMAP) { + memset(buf, 0, sizeof(buf)); + buf->index = index; + } + + down(&cam->param_lock); + if (buf->memory & V4L2_MEMORY_USERPTR) { + csi_v4l2_release_bufs(cam); + retval = csi_v4l2_prepare_bufs(cam, buf); + } + if (buf->memory & V4L2_MEMORY_MMAP) + retval = csi_v4l2_buffer_status(cam, buf); + up(&cam->param_lock); + break; + } + + case VIDIOC_QBUF: { + struct v4l2_buffer *buf = arg; + int index = buf->index; + pr_debug(" case VIDIOC_QBUF\n"); + + spin_lock_irqsave(&cam->queue_int_lock, lock_flags); + cam->frame[index].buffer.m.offset = buf->m.offset; + if ((cam->frame[index].buffer.flags & 0x7) == + V4L2_BUF_FLAG_MAPPED) { + cam->frame[index].buffer.flags |= V4L2_BUF_FLAG_QUEUED; + list_add_tail(&cam->frame[index].queue, &cam->ready_q); + } else if (cam->frame[index].buffer.flags & + V4L2_BUF_FLAG_QUEUED) { + pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " + "buffer already queued\n"); + retval = -EINVAL; + } else if (cam->frame[index].buffer. + flags & V4L2_BUF_FLAG_DONE) { + pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " + "overwrite done buffer.\n"); + cam->frame[index].buffer.flags &= + ~V4L2_BUF_FLAG_DONE; + cam->frame[index].buffer.flags |= + V4L2_BUF_FLAG_QUEUED; + retval = -EINVAL; + } + buf->flags = cam->frame[index].buffer.flags; + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); + + break; + } + + case VIDIOC_DQBUF: { + struct v4l2_buffer *buf = arg; + pr_debug(" case VIDIOC_DQBUF\n"); + + retval = csi_v4l_dqueue(cam, buf); + + break; + } + + case VIDIOC_STREAMON: { + pr_debug(" case VIDIOC_STREAMON\n"); + retval = csi_streamon(cam); + break; + } + + case VIDIOC_STREAMOFF: { + pr_debug(" case VIDIOC_STREAMOFF\n"); + retval = csi_streamoff(cam); + break; + } + case VIDIOC_ENUM_FMT: { + struct v4l2_fmtdesc *fmt = arg; + if (cam->sensor) + retval = vidioc_int_enum_fmt_cap(cam->sensor, fmt); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + case VIDIOC_ENUM_FRAMESIZES: { + struct v4l2_frmsizeenum *fsize = arg; + if (cam->sensor) + retval = vidioc_int_enum_framesizes(cam->sensor, fsize); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + case VIDIOC_ENUM_FRAMEINTERVALS: { + struct v4l2_frmivalenum *fival = arg; + if (cam->sensor) + retval = vidioc_int_enum_frameintervals(cam->sensor, + fival); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + case VIDIOC_DBG_G_CHIP_IDENT: { + struct v4l2_dbg_chip_ident *p = arg; + p->ident = V4L2_IDENT_NONE; + p->revision = 0; + if (cam->sensor) + retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + + case VIDIOC_S_CTRL: + { + struct v4l2_control *vc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (vc->id == pxp_controls[i].id) { + if (vc->value < pxp_controls[i].minimum || + vc->value > pxp_controls[i].maximum) { + retval = -ERANGE; + break; + } + retval = pxp_set_cstate(cam, vc); + break; + } + + if (i >= ARRAY_SIZE(pxp_controls)) + retval = -EINVAL; + break; + + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *vc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (vc->id == pxp_controls[i].id) { + retval = pxp_get_cstate(cam, vc); + break; + } + + if (i >= ARRAY_SIZE(pxp_controls)) + retval = -EINVAL; + break; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (qc->id && qc->id == pxp_controls[i].id) { + memcpy(qc, &(pxp_controls[i]), sizeof(*qc)); + break; + } + + if (i >= ARRAY_SIZE(pxp_controls)) + retval = -EINVAL; + break; + } + case VIDIOC_G_STD: + case VIDIOC_G_OUTPUT: + case VIDIOC_S_OUTPUT: + case VIDIOC_ENUMSTD: + case VIDIOC_S_STD: + case VIDIOC_TRY_FMT: + case VIDIOC_ENUMINPUT: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_ENUMOUTPUT: + default: + pr_debug(" case not supported\n"); + retval = -EINVAL; + break; + } + + if (ioctlnr != VIDIOC_DQBUF) + up(&cam->busy_lock); + return retval; +} + +/* + * V4L interface - ioctl function + * + * @return None + */ +static long csi_v4l_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(file, cmd, arg, csi_v4l_do_ioctl); +} + +/*! + * V4L interface - mmap function + * + * @param file structure file * + * + * @param vma structure vm_area_struct * + * + * @return status 0 Success, EINTR busy lock error, ENOBUFS remap_page error + */ +static int csi_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *dev = video_devdata(file); + unsigned long size; + int res = 0; + cam_data *cam = video_get_drvdata(dev); + + pr_debug("%s\n", __func__); + pr_debug("\npgoff=0x%lx, start=0x%lx, end=0x%lx\n", + vma->vm_pgoff, vma->vm_start, vma->vm_end); + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + size = vma->vm_end - vma->vm_start; + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + if (remap_pfn_range(vma, vma->vm_start, + vma->vm_pgoff, size, vma->vm_page_prot)) { + pr_err("ERROR: v4l2 capture: %s : " + "remap_pfn_range failed\n", __func__); + res = -ENOBUFS; + goto csi_mmap_exit; + } + + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ + +csi_mmap_exit: + up(&cam->busy_lock); + return res; +} + +/*! + * This structure defines the functions to be called in this driver. + */ +static struct v4l2_file_operations csi_v4l_fops = { + .owner = THIS_MODULE, + .open = csi_v4l_open, + .release = csi_v4l_close, + .read = csi_v4l_read, + .ioctl = csi_v4l_ioctl, + .mmap = csi_mmap, +}; + +static struct video_device csi_v4l_template = { + .name = "Mx25 Camera", + .fops = &csi_v4l_fops, + .release = video_device_release, +}; + +/*! + * initialize cam_data structure + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static void init_camera_struct(cam_data *cam) +{ + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + pr_debug("In MVC: %s\n", __func__); + + proc_data->hflip = 0; + proc_data->vflip = 0; + proc_data->rotate = 0; + proc_data->bgcolor = 0; + + /* Default everything to 0 */ + memset(cam, 0, sizeof(cam_data)); + + sema_init(&cam->param_lock, 1); + sema_init(&cam->busy_lock, 1); + + cam->video_dev = video_device_alloc(); + if (cam->video_dev == NULL) + return; + + *(cam->video_dev) = csi_v4l_template; + + video_set_drvdata(cam->video_dev, cam); + cam->video_dev->minor = -1; + + init_waitqueue_head(&cam->enc_queue); + init_waitqueue_head(&cam->still_queue); + + cam->streamparm.parm.capture.capturemode = 0; + + cam->standard.index = 0; + cam->standard.id = V4L2_STD_UNKNOWN; + cam->standard.frameperiod.denominator = 30; + cam->standard.frameperiod.numerator = 1; + cam->standard.framelines = 480; + cam->standard_autodetect = true; + cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod; + cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + cam->overlay_on = false; + cam->capture_on = false; + cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY; + + cam->v2f.fmt.pix.sizeimage = 480 * 640 * 2; + cam->v2f.fmt.pix.bytesperline = 640 * 2; + cam->v2f.fmt.pix.width = 640; + cam->v2f.fmt.pix.height = 480; + cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + cam->win.w.width = 160; + cam->win.w.height = 160; + cam->win.w.left = 0; + cam->win.w.top = 0; + cam->still_counter = 0; + /* setup cropping */ + cam->crop_bounds.left = 0; + cam->crop_bounds.width = 640; + cam->crop_bounds.top = 0; + cam->crop_bounds.height = 480; + cam->crop_current = cam->crop_defrect = cam->crop_bounds; + + cam->enc_callback = camera_callback; + csi_start_callback(cam); + init_waitqueue_head(&cam->power_queue); + spin_lock_init(&cam->queue_int_lock); + spin_lock_init(&cam->dqueue_int_lock); +} + +/*! + * camera_power function + * Turns Sensor power On/Off + * + * @param cam cam data struct + * @param cameraOn true to turn camera on, false to turn off power. + * + * @return status + */ +static u8 camera_power(cam_data *cam, bool cameraOn) +{ + pr_debug("In MVC: %s on=%d\n", __func__, cameraOn); + + if (cameraOn == true) { + vidioc_int_s_power(cam->sensor, 1); + } else { + vidioc_int_s_power(cam->sensor, 0); + } + return 0; +} + +static const struct of_device_id imx_csi_v4l2_dt_ids[] = { + { .compatible = "fsl,imx6sl-csi-v4l2", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_csi_v4l2_dt_ids); + +static int csi_v4l2_probe(struct platform_device *pdev) +{ + struct scatterlist *sg; + u8 err = 0; + + /* Create g_cam and initialize it. */ + g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL); + if (g_cam == NULL) { + pr_err("ERROR: v4l2 capture: failed to register camera\n"); + err = -ENOMEM; + goto out; + } + memset(&crop_current, 0, sizeof(crop_current)); + memset(&win_current, 0, sizeof(win_current)); + init_camera_struct(g_cam); + platform_set_drvdata(pdev, (void *)g_cam); + + /* Set up the v4l2 device and register it */ + csi_v4l2_int_device.priv = g_cam; + /* This function contains a bug that won't let this be rmmod'd. */ + v4l2_int_device_register(&csi_v4l2_int_device); + + /* register v4l video device */ + if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr) + == -1) { + kfree(g_cam); + g_cam = NULL; + pr_err("ERROR: v4l2 capture: video_register_device failed\n"); + err = -ENODEV; + goto out; + } + pr_debug(" Video device registered: %s #%d\n", + g_cam->video_dev->name, g_cam->video_dev->minor); + + g_cam->pxp_chan = NULL; + /* Initialize Scatter-gather list containing 2 buffer addresses. */ + sg = g_cam->sg; + sg_init_table(sg, 2); + +out: + return err; +} + +static int csi_v4l2_remove(struct platform_device *pdev) +{ + if (g_cam->open_count) { + pr_err("ERROR: v4l2 capture:camera open " + "-- setting ops to NULL\n"); + } else { + pr_info("V4L2 freeing image input device\n"); + v4l2_int_device_unregister(&csi_v4l2_int_device); + csi_stop_callback(g_cam); + video_unregister_device(g_cam->video_dev); + platform_set_drvdata(pdev, NULL); + + kfree(g_cam); + g_cam = NULL; + } + + return 0; +} + +/*! + * This function is called to put the sensor in a low power state. + * Refer to the document driver-model/driver.txt in the kernel source tree + * for more information. + * + * @param pdev the device structure used to give information on which I2C + * to suspend + * @param state the power state the device is entering + * + * @return The function returns 0 on success and -1 on failure. + */ +static int csi_v4l2_suspend(struct platform_device *pdev, pm_message_t state) +{ + cam_data *cam = platform_get_drvdata(pdev); + + pr_debug("In MVC: %s\n", __func__); + + if (cam == NULL) + return -1; + + cam->low_power = true; + + if (cam->overlay_on == true) + stop_preview(cam); + + if (cam->capture_on == true || cam->overlay_on == true) + camera_power(cam, false); + + return 0; +} + +/*! + * This function is called to bring the sensor back from a low power state. + * Refer to the document driver-model/driver.txt in the kernel source tree + * for more information. + * + * @param pdev the device structure + * + * @return The function returns 0 on success and -1 on failure + */ +static int csi_v4l2_resume(struct platform_device *pdev) +{ + cam_data *cam = platform_get_drvdata(pdev); + + pr_debug("In MVC: %s\n", __func__); + + if (cam == NULL) + return -1; + + cam->low_power = false; + wake_up_interruptible(&cam->power_queue); + if (cam->capture_on == true || cam->overlay_on == true) + camera_power(cam, true); + + if (cam->overlay_on == true) + start_preview(cam); + + return 0; +} + +/*! + * This structure contains pointers to the power management callback functions. + */ +static struct platform_driver csi_v4l2_driver = { + .driver = { + .name = "csi_v4l2", + .of_match_table = of_match_ptr(imx_csi_v4l2_dt_ids), + }, + .probe = csi_v4l2_probe, + .remove = csi_v4l2_remove, +#ifdef CONFIG_PM + .suspend = csi_v4l2_suspend, + .resume = csi_v4l2_resume, +#endif + .shutdown = NULL, +}; + +/*! + * Initializes the camera driver. + */ +static int csi_v4l2_master_attach(struct v4l2_int_device *slave) +{ + cam_data *cam = slave->u.slave->master->priv; + struct v4l2_format cam_fmt; + + pr_debug("In MVC: %s\n", __func__); + pr_debug(" slave.name = %s\n", slave->name); + pr_debug(" master.name = %s\n", slave->u.slave->master->name); + + cam->sensor = slave; + if (slave == NULL) { + pr_err("ERROR: v4l2 capture: slave parameter not valid.\n"); + return -1; + } + + cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); + + /* Used to detect TV in (type 1) vs. camera (type 0) */ + cam->device_type = cam_fmt.fmt.pix.priv; + + cam->crop_bounds.top = cam->crop_bounds.left = 0; + cam->crop_bounds.width = cam_fmt.fmt.pix.width; + cam->crop_bounds.height = cam_fmt.fmt.pix.height; + + /* This also is the max crop size for this device. */ + cam->crop_defrect.top = cam->crop_defrect.left = 0; + cam->crop_defrect.width = cam_fmt.fmt.pix.width; + cam->crop_defrect.height = cam_fmt.fmt.pix.height; + + /* At this point, this is also the current image size. */ + cam->crop_current.top = cam->crop_current.left = 0; + cam->crop_current.width = cam_fmt.fmt.pix.width; + cam->crop_current.height = cam_fmt.fmt.pix.height; + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + + return 0; +} + +/*! + * Disconnects the camera driver. + */ +static void csi_v4l2_master_detach(struct v4l2_int_device *slave) +{ + pr_debug("In MVC: %s\n", __func__); + + vidioc_int_dev_exit(slave); +} + +module_platform_driver(csi_v4l2_driver); + +module_param(video_nr, int, 0444); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("V4L2 capture driver for Mx25 based cameras"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("video"); diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/capture/fsl_csi.c linux-4.1.13/drivers/media/platform/mxc/capture/fsl_csi.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/fsl_csi.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/fsl_csi.c 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,302 @@ +/* + * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file fsl_csi.c, this file is derived from mx27_csi.c + * + * @brief mx25 CMOS Sensor interface functions + * + * @ingroup CSI + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mxc_v4l2_capture.h" +#include "fsl_csi.h" + +void __iomem *csi_regbase; +EXPORT_SYMBOL(csi_regbase); +static int irq_nr; +static csi_irq_callback_t g_callback; +static void *g_callback_data; + +static irqreturn_t csi_irq_handler(int irq, void *data) +{ + cam_data *cam = (cam_data *) data; + unsigned long status = __raw_readl(CSI_CSISR); + + __raw_writel(status, CSI_CSISR); + + if (status & BIT_HRESP_ERR_INT) + pr_warning("Hresponse error is detected.\n"); + + if (status & BIT_DMA_TSF_DONE_FB1) { + if (cam->capture_on) { + spin_lock(&cam->queue_int_lock); + cam->ping_pong_csi = 1; + spin_unlock(&cam->queue_int_lock); + cam->enc_callback(0, cam); + } else { + cam->still_counter++; + wake_up_interruptible(&cam->still_queue); + } + } + + if (status & BIT_DMA_TSF_DONE_FB2) { + if (cam->capture_on) { + spin_lock(&cam->queue_int_lock); + cam->ping_pong_csi = 2; + spin_unlock(&cam->queue_int_lock); + cam->enc_callback(0, cam); + } else { + cam->still_counter++; + wake_up_interruptible(&cam->still_queue); + } + } + + if (g_callback) + g_callback(g_callback_data, status); + + pr_debug("CSI status = 0x%08lX\n", status); + + return IRQ_HANDLED; +} + +static void csihw_reset_frame_count(void) +{ + __raw_writel(__raw_readl(CSI_CSICR3) | BIT_FRMCNT_RST, CSI_CSICR3); +} + +static void csihw_reset(void) +{ + csihw_reset_frame_count(); + __raw_writel(CSICR1_RESET_VAL, CSI_CSICR1); + __raw_writel(CSICR2_RESET_VAL, CSI_CSICR2); + __raw_writel(CSICR3_RESET_VAL, CSI_CSICR3); +} + +/*! + * csi_init_interface + * Init csi interface + */ +void csi_init_interface(void) +{ + unsigned int val = 0; + unsigned int imag_para; + + val |= BIT_SOF_POL; + val |= BIT_REDGE; + val |= BIT_GCLK_MODE; + val |= BIT_HSYNC_POL; + val |= BIT_PACK_DIR; + val |= BIT_FCC; + val |= BIT_SWAP16_EN; + val |= 1 << SHIFT_MCLKDIV; + val |= BIT_MCLKEN; + __raw_writel(val, CSI_CSICR1); + + imag_para = (640 << 16) | 960; + __raw_writel(imag_para, CSI_CSIIMAG_PARA); + + val = 0x1010; + val |= BIT_DMA_REFLASH_RFF; + __raw_writel(val, CSI_CSICR3); +} +EXPORT_SYMBOL(csi_init_interface); + +void csi_init_format(int fmt) +{ + unsigned int val; + + val = __raw_readl(CSI_CSICR1); + if (fmt == V4L2_PIX_FMT_YUYV) { + val &= ~BIT_PACK_DIR; + val &= ~BIT_SWAP16_EN; + } else if (fmt == V4L2_PIX_FMT_UYVY) { + val |= BIT_PACK_DIR; + val |= BIT_SWAP16_EN; + } else + pr_warning("unsupported format, old format remains.\n"); + + __raw_writel(val, CSI_CSICR1); +} +EXPORT_SYMBOL(csi_init_format); + +/*! + * csi_read_mclk_flag + * + * @return gcsi_mclk_source + */ +int csi_read_mclk_flag(void) +{ + return 0; +} +EXPORT_SYMBOL(csi_read_mclk_flag); + +void csi_start_callback(void *data) +{ + cam_data *cam = (cam_data *) data; + + if (request_irq(irq_nr, csi_irq_handler, 0, "csi", cam) < 0) + pr_debug("CSI error: irq request fail\n"); + +} +EXPORT_SYMBOL(csi_start_callback); + +void csi_stop_callback(void *data) +{ + cam_data *cam = (cam_data *) data; + + free_irq(irq_nr, cam); +} +EXPORT_SYMBOL(csi_stop_callback); + +void csi_enable_int(int arg) +{ + unsigned long cr1 = __raw_readl(CSI_CSICR1); + + cr1 |= BIT_SOF_INTEN; + if (arg == 1) { + /* still capture needs DMA intterrupt */ + cr1 |= BIT_FB1_DMA_DONE_INTEN; + cr1 |= BIT_FB2_DMA_DONE_INTEN; + } + __raw_writel(cr1, CSI_CSICR1); +} +EXPORT_SYMBOL(csi_enable_int); + +void csi_disable_int(void) +{ + unsigned long cr1 = __raw_readl(CSI_CSICR1); + + cr1 &= ~BIT_SOF_INTEN; + cr1 &= ~BIT_FB1_DMA_DONE_INTEN; + cr1 &= ~BIT_FB2_DMA_DONE_INTEN; + __raw_writel(cr1, CSI_CSICR1); +} +EXPORT_SYMBOL(csi_disable_int); + +void csi_set_16bit_imagpara(int width, int height) +{ + int imag_para = 0; + unsigned long cr3 = __raw_readl(CSI_CSICR3); + + imag_para = (width << 16) | (height * 2); + __raw_writel(imag_para, CSI_CSIIMAG_PARA); + + /* reflash the embeded DMA controller */ + __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, CSI_CSICR3); +} +EXPORT_SYMBOL(csi_set_16bit_imagpara); + +void csi_set_12bit_imagpara(int width, int height) +{ + int imag_para = 0; + unsigned long cr3 = __raw_readl(CSI_CSICR3); + + imag_para = (width << 16) | (height * 3 / 2); + __raw_writel(imag_para, CSI_CSIIMAG_PARA); + + /* reflash the embeded DMA controller */ + __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, CSI_CSICR3); +} +EXPORT_SYMBOL(csi_set_12bit_imagpara); + +void csi_dmareq_rff_enable(void) +{ + unsigned long cr3 = __raw_readl(CSI_CSICR3); + + cr3 |= BIT_DMA_REQ_EN_RFF; + cr3 |= BIT_HRESP_ERR_EN; + __raw_writel(cr3, CSI_CSICR3); +} +EXPORT_SYMBOL(csi_dmareq_rff_enable); + +void csi_dmareq_rff_disable(void) +{ + unsigned long cr3 = __raw_readl(CSI_CSICR3); + + cr3 &= ~BIT_DMA_REQ_EN_RFF; + cr3 &= ~BIT_HRESP_ERR_EN; + __raw_writel(cr3, CSI_CSICR3); +} +EXPORT_SYMBOL(csi_dmareq_rff_disable); + +static const struct of_device_id fsl_csi_dt_ids[] = { + { .compatible = "fsl,imx6sl-csi", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_csi_dt_ids); + +static int csi_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "No csi irq found.\n"); + ret = -ENODEV; + goto err; + } + irq_nr = res->start; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "No csi base address found.\n"); + ret = -ENODEV; + goto err; + } + csi_regbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!csi_regbase) { + dev_err(&pdev->dev, "ioremap failed with csi base\n"); + ret = -ENOMEM; + goto err; + } + + csihw_reset(); + csi_init_interface(); + csi_dmareq_rff_disable(); + +err: + return ret; +} + +static int csi_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver csi_driver = { + .driver = { + .name = "fsl_csi", + .of_match_table = of_match_ptr(fsl_csi_dt_ids), + }, + .probe = csi_probe, + .remove = csi_remove, +}; + +module_platform_driver(csi_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("fsl CSI driver"); +MODULE_LICENSE("GPL"); diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/capture/fsl_csi.h linux-4.1.13/drivers/media/platform/mxc/capture/fsl_csi.h --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/fsl_csi.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/fsl_csi.h 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,198 @@ +/* + * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file fsl_csi.h + * + * @brief mx25 CMOS Sensor interface functions + * + * @ingroup CSI + */ + +#ifndef MX25_CSI_H +#define MX25_CSI_H + +#include + +/* reset values */ +#define CSICR1_RESET_VAL 0x40000800 +#define CSICR2_RESET_VAL 0x0 +#define CSICR3_RESET_VAL 0x0 + +/* csi control reg 1 */ +#define BIT_SWAP16_EN (0x1 << 31) +#define BIT_EXT_VSYNC (0x1 << 30) +#define BIT_EOF_INT_EN (0x1 << 29) +#define BIT_PRP_IF_EN (0x1 << 28) +#define BIT_CCIR_MODE (0x1 << 27) +#define BIT_COF_INT_EN (0x1 << 26) +#define BIT_SF_OR_INTEN (0x1 << 25) +#define BIT_RF_OR_INTEN (0x1 << 24) +#define BIT_SFF_DMA_DONE_INTEN (0x1 << 22) +#define BIT_STATFF_INTEN (0x1 << 21) +#define BIT_FB2_DMA_DONE_INTEN (0x1 << 20) +#define BIT_FB1_DMA_DONE_INTEN (0x1 << 19) +#define BIT_RXFF_INTEN (0x1 << 18) +#define BIT_SOF_POL (0x1 << 17) +#define BIT_SOF_INTEN (0x1 << 16) +#define BIT_MCLKDIV (0xF << 12) +#define BIT_HSYNC_POL (0x1 << 11) +#define BIT_CCIR_EN (0x1 << 10) +#define BIT_MCLKEN (0x1 << 9) +#define BIT_FCC (0x1 << 8) +#define BIT_PACK_DIR (0x1 << 7) +#define BIT_CLR_STATFIFO (0x1 << 6) +#define BIT_CLR_RXFIFO (0x1 << 5) +#define BIT_GCLK_MODE (0x1 << 4) +#define BIT_INV_DATA (0x1 << 3) +#define BIT_INV_PCLK (0x1 << 2) +#define BIT_REDGE (0x1 << 1) +#define BIT_PIXEL_BIT (0x1 << 0) + +#define SHIFT_MCLKDIV 12 + +/* control reg 3 */ +#define BIT_FRMCNT (0xFFFF << 16) +#define BIT_FRMCNT_RST (0x1 << 15) +#define BIT_DMA_REFLASH_RFF (0x1 << 14) +#define BIT_DMA_REFLASH_SFF (0x1 << 13) +#define BIT_DMA_REQ_EN_RFF (0x1 << 12) +#define BIT_DMA_REQ_EN_SFF (0x1 << 11) +#define BIT_STATFF_LEVEL (0x7 << 8) +#define BIT_HRESP_ERR_EN (0x1 << 7) +#define BIT_RXFF_LEVEL (0x7 << 4) +#define BIT_TWO_8BIT_SENSOR (0x1 << 3) +#define BIT_ZERO_PACK_EN (0x1 << 2) +#define BIT_ECC_INT_EN (0x1 << 1) +#define BIT_ECC_AUTO_EN (0x1 << 0) + +#define SHIFT_FRMCNT 16 + +/* csi status reg */ +#define BIT_SFF_OR_INT (0x1 << 25) +#define BIT_RFF_OR_INT (0x1 << 24) +#define BIT_DMA_TSF_DONE_SFF (0x1 << 22) +#define BIT_STATFF_INT (0x1 << 21) +#define BIT_DMA_TSF_DONE_FB2 (0x1 << 20) +#define BIT_DMA_TSF_DONE_FB1 (0x1 << 19) +#define BIT_RXFF_INT (0x1 << 18) +#define BIT_EOF_INT (0x1 << 17) +#define BIT_SOF_INT (0x1 << 16) +#define BIT_F2_INT (0x1 << 15) +#define BIT_F1_INT (0x1 << 14) +#define BIT_COF_INT (0x1 << 13) +#define BIT_HRESP_ERR_INT (0x1 << 7) +#define BIT_ECC_INT (0x1 << 1) +#define BIT_DRDY (0x1 << 0) + +#define CSI_MCLK_VF 1 +#define CSI_MCLK_ENC 2 +#define CSI_MCLK_RAW 4 +#define CSI_MCLK_I2C 8 +#endif + +extern void __iomem *csi_regbase; +#define CSI_CSICR1 (csi_regbase) +#define CSI_CSICR2 (csi_regbase + 0x4) +#define CSI_CSICR3 (csi_regbase + 0x8) +#define CSI_STATFIFO (csi_regbase + 0xC) +#define CSI_CSIRXFIFO (csi_regbase + 0x10) +#define CSI_CSIRXCNT (csi_regbase + 0x14) +#define CSI_CSISR (csi_regbase + 0x18) + +#define CSI_CSIDBG (csi_regbase + 0x1C) +#define CSI_CSIDMASA_STATFIFO (csi_regbase + 0x20) +#define CSI_CSIDMATS_STATFIFO (csi_regbase + 0x24) +#define CSI_CSIDMASA_FB1 (csi_regbase + 0x28) +#define CSI_CSIDMASA_FB2 (csi_regbase + 0x2C) +#define CSI_CSIFBUF_PARA (csi_regbase + 0x30) +#define CSI_CSIIMAG_PARA (csi_regbase + 0x34) + +static inline void csi_clear_status(unsigned long status) +{ + __raw_writel(status, CSI_CSISR); +} + +struct csi_signal_cfg_t { + unsigned data_width:3; + unsigned clk_mode:2; + unsigned ext_vsync:1; + unsigned Vsync_pol:1; + unsigned Hsync_pol:1; + unsigned pixclk_pol:1; + unsigned data_pol:1; + unsigned sens_clksrc:1; +}; + +struct csi_config_t { + /* control reg 1 */ + unsigned int swap16_en:1; + unsigned int ext_vsync:1; + unsigned int eof_int_en:1; + unsigned int prp_if_en:1; + unsigned int ccir_mode:1; + unsigned int cof_int_en:1; + unsigned int sf_or_inten:1; + unsigned int rf_or_inten:1; + unsigned int sff_dma_done_inten:1; + unsigned int statff_inten:1; + unsigned int fb2_dma_done_inten:1; + unsigned int fb1_dma_done_inten:1; + unsigned int rxff_inten:1; + unsigned int sof_pol:1; + unsigned int sof_inten:1; + unsigned int mclkdiv:4; + unsigned int hsync_pol:1; + unsigned int ccir_en:1; + unsigned int mclken:1; + unsigned int fcc:1; + unsigned int pack_dir:1; + unsigned int gclk_mode:1; + unsigned int inv_data:1; + unsigned int inv_pclk:1; + unsigned int redge:1; + unsigned int pixel_bit:1; + + /* control reg 3 */ + unsigned int frmcnt:16; + unsigned int frame_reset:1; + unsigned int dma_reflash_rff:1; + unsigned int dma_reflash_sff:1; + unsigned int dma_req_en_rff:1; + unsigned int dma_req_en_sff:1; + unsigned int statff_level:3; + unsigned int hresp_err_en:1; + unsigned int rxff_level:3; + unsigned int two_8bit_sensor:1; + unsigned int zero_pack_en:1; + unsigned int ecc_int_en:1; + unsigned int ecc_auto_en:1; + /* fifo counter */ + unsigned int rxcnt; +}; + +typedef void (*csi_irq_callback_t) (void *data, unsigned long status); + +void csi_init_interface(void); +void csi_init_format(int fmt); +void csi_set_16bit_imagpara(int width, int height); +void csi_set_12bit_imagpara(int width, int height); +int csi_read_mclk_flag(void); +void csi_start_callback(void *data); +void csi_stop_callback(void *data); +void csi_enable_int(int arg); +void csi_disable_int(void); +void csi_mclk_enable(void); +void csi_mclk_disable(void); +void csi_dmareq_rff_enable(void); +void csi_dmareq_rff_disable(void); diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c linux-4.1.13/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 2015-11-30 17:56:13.600136395 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_csi_enc.c linux-4.1.13/drivers/media/platform/mxc/capture/ipu_csi_enc.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_csi_enc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_csi_enc.c 2015-11-30 17:56:13.600136395 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c linux-4.1.13/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 2015-11-30 17:56:13.600136395 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_enc.c linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_enc.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_enc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_enc.c 2015-11-30 17:56:13.600136395 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_sw.h linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_sw.h --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_sw.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_sw.h 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_prp_sw.h + * + * @brief This file contains the IPU PRP use case driver header. + * + * @ingroup IPU + */ + +#ifndef _INCLUDE_IPU__PRP_SW_H_ +#define _INCLUDE_IPU__PRP_SW_H_ + +int csi_enc_select(void *private); +int csi_enc_deselect(void *private); +int prp_enc_select(void *private); +int prp_enc_deselect(void *private); +#ifdef CONFIG_MXC_IPU_PRP_VF_SDC +int prp_vf_sdc_select(void *private); +int prp_vf_sdc_deselect(void *private); +int prp_vf_sdc_select_bg(void *private); +int prp_vf_sdc_deselect_bg(void *private); +#else +int foreground_sdc_select(void *private); +int foreground_sdc_deselect(void *private); +int bg_overlay_sdc_select(void *private); +int bg_overlay_sdc_deselect(void *private); +#endif +int prp_still_select(void *private); +int prp_still_deselect(void *private); + +#endif diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 2015-11-30 17:56:13.600136395 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 2015-11-30 17:56:13.600136395 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_still.c linux-4.1.13/drivers/media/platform/mxc/capture/ipu_still.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ipu_still.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ipu_still.c 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,269 @@ +/* + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_still.c + * + * @brief IPU Use case for still image capture + * + * @ingroup IPU + */ + +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +static int callback_eof_flag; +#ifndef CONFIG_MXC_IPU_V1 +static int buffer_num; +#endif + +#ifdef CONFIG_MXC_IPU_V1 +static int callback_flag; +/* + * Function definitions + */ +/*! + * CSI EOF callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id) +{ + cam_data *cam = devid; + ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, + callback_flag%2 ? 1 : 0); + if (callback_flag == 0) + ipu_enable_channel(cam->ipu, CSI_MEM); + + callback_flag++; + return IRQ_HANDLED; +} +#endif + +/*! + * CSI callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t prp_still_callback(int irq, void *dev_id) +{ + cam_data *cam = (cam_data *) dev_id; + + callback_eof_flag++; + if (callback_eof_flag < 5) { +#ifndef CONFIG_MXC_IPU_V1 + buffer_num = (buffer_num == 0) ? 1 : 0; + ipu_select_buffer(cam->ipu, CSI_MEM, + IPU_OUTPUT_BUFFER, buffer_num); +#endif + } else { + cam->still_counter++; + wake_up_interruptible(&cam->still_queue); + } + + return IRQ_HANDLED; +} + +/*! + * start csi->mem task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_still_start(void *private) +{ + cam_data *cam = (cam_data *) private; + u32 pixel_fmt; + int err; + ipu_channel_params_t params; + + if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) + pixel_fmt = IPU_PIX_FMT_YUV420P; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) + pixel_fmt = IPU_PIX_FMT_NV12; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) + pixel_fmt = IPU_PIX_FMT_YUV422P; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) + pixel_fmt = IPU_PIX_FMT_UYVY; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) + pixel_fmt = IPU_PIX_FMT_YUYV; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) + pixel_fmt = IPU_PIX_FMT_BGR24; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) + pixel_fmt = IPU_PIX_FMT_RGB24; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) + pixel_fmt = IPU_PIX_FMT_RGB565; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) + pixel_fmt = IPU_PIX_FMT_BGR32; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) + pixel_fmt = IPU_PIX_FMT_RGB32; + else { + printk(KERN_ERR "format not supported\n"); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(params)); + err = ipu_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-4.1.13.orig/drivers/media/platform/mxc/capture/Kconfig linux-4.1.13/drivers/media/platform/mxc/capture/Kconfig --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/Kconfig 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,106 @@ +if VIDEO_MXC_CAPTURE + +menu "MXC Camera/V4L2 PRP Features support" +config VIDEO_MXC_IPU_CAMERA + bool + depends on VIDEO_MXC_CAPTURE && MXC_IPU + default y + +config VIDEO_MXC_CSI_CAMERA + tristate "CSI camera support" + depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2 + ---help--- + This is the video4linux2 capture driver based on CSI module. + +config MXC_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 + ---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 !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-4.1.13.orig/drivers/media/platform/mxc/capture/Makefile linux-4.1.13/drivers/media/platform/mxc/capture/Makefile --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/Makefile 2015-11-30 17:56:13.600136395 +0100 @@ -0,0 +1,32 @@ +obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += fsl_csi.o csi_v4l2_capture.o + +ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y) + obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc_v4l2_capture.o + obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o + obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o + obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o + obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o +endif + +ov5640_camera-objs := ov5640.o +obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera.o + +ov5642_camera-objs := ov5642.o +obj-$(CONFIG_MXC_CAMERA_OV5642) += ov5642_camera.o + +ov5640_camera_mipi-objs := ov5640_mipi.o +obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi.o + +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_INT_DEVICE) += v4l2-int-device.o + +tda1997x-video-objs := tda1997x.o +obj-$(CONFIG_MXC_TVIN_TDA1997X) += tda1997x-video.o diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c linux-4.1.13/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 2015-11-30 17:56:13.604136128 +0100 @@ -0,0 +1,3384 @@ +/* + * 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 "../v4l2-extra.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, + .unlocked_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-4.1.13.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h linux-4.1.13/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 2015-11-30 17:56:13.604136128 +0100 @@ -0,0 +1,355 @@ +/* + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup MXC_V4L2_CAPTURE MXC V4L2 Video Capture Driver + */ +/*! + * @file mxc_v4l2_capture.h + * + * @brief mxc V4L2 capture device API Header file + * + * It include all the defines for frame operations, also three structure defines + * use case ops structure, common v4l2 driver structure and frame structure. + * + * @ingroup MXC_V4L2_CAPTURE + */ +#ifndef __MXC_V4L2_CAPTURE_H__ +#define __MXC_V4L2_CAPTURE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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; + 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; + 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-4.1.13.orig/drivers/media/platform/mxc/capture/ov5640.c linux-4.1.13/drivers/media/platform/mxc/capture/ov5640.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ov5640.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ov5640.c 2015-11-30 17:56:13.604136128 +0100 @@ -0,0 +1,1959 @@ +/* + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" + +#define OV5640_VOLTAGE_ANALOG 2800000 +#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5640_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5640_XCLK_MIN 6000000 +#define OV5640_XCLK_MAX 24000000 + +#define OV5640_CHIP_ID_HIGH_BYTE 0x300A +#define OV5640_CHIP_ID_LOW_BYTE 0x300B + +enum ov5640_mode { + ov5640_mode_MIN = 0, + ov5640_mode_VGA_640_480 = 0, + ov5640_mode_QVGA_320_240 = 1, + ov5640_mode_NTSC_720_480 = 2, + ov5640_mode_PAL_720_576 = 3, + ov5640_mode_720P_1280_720 = 4, + ov5640_mode_1080P_1920_1080 = 5, + ov5640_mode_QSXGA_2592_1944 = 6, + ov5640_mode_QCIF_176_144 = 7, + ov5640_mode_XGA_1024_768 = 8, + ov5640_mode_MAX = 8 +}; + +enum ov5640_frame_rate { + ov5640_15_fps, + ov5640_30_fps +}; + +static int ov5640_framerates[] = { + [ov5640_15_fps] = 15, + [ov5640_30_fps] = 30, +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5640_mode_info { + enum ov5640_mode mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +/*! + * Maintains the information on the current state of the sesor. + */ +static struct sensor_data ov5640_data; +static int pwn_gpio, rst_gpio; +static int prev_sysclk; +static int AE_Target = 52, night_mode; +static int prev_HTS; +static int AE_high, AE_low; + +static struct reg_value ov5640_global_init_setting[] = { + {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, + {0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, + {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, + {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, + {0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, + {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, + {0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, + {0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, + {0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, + {0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, + {0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, + {0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, + {0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0}, + {0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, + {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0}, + {0x3008, 0x02, 0, 0}, +}; + +static struct reg_value ov5640_init_setting_30fps_VGA[] = { + {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, + {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0}, + {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, + {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, + {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, + {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, + {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, + {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, + {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, + {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, + {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, + {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0}, + {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0}, + {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0}, + {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0}, + {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0}, + {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0}, + {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0}, + {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0}, + {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0}, + {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0}, + {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0}, + {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0}, + {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0}, + {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0}, + {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0}, + {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0}, + {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0}, + {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0}, + {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0}, + {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0}, + {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0}, + {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0}, + {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0}, + {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0}, + {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0}, + {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0}, + {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0}, + {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0}, + {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0}, + {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0}, + {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0}, + {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0}, + {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0}, + {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0}, + {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0}, + {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0}, + {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0}, + {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0}, + {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0}, + {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0}, + {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0}, + {0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, + {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, + {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { + {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, + {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { + {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, + {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, + {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, + {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + + +static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { + {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0}, + {0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0}, + {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, + {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, + {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, + {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { + {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, + {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, + {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, + {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, + {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, + {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { + { + {ov5640_mode_VGA_640_480, 640, 480, + ov5640_setting_15fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, 320, 240, + ov5640_setting_15fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, 720, 480, + ov5640_setting_15fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, 720, 576, + ov5640_setting_15fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, 1280, 720, + ov5640_setting_15fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, 1920, 1080, + ov5640_setting_15fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, 2592, 1944, + ov5640_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, + {ov5640_mode_QCIF_176_144, 176, 144, + ov5640_setting_15fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, 1024, 768, + ov5640_setting_15fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, + }, + { + {ov5640_mode_VGA_640_480, 640, 480, + ov5640_setting_30fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, 320, 240, + ov5640_setting_30fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, 720, 480, + ov5640_setting_30fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, 720, 576, + ov5640_setting_30fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, 1280, 720, + ov5640_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0}, + {ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0}, + {ov5640_mode_QCIF_176_144, 176, 144, + ov5640_setting_30fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, 1024, 768, + ov5640_setting_30fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; + +static int ov5640_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5640_remove(struct i2c_client *client); + +static s32 ov5640_read_reg(u16 reg, u8 *val); +static s32 ov5640_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5640_id[] = { + {"ov5640", 0}, + {"ov564x", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5640_id); + +static struct i2c_driver ov5640_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov5640", + }, + .probe = ov5640_probe, + .remove = ov5640_remove, + .id_table = ov5640_id, +}; + +static inline void ov5640_power_down(int enable) +{ + gpio_set_value(pwn_gpio, enable); + + msleep(2); +} + +static inline void ov5640_reset(void) +{ + /* camera reset */ + gpio_set_value(rst_gpio, 1); + + /* camera power down */ + gpio_set_value(pwn_gpio, 1); + msleep(5); + gpio_set_value(pwn_gpio, 0); + msleep(5); + gpio_set_value(rst_gpio, 0); + msleep(1); + gpio_set_value(rst_gpio, 1); + msleep(5); + gpio_set_value(pwn_gpio, 1); +} + +static int ov5640_regulator_enable(struct device *dev) +{ + int ret = 0; + + io_regulator = devm_regulator_get(dev, "DOVDD"); + if (!IS_ERR(io_regulator)) { + regulator_set_voltage(io_regulator, + OV5640_VOLTAGE_DIGITAL_IO, + OV5640_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(io_regulator); + if (ret) { + dev_err(dev, "set io voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set io voltage ok\n"); + } + } else { + io_regulator = NULL; + dev_warn(dev, "cannot get io voltage\n"); + } + + core_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(core_regulator)) { + regulator_set_voltage(core_regulator, + OV5640_VOLTAGE_DIGITAL_CORE, + OV5640_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(core_regulator); + if (ret) { + dev_err(dev, "set core voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set core voltage ok\n"); + } + } else { + core_regulator = NULL; + dev_warn(dev, "cannot get core voltage\n"); + } + + analog_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(analog_regulator)) { + regulator_set_voltage(analog_regulator, + OV5640_VOLTAGE_ANALOG, + OV5640_VOLTAGE_ANALOG); + ret = regulator_enable(analog_regulator); + if (ret) { + dev_err(dev, "set analog voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set analog voltage ok\n"); + } + } else { + analog_regulator = NULL; + dev_warn(dev, "cannot get analog voltage\n"); + } + + return ret; +} + +static s32 ov5640_write_reg(u16 reg, u8 val) +{ + u8 au8Buf[3] = {0}; + + au8Buf[0] = reg >> 8; + au8Buf[1] = reg & 0xff; + au8Buf[2] = val; + + if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) { + pr_err("%s:write reg error:reg=%x,val=%x\n", + __func__, reg, val); + return -1; + } + + return 0; +} + +static s32 ov5640_read_reg(u16 reg, u8 *val) +{ + u8 au8RegBuf[2] = {0}; + u8 u8RdVal = 0; + + au8RegBuf[0] = reg >> 8; + au8RegBuf[1] = reg & 0xff; + + if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) { + pr_err("%s:write reg error:reg=%x\n", + __func__, reg); + return -1; + } + + if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) { + pr_err("%s:read reg error:reg=%x,val=%x\n", + __func__, reg, u8RdVal); + return -1; + } + + *val = u8RdVal; + + return u8RdVal; +} + +static void ov5640_soft_reset(void) +{ + /* sysclk from pad */ + ov5640_write_reg(0x3103, 0x11); + + /* software reset */ + ov5640_write_reg(0x3008, 0x82); + + /* delay at least 5ms */ + msleep(10); +} + +/* set sensor driver capability + * 0x302c[7:6] - strength + 00 - 1x + 01 - 2x + 10 - 3x + 11 - 4x + */ +static int ov5640_driver_capability(int strength) +{ + u8 temp = 0; + + if (strength > 4 || strength < 1) { + pr_err("The valid driver capability of ov5640 is 1x~4x\n"); + return -EINVAL; + } + + ov5640_read_reg(0x302c, &temp); + + temp &= ~0xc0; /* clear [7:6] */ + temp |= ((strength - 1) << 6); /* set [7:6] */ + + ov5640_write_reg(0x302c, temp); + + return 0; +} + +/* calculate sysclk */ +static int ov5640_get_sysclk(void) +{ + int xvclk = ov5640_data.mclk / 10000; + int sysclk; + int temp1, temp2; + int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv; + int sclk_rdiv_map[] = {1, 2, 4, 8}; + u8 regval = 0; + + temp1 = ov5640_read_reg(0x3034, ®val); + temp2 = temp1 & 0x0f; + if (temp2 == 8 || temp2 == 10) { + Bit_div2x = temp2 / 2; + } else { + pr_err("ov5640: unsupported bit mode %d\n", temp2); + return -1; + } + + temp1 = ov5640_read_reg(0x3035, ®val); + SysDiv = temp1 >> 4; + if (SysDiv == 0) + SysDiv = 16; + + temp1 = ov5640_read_reg(0x3036, ®val); + Multiplier = temp1; + temp1 = ov5640_read_reg(0x3037, ®val); + PreDiv = temp1 & 0x0f; + Pll_rdiv = ((temp1 >> 4) & 0x01) + 1; + + temp1 = ov5640_read_reg(0x3108, ®val); + temp2 = temp1 & 0x03; + + sclk_rdiv = sclk_rdiv_map[temp2]; + VCO = xvclk * Multiplier / PreDiv; + sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv; + + return sysclk; +} + +/* read HTS from register settings */ +static int ov5640_get_HTS(void) +{ + int HTS; + u8 temp = 0; + + HTS = ov5640_read_reg(0x380c, &temp); + HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp); + return HTS; +} + +/* read VTS from register settings */ +static int ov5640_get_VTS(void) +{ + int VTS; + u8 temp = 0; + + VTS = ov5640_read_reg(0x380e, &temp); + VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp); + + return VTS; +} + +/* write VTS to registers */ +static int ov5640_set_VTS(int VTS) +{ + int temp; + + temp = VTS & 0xff; + ov5640_write_reg(0x380f, temp); + + temp = VTS>>8; + ov5640_write_reg(0x380e, temp); + return 0; +} + +/* read shutter, in number of line period */ +static int ov5640_get_shutter(void) +{ + int shutter; + u8 regval; + + shutter = (ov5640_read_reg(0x03500, ®val) & 0x0f); + + shutter = (shutter<<8) + ov5640_read_reg(0x3501, ®val); + shutter = (shutter<<4) + (ov5640_read_reg(0x3502, ®val)>>4); + + return shutter; +} + +/* write shutter, in number of line period */ +static int ov5640_set_shutter(int shutter) +{ + int temp; + + shutter = shutter & 0xffff; + temp = shutter & 0x0f; + temp = temp<<4; + ov5640_write_reg(0x3502, temp); + + temp = shutter & 0xfff; + temp = temp>>4; + ov5640_write_reg(0x3501, temp); + + temp = shutter>>12; + ov5640_write_reg(0x3500, temp); + + return 0; +} + +/* read gain, 16 = 1x */ +static int ov5640_get_gain16(void) +{ + int gain16; + u8 regval; + + gain16 = ov5640_read_reg(0x350a, ®val) & 0x03; + gain16 = (gain16<<8) + ov5640_read_reg(0x350b, ®val); + + return gain16; +} + +/* write gain, 16 = 1x */ +static int ov5640_set_gain16(int gain16) +{ + int temp; + + gain16 = gain16 & 0x3ff; + temp = gain16 & 0xff; + + ov5640_write_reg(0x350b, temp); + temp = gain16>>8; + + ov5640_write_reg(0x350a, temp); + return 0; +} + +/* get banding filter value */ +static int ov5640_get_light_freq(void) +{ + int temp, temp1, light_frequency; + u8 regval; + + temp = ov5640_read_reg(0x3c01, ®val); + if (temp & 0x80) { + /* manual */ + temp1 = ov5640_read_reg(0x3c00, ®val); + if (temp1 & 0x04) { + /* 50Hz */ + light_frequency = 50; + } else { + /* 60Hz */ + light_frequency = 60; + } + } else { + /* auto */ + temp1 = ov5640_read_reg(0x3c0c, ®val); + if (temp1 & 0x01) { + /* 50Hz */ + light_frequency = 50; + } else { + /* 60Hz */ + light_frequency = 60; + } + } + + return light_frequency; +} + +static void ov5640_set_bandingfilter(void) +{ + int prev_VTS; + int band_step60, max_band60, band_step50, max_band50; + + /* read preview PCLK */ + prev_sysclk = ov5640_get_sysclk(); + + /* read preview HTS */ + prev_HTS = ov5640_get_HTS(); + + /* read preview VTS */ + prev_VTS = ov5640_get_VTS(); + + /* calculate banding filter */ + /* 60Hz */ + band_step60 = prev_sysclk * 100/prev_HTS * 100/120; + ov5640_write_reg(0x3a0a, (band_step60 >> 8)); + ov5640_write_reg(0x3a0b, (band_step60 & 0xff)); + + max_band60 = (int)((prev_VTS-4)/band_step60); + ov5640_write_reg(0x3a0d, max_band60); + + /* 50Hz */ + band_step50 = prev_sysclk * 100/prev_HTS; + ov5640_write_reg(0x3a08, (band_step50 >> 8)); + ov5640_write_reg(0x3a09, (band_step50 & 0xff)); + + max_band50 = (int)((prev_VTS-4)/band_step50); + ov5640_write_reg(0x3a0e, max_band50); +} + +/* stable in high */ +static int ov5640_set_AE_target(int target) +{ + int fast_high, fast_low; + + AE_low = target * 23 / 25; /* 0.92 */ + AE_high = target * 27 / 25; /* 1.08 */ + fast_high = AE_high << 1; + + if (fast_high > 255) + fast_high = 255; + fast_low = AE_low >> 1; + + ov5640_write_reg(0x3a0f, AE_high); + ov5640_write_reg(0x3a10, AE_low); + ov5640_write_reg(0x3a1b, AE_high); + ov5640_write_reg(0x3a1e, AE_low); + ov5640_write_reg(0x3a11, fast_high); + ov5640_write_reg(0x3a1f, fast_low); + + return 0; +} + +/* enable = 0 to turn off night mode + enable = 1 to turn on night mode */ +static int ov5640_set_night_mode(int enable) +{ + u8 mode; + + ov5640_read_reg(0x3a00, &mode); + + if (enable) { + /* night mode on */ + mode |= 0x04; + ov5640_write_reg(0x3a00, mode); + } else { + /* night mode off */ + mode &= 0xfb; + ov5640_write_reg(0x3a00, mode); + } + + return 0; +} + +/* enable = 0 to turn off AEC/AGC + enable = 1 to turn on AEC/AGC */ +void ov5640_turn_on_AE_AG(int enable) +{ + u8 ae_ag_ctrl; + + ov5640_read_reg(0x3503, &ae_ag_ctrl); + if (enable) { + /* turn on auto AE/AG */ + ae_ag_ctrl = ae_ag_ctrl & ~(0x03); + } else { + /* turn off AE/AG */ + ae_ag_ctrl = ae_ag_ctrl | 0x03; + } + ov5640_write_reg(0x3503, ae_ag_ctrl); +} + +/* download ov5640 settings to sensor through i2c */ +static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) +{ + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int i, retval = 0; + + for (i = 0; i < ArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5640_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5640_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +static int ov5640_init_mode(void) +{ + struct reg_value *pModeSetting = NULL; + int ArySize = 0, retval = 0; + + ov5640_soft_reset(); + + pModeSetting = ov5640_global_init_setting; + ArySize = ARRAY_SIZE(ov5640_global_init_setting); + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + pModeSetting = ov5640_init_setting_30fps_VGA; + ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA); + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* change driver capability to 2x according to validation board. + * if the image is not stable, please increase the driver strength. + */ + ov5640_driver_capability(2); + ov5640_set_bandingfilter(); + ov5640_set_AE_target(AE_Target); + ov5640_set_night_mode(night_mode); + + /* skip 9 vysnc: start capture at 10th vsync */ + msleep(300); + + /* turn off night mode */ + night_mode = 0; + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; +err: + return retval; +} + +/* change to or back to subsampling mode set the mode directly + * image size below 1280 * 960 is subsampling mode */ +static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* set ov5640 to subsampling mode */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + + /* turn on AE AG for subsampling mode, in case the firmware didn't */ + ov5640_turn_on_AE_AG(1); + + /* calculate banding filter */ + ov5640_set_bandingfilter(); + + /* set AE target */ + ov5640_set_AE_target(AE_Target); + + /* update night mode setting */ + ov5640_set_night_mode(night_mode); + + /* skip 9 vysnc: start capture at 10th vsync */ + if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) { + pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n"); + /* 1/22.5 * 9*/ + msleep(400); + return retval; + } + + if (frame_rate == ov5640_15_fps) { + /* 1/15 * 9*/ + msleep(600); + } else if (frame_rate == ov5640_30_fps) { + /* 1/30 * 9*/ + msleep(300); + } + + return retval; +} + +/* change to scaling mode go through exposure calucation + * image size above 1280 * 960 is scaling mode */ +static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + int prev_shutter, prev_gain16, average; + int cap_shutter, cap_gain16; + int cap_sysclk, cap_HTS, cap_VTS; + int light_freq, cap_bandfilt, cap_maxband; + long cap_gain16_shutter; + u8 temp; + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* read preview shutter */ + prev_shutter = ov5640_get_shutter(); + + /* read preview gain */ + prev_gain16 = ov5640_get_gain16(); + + /* get average */ + average = ov5640_read_reg(0x56a1, &temp); + + /* turn off night mode for capture */ + ov5640_set_night_mode(0); + + /* turn off overlay */ + ov5640_write_reg(0x3022, 0x06); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* turn off AE AG when capture image. */ + ov5640_turn_on_AE_AG(0); + + /* read capture VTS */ + cap_VTS = ov5640_get_VTS(); + cap_HTS = ov5640_get_HTS(); + cap_sysclk = ov5640_get_sysclk(); + + /* calculate capture banding filter */ + light_freq = ov5640_get_light_freq(); + if (light_freq == 60) { + /* 60Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; + } else { + /* 50Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS; + } + cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); + /* calculate capture shutter/gain16 */ + if (average > AE_low && average < AE_high) { + /* in stable range */ + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * + prev_HTS/cap_HTS * AE_Target / average; + } else { + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * + prev_HTS/cap_HTS; + } + + /* gain to shutter */ + if (cap_gain16_shutter < (cap_bandfilt * 16)) { + /* shutter < 1/100 */ + cap_shutter = cap_gain16_shutter/16; + if (cap_shutter < 1) + cap_shutter = 1; + cap_gain16 = cap_gain16_shutter/cap_shutter; + if (cap_gain16 < 16) + cap_gain16 = 16; + } else { + if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) { + /* exposure reach max */ + cap_shutter = cap_bandfilt*cap_maxband; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } else { + /* 1/100 < cap_shutter =< max, cap_shutter = n/100 */ + cap_shutter = + ((int)(cap_gain16_shutter/16/cap_bandfilt)) + * cap_bandfilt; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } + } + + /* write capture gain */ + ov5640_set_gain16(cap_gain16); + + /* write capture shutter */ + if (cap_shutter > (cap_VTS - 4)) { + cap_VTS = cap_shutter + 4; + ov5640_set_VTS(cap_VTS); + } + + ov5640_set_shutter(cap_shutter); + + /* skip 2 vysnc: start capture at 3rd vsync + * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2 + */ + pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n", + mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA"); + msleep(267); +err: + return retval; +} + +static int ov5640_change_mode(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + int retval = 0; + + if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + if (mode == ov5640_mode_1080P_1920_1080 || + mode == ov5640_mode_QSXGA_2592_1944) { + /* change to scaling mode go through exposure calucation + * image size above 1280 * 960 is scaling mode */ + retval = ov5640_change_mode_exposure_calc(frame_rate, mode); + } else { + /* change back to subsampling modem download firmware directly + * image size below 1280 * 960 is subsampling mode */ + retval = ov5640_change_mode_direct(frame_rate, mode); + } + + return retval; +} + +/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ + +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + if (s == NULL) { + pr_err(" ERROR!! no slave device set!\n"); + return -1; + } + + memset(p, 0, sizeof(*p)); + p->u.bt656.clock_curr = ov5640_data.mclk; + pr_debug(" clock_curr=mclk=%d\n", ov5640_data.mclk); + p->if_type = V4L2_IF_TYPE_BT656; + p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.clock_min = OV5640_XCLK_MIN; + p->u.bt656.clock_max = OV5640_XCLK_MAX; + p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */ + + return 0; +} + +/*! + * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl + * @s: pointer to standard V4L2 device structure + * @on: indicates power mode (on or off) + * + * Turns the power on or off, depending on the value of on and returns the + * appropriate error code. + */ +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct sensor_data *sensor = s->priv; + + if (on && !sensor->on) { + if (io_regulator) + if (regulator_enable(io_regulator) != 0) + return -EIO; + if (core_regulator) + if (regulator_enable(core_regulator) != 0) + return -EIO; + if (analog_regulator) + if (regulator_enable(analog_regulator) != 0) + return -EIO; + /* Make sure power on */ + ov5640_power_down(0); + } else if (!on && sensor->on) { + if (analog_regulator) + regulator_disable(analog_regulator); + if (core_regulator) + regulator_disable(core_regulator); + if (io_regulator) + regulator_disable(io_regulator); + + ov5640_power_down(1); +} + + sensor->on = on; + + return 0; +} + +/*! + * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->streamcap.capability; + cparm->timeperframe = sensor->streamcap.timeperframe; + cparm->capturemode = sensor->streamcap.capturemode; + ret = 0; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + */ +static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + int ret = 0; + + /* Make sure power on */ + ov5640_power_down(0); + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* Check that the new frame rate is allowed. */ + if ((timeperframe->numerator == 0) || + (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + /* Actual frame rate we use */ + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else { + pr_err(" The camera frame rate is not supported!\n"); + return -EINVAL; + } + + ret = ov5640_change_mode(frame_rate, + a->parm.capture.capturemode); + if (ret < 0) + return ret; + + sensor->streamcap.timeperframe = *timeperframe; + sensor->streamcap.capturemode = a->parm.capture.capturemode; + + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + pr_debug(" type is not " \ + "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", + a->type); + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap + * @s: pointer to standard V4L2 device structure + * @f: pointer to standard V4L2 v4l2_format structure + * + * Returns the sensor's current pixel format in the v4l2_format + * parameter. + */ +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + struct sensor_data *sensor = s->priv; + + f->fmt.pix = sensor->pix; + + return 0; +} + +/*! + * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure + * + * If the requested control is supported, returns the control's current + * value from the video_control[] array. Otherwise, returns -EINVAL + * if the control is not supported. + */ +static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int ret = 0; + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + vc->value = ov5640_data.brightness; + break; + case V4L2_CID_HUE: + vc->value = ov5640_data.hue; + break; + case V4L2_CID_CONTRAST: + vc->value = ov5640_data.contrast; + break; + case V4L2_CID_SATURATION: + vc->value = ov5640_data.saturation; + break; + case V4L2_CID_RED_BALANCE: + vc->value = ov5640_data.red; + break; + case V4L2_CID_BLUE_BALANCE: + vc->value = ov5640_data.blue; + break; + case V4L2_CID_EXPOSURE: + vc->value = ov5640_data.ae_mode; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +/*! + * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure + * + * If the requested control is supported, sets the control's current + * value in HW (and updates the video_control[] array). Otherwise, + * returns -EINVAL if the control is not supported. + */ +static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int retval = 0; + + pr_debug("In ov5640:ioctl_s_ctrl %d\n", + vc->id); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + break; + case V4L2_CID_CONTRAST: + break; + case V4L2_CID_SATURATION: + break; + case V4L2_CID_HUE: + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + break; + case V4L2_CID_DO_WHITE_BALANCE: + break; + case V4L2_CID_RED_BALANCE: + break; + case V4L2_CID_BLUE_BALANCE: + break; + case V4L2_CID_GAMMA: + break; + case V4L2_CID_EXPOSURE: + break; + case V4L2_CID_AUTOGAIN: + break; + case V4L2_CID_GAIN: + break; + case V4L2_CID_HFLIP: + break; + case V4L2_CID_VFLIP: + break; + default: + retval = -EPERM; + break; + } + + return retval; +} + +/*! + * ioctl_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_framesizes(struct v4l2_int_device *s, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index > ov5640_mode_MAX) + return -EINVAL; + + fsize->pixel_format = ov5640_data.pix.pixelformat; + fsize->discrete.width = + max(ov5640_mode_info_data[0][fsize->index].width, + ov5640_mode_info_data[1][fsize->index].width); + fsize->discrete.height = + max(ov5640_mode_info_data[0][fsize->index].height, + ov5640_mode_info_data[1][fsize->index].height); + return 0; +} + +/*! + * ioctl_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_frameintervals(struct v4l2_int_device *s, + struct v4l2_frmivalenum *fival) +{ + int i, j, count; + + if (fival->index < 0 || fival->index > ov5640_mode_MAX) + return -EINVAL; + + if (fival->width == 0 || fival->height == 0 || + fival->pixel_format == 0) { + pr_warning("Please assign pixelformat, width and height.\n"); + return -EINVAL; + } + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + + count = 0; + for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) { + for (j = 0; j < (ov5640_mode_MAX + 1); j++) { + if (fival->pixel_format == ov5640_data.pix.pixelformat + && fival->width == ov5640_mode_info_data[i][j].width + && fival->height == ov5640_mode_info_data[i][j].height + && ov5640_mode_info_data[i][j].init_data_ptr != NULL) { + count++; + } + if (fival->index == (count - 1)) { + fival->discrete.denominator = + ov5640_framerates[i]; + return 0; + } + } + } + + return -EINVAL; +} + +/*! + * ioctl_g_chip_ident - V4L2 sensor interface handler for + * VIDIOC_DBG_G_CHIP_IDENT ioctl + * @s: pointer to standard V4L2 device structure + * @id: pointer to int + * + * Return 0. + */ +static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) +{ + ((struct v4l2_dbg_chip_ident *)id)->match.type = + V4L2_CHIP_MATCH_I2C_DRIVER; + strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5640_camera"); + + return 0; +} + +/*! + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT + * @s: pointer to standard V4L2 device structure + */ +static int ioctl_init(struct v4l2_int_device *s) +{ + + return 0; +} + +/*! + * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT + * @s: pointer to standard V4L2 device structure + * @fmt: pointer to standard V4L2 fmt description structure + * + * Return 0. + */ +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index > ov5640_mode_MAX) + return -EINVAL; + + fmt->pixelformat = ov5640_data.pix.pixelformat; + + return 0; +} + +/*! + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device structure + * + * Initialise the device when slave attaches to the master. + */ +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct sensor_data *sensor = s->priv; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + int ret; + + ov5640_data.on = true; + + /* mclk */ + tgt_xclk = ov5640_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); + ov5640_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk); + + /* Default camera frame rate is set in probe */ + tgt_fps = sensor->streamcap.timeperframe.denominator / + sensor->streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + ret = ov5640_init_mode(); + return ret; +} + +/*! + * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num + * @s: pointer to standard V4L2 device structure + * + * Delinitialise the device when slave detaches to the master. + */ +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + return 0; +} + +/*! + * This structure defines all the ioctls for this module and links them to the + * enumeration. + */ +static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = { + { vidioc_int_dev_init_num, + (v4l2_int_ioctl_func *)ioctl_dev_init }, + { vidioc_int_dev_exit_num, + ioctl_dev_exit}, + { vidioc_int_s_power_num, + (v4l2_int_ioctl_func *)ioctl_s_power }, + { vidioc_int_g_ifparm_num, + (v4l2_int_ioctl_func *)ioctl_g_ifparm }, + { vidioc_int_init_num, + (v4l2_int_ioctl_func *)ioctl_init }, + { vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, + { vidioc_int_g_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, + { vidioc_int_g_parm_num, + (v4l2_int_ioctl_func *)ioctl_g_parm }, + { vidioc_int_s_parm_num, + (v4l2_int_ioctl_func *)ioctl_s_parm }, + { vidioc_int_g_ctrl_num, + (v4l2_int_ioctl_func *)ioctl_g_ctrl }, + { vidioc_int_s_ctrl_num, + (v4l2_int_ioctl_func *)ioctl_s_ctrl }, + { vidioc_int_enum_framesizes_num, + (v4l2_int_ioctl_func *)ioctl_enum_framesizes }, + { vidioc_int_enum_frameintervals_num, + (v4l2_int_ioctl_func *)ioctl_enum_frameintervals }, + { vidioc_int_g_chip_ident_num, + (v4l2_int_ioctl_func *)ioctl_g_chip_ident }, +}; + +static struct v4l2_int_slave ov5640_slave = { + .ioctls = ov5640_ioctl_desc, + .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc), +}; + +static struct v4l2_int_device ov5640_int_device = { + .module = THIS_MODULE, + .name = "ov5640", + .type = v4l2_int_type_slave, + .u = { + .slave = &ov5640_slave, + }, +}; + +/*! + * ov5640 I2C probe function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int ov5640_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + int retval; + u8 chip_id_high, chip_id_low; + 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-4.1.13.orig/drivers/media/platform/mxc/capture/ov5640_mipi.c linux-4.1.13/drivers/media/platform/mxc/capture/ov5640_mipi.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ov5640_mipi.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ov5640_mipi.c 2015-11-30 17:56:13.604136128 +0100 @@ -0,0 +1,2193 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" + +#define OV5640_VOLTAGE_ANALOG 2800000 +#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5640_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5640_XCLK_MIN 6000000 +#define OV5640_XCLK_MAX 24000000 + +#define OV5640_CHIP_ID_HIGH_BYTE 0x300A +#define OV5640_CHIP_ID_LOW_BYTE 0x300B + +enum ov5640_mode { + ov5640_mode_MIN = 0, + ov5640_mode_VGA_640_480 = 0, + ov5640_mode_QVGA_320_240 = 1, + ov5640_mode_NTSC_720_480 = 2, + ov5640_mode_PAL_720_576 = 3, + ov5640_mode_720P_1280_720 = 4, + ov5640_mode_1080P_1920_1080 = 5, + ov5640_mode_QSXGA_2592_1944 = 6, + ov5640_mode_QCIF_176_144 = 7, + ov5640_mode_XGA_1024_768 = 8, + ov5640_mode_MAX = 8, + ov5640_mode_INIT = 0xff, /*only for sensor init*/ +}; + +enum ov5640_frame_rate { + ov5640_15_fps, + ov5640_30_fps +}; + +/* image size under 1280 * 960 are SUBSAMPLING + * image size upper 1280 * 960 are SCALING + */ +enum ov5640_downsize_mode { + SUBSAMPLING, + SCALING, +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5640_mode_info { + enum ov5640_mode mode; + enum ov5640_downsize_mode dn_mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +/*! + * Maintains the information on the current state of the sesor. + */ +static struct sensor_data ov5640_data; +static int pwn_gpio, rst_gpio; + +static struct reg_value ov5640_init_setting_30fps_VGA[] = { + + {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, + {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, + {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, + {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, + {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, + {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, + {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, + {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, + {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, + {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, + {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, + {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, + {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, + {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, + {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, + {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, + {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, + {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, + {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, + {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, + {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, + {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, + {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, + {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, + {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, + {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, + {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, + {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, + {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, + {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, + {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, + {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, + {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, + {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, + {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, + {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, + {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, + {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, + {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, + {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, + {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, + {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, + {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, + {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, + {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, + {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, + {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, + {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, + {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, + {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, + {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, + {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, + {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, + {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, + {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, + {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, + {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, + {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, + {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, +}; + +static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { + + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { + + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, + {0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0}, + {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; +static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { + {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { + {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, + {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0}, + {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { + {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, + {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, + {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, + {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, + {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, + {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, + {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { + {0x4202, 0x0f, 0, 0}, /* stream off the sensor */ + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/ + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, + {0x4202, 0x00, 0, 0}, /* stream on the sensor */ +}; + +static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { + { + {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, + ov5640_setting_15fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, + ov5640_setting_15fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, + ov5640_setting_15fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, + ov5640_setting_15fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, + ov5640_setting_15fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, + ov5640_setting_15fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944, + ov5640_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, + {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, + ov5640_setting_15fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, + ov5640_setting_15fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, + }, + { + {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, + ov5640_setting_30fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, + ov5640_setting_30fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, + ov5640_setting_30fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, + ov5640_setting_30fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, + ov5640_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, + ov5640_setting_30fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0}, + {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, + ov5640_setting_30fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, + ov5640_setting_30fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; +static struct regulator *gpo_regulator; + +static int ov5640_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5640_remove(struct i2c_client *client); + +static s32 ov5640_read_reg(u16 reg, u8 *val); +static s32 ov5640_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5640_id[] = { + {"ov5640_mipi", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5640_id); + +static struct i2c_driver ov5640_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov5640_mipi", + }, + .probe = ov5640_probe, + .remove = ov5640_remove, + .id_table = ov5640_id, +}; + +static void ov5640_standby(s32 enable) +{ + if (enable) + gpio_set_value(pwn_gpio, 1); + else + gpio_set_value(pwn_gpio, 0); + 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 binning_on(void) +{ + u8 temp; + ov5640_read_reg(0x3821, &temp); + temp &= 0xfe; + if (temp) + return true; + else + return false; +} + +static void ov5640_set_virtual_channel(int channel) +{ + u8 channel_id; + + ov5640_read_reg(0x4814, &channel_id); + channel_id &= ~(3 << 6); + ov5640_write_reg(0x4814, channel_id | (channel << 6)); +} + +/* download ov5640 settings to sensor through i2c */ +static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) +{ + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int i, retval = 0; + + for (i = 0; i < ArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5640_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5640_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +/* sensor changes between scaling and subsampling + * go through exposure calcualtion + */ +static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + u8 average; + int prev_shutter, prev_gain16; + int cap_shutter, cap_gain16; + int cap_sysclk, cap_HTS, cap_VTS; + int light_freq, cap_bandfilt, cap_maxband; + long cap_gain16_shutter; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* auto focus */ + /* OV5640_auto_focus();//if no af function, just skip it */ + + /* turn off AE/AG */ + OV5640_turn_on_AE_AG(0); + + /* read preview shutter */ + prev_shutter = OV5640_get_shutter(); + if ((binning_on()) && (mode != ov5640_mode_720P_1280_720) + && (mode != ov5640_mode_1080P_1920_1080)) + prev_shutter *= 2; + + /* read preview gain */ + prev_gain16 = OV5640_get_gain16(); + + /* get average */ + ov5640_read_reg(0x56a1, &average); + + /* turn off night mode for capture */ + OV5640_set_night_mode(); + + /* turn off overlay */ + /* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */ + + OV5640_stream_off(); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* read capture VTS */ + cap_VTS = OV5640_get_VTS(); + cap_HTS = OV5640_get_HTS(); + cap_sysclk = OV5640_get_sysclk(); + + /* calculate capture banding filter */ + light_freq = OV5640_get_light_freq(); + if (light_freq == 60) { + /* 60Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; + } else { + /* 50Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS; + } + cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); + + /* calculate capture shutter/gain16 */ + if (average > AE_low && average < AE_high) { + /* in stable range */ + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk + * prev_HTS/cap_HTS * AE_Target / average; + } else { + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk + * prev_HTS/cap_HTS; + } + + /* gain to shutter */ + if (cap_gain16_shutter < (cap_bandfilt * 16)) { + /* shutter < 1/100 */ + cap_shutter = cap_gain16_shutter/16; + if (cap_shutter < 1) + cap_shutter = 1; + + cap_gain16 = cap_gain16_shutter/cap_shutter; + if (cap_gain16 < 16) + cap_gain16 = 16; + } else { + if (cap_gain16_shutter > + (cap_bandfilt * cap_maxband * 16)) { + /* exposure reach max */ + cap_shutter = cap_bandfilt * cap_maxband; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } else { + /* 1/100 < (cap_shutter = n/100) =< max */ + cap_shutter = + ((int) (cap_gain16_shutter/16 / cap_bandfilt)) + *cap_bandfilt; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } + } + + /* write capture gain */ + OV5640_set_gain16(cap_gain16); + + /* write capture shutter */ + if (cap_shutter > (cap_VTS - 4)) { + cap_VTS = cap_shutter + 4; + OV5640_set_VTS(cap_VTS); + } + OV5640_set_shutter(cap_shutter); + + OV5640_stream_on(); + +err: + return retval; +} + +/* if sensor changes inside scaling or subsampling + * change mode directly + * */ +static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* turn off AE/AG */ + OV5640_turn_on_AE_AG(0); + + OV5640_stream_off(); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + OV5640_stream_on(); + + OV5640_turn_on_AE_AG(1); + +err: + return retval; +} + +static int ov5640_init_mode(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode, enum ov5640_mode orig_mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + void *mipi_csi2_info; + u32 mipi_reg, msec_wait4stable = 0; + enum ov5640_downsize_mode dn_mode, orig_dn_mode; + + if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) + && (mode != ov5640_mode_INIT)) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + mipi_csi2_info = mipi_csi2_get_info(); + + /* initial mipi dphy */ + if (!mipi_csi2_info) { + printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", + __func__, __FILE__); + return -1; + } + + if (!mipi_csi2_get_status(mipi_csi2_info)) + mipi_csi2_enable(mipi_csi2_info); + + if (!mipi_csi2_get_status(mipi_csi2_info)) { + pr_err("Can not enable mipi csi2 driver!\n"); + return -1; + } + + mipi_csi2_set_lanes(mipi_csi2_info, 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_g_chip_ident - V4L2 sensor interface handler for + * VIDIOC_DBG_G_CHIP_IDENT ioctl + * @s: pointer to standard V4L2 device structure + * @id: pointer to int + * + * Return 0. + */ +static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) +{ + ((struct v4l2_dbg_chip_ident *)id)->match.type = + V4L2_CHIP_MATCH_I2C_DRIVER; + strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, + "ov5640_mipi_camera"); + + return 0; +} + +/*! + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT + * @s: pointer to standard V4L2 device structure + */ +static int ioctl_init(struct v4l2_int_device *s) +{ + + return 0; +} + +/*! + * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT + * @s: pointer to standard V4L2 device structure + * @fmt: pointer to standard V4L2 fmt description structure + * + * Return 0. + */ +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index > ov5640_mode_MAX) + return -EINVAL; + + fmt->pixelformat = ov5640_data.pix.pixelformat; + + return 0; +} + +/*! + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device structure + * + * Initialise the device when slave attaches to the master. + */ +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct sensor_data *sensor = s->priv; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + int ret; + enum ov5640_frame_rate frame_rate; + void *mipi_csi2_info; + + ov5640_data.on = true; + + /* mclk */ + tgt_xclk = ov5640_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); + ov5640_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + + /* Default camera frame rate is set in probe */ + tgt_fps = sensor->streamcap.timeperframe.denominator / + sensor->streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + mipi_csi2_info = mipi_csi2_get_info(); + + /* enable mipi csi2 */ + if (mipi_csi2_info) + mipi_csi2_enable(mipi_csi2_info); + else { + printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", + __func__, __FILE__); + return -EPERM; + } + + ret = ov5640_init_mode(frame_rate, ov5640_mode_INIT, ov5640_mode_INIT); + + return ret; +} + +/*! + * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num + * @s: pointer to standard V4L2 device structure + * + * Delinitialise the device when slave detaches to the master. + */ +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + void *mipi_csi2_info; + + mipi_csi2_info = mipi_csi2_get_info(); + + /* disable mipi csi2 */ + if (mipi_csi2_info) + if (mipi_csi2_get_status(mipi_csi2_info)) + mipi_csi2_disable(mipi_csi2_info); + + return 0; +} + +/*! + * This structure defines all the ioctls for this module and links them to the + * enumeration. + */ +static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = { + {vidioc_int_dev_init_num, (v4l2_int_ioctl_func *) ioctl_dev_init}, + {vidioc_int_dev_exit_num, ioctl_dev_exit}, + {vidioc_int_s_power_num, (v4l2_int_ioctl_func *) ioctl_s_power}, + {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *) ioctl_g_ifparm}, +/* {vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */ +/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */ + {vidioc_int_init_num, (v4l2_int_ioctl_func *) ioctl_init}, + {vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, +/* {vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */ + {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap}, +/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_s_fmt_cap}, */ + {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm}, + {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm}, +/* {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */ + {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl}, + {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl}, + {vidioc_int_enum_framesizes_num, + (v4l2_int_ioctl_func *) ioctl_enum_framesizes}, + {vidioc_int_g_chip_ident_num, + (v4l2_int_ioctl_func *) ioctl_g_chip_ident}, +}; + +static struct v4l2_int_slave ov5640_slave = { + .ioctls = ov5640_ioctl_desc, + .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc), +}; + +static struct v4l2_int_device ov5640_int_device = { + .module = THIS_MODULE, + .name = "ov5640_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_IWUSR|S_IWGRP, 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-4.1.13.orig/drivers/media/platform/mxc/capture/ov5642.c linux-4.1.13/drivers/media/platform/mxc/capture/ov5642.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ov5642.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ov5642.c 2015-11-30 17:56:13.612135595 +0100 @@ -0,0 +1,6294 @@ +/* + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" + +#define OV5642_VOLTAGE_ANALOG 2800000 +#define OV5642_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5642_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5642_XCLK_MIN 6000000 +#define OV5642_XCLK_MAX 24000000 + +/* 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-4.1.13.orig/drivers/media/platform/mxc/capture/ov5647_mipi.c linux-4.1.13/drivers/media/platform/mxc/capture/ov5647_mipi.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/ov5647_mipi.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/ov5647_mipi.c 2015-11-30 17:56:13.612135595 +0100 @@ -0,0 +1,3780 @@ +/* + * 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 "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_IWUSR|S_IWGRP, show_reg, set_reg); +static DEVICE_ATTR(ov5647_mode, S_IRUGO|S_IWUSR|S_IWGRP, 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-4.1.13.orig/drivers/media/platform/mxc/capture/tc358743_h2c.c linux-4.1.13/drivers/media/platform/mxc/capture/tc358743_h2c.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/tc358743_h2c.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/tc358743_h2c.c 2015-11-30 17:56:13.616135330 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/tda1997x.c linux-4.1.13/drivers/media/platform/mxc/capture/tda1997x.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/tda1997x.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/tda1997x.c 2015-11-30 17:56:13.616135330 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/v4l2-int-device.c linux-4.1.13/drivers/media/platform/mxc/capture/v4l2-int-device.c --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/v4l2-int-device.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/v4l2-int-device.c 2015-11-30 17:56:13.616135330 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/capture/v4l2-int-device.h linux-4.1.13/drivers/media/platform/mxc/capture/v4l2-int-device.h --- linux-4.1.13.orig/drivers/media/platform/mxc/capture/v4l2-int-device.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/capture/v4l2-int-device.h 2015-11-30 17:56:13.616135330 +0100 @@ -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-4.1.13.orig/drivers/media/platform/mxc/output/Kconfig linux-4.1.13/drivers/media/platform/mxc/output/Kconfig --- linux-4.1.13.orig/drivers/media/platform/mxc/output/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/output/Kconfig 2015-11-30 17:56:13.616135330 +0100 @@ -0,0 +1,5 @@ +config VIDEO_MXC_IPU_OUTPUT + tristate "IPU v4l2 output support" + depends on VIDEO_MXC_OUTPUT && MXC_IPU + ---help--- + This is the video4linux2 driver for IPU post processing video output. diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/output/Makefile linux-4.1.13/drivers/media/platform/mxc/output/Makefile --- linux-4.1.13.orig/drivers/media/platform/mxc/output/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/output/Makefile 2015-11-30 17:56:13.616135330 +0100 @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc_vout.o diff -Nur linux-4.1.13.orig/drivers/media/platform/mxc/output/mxc_vout.c linux-4.1.13/drivers/media/platform/mxc/output/mxc_vout.c --- linux-4.1.13.orig/drivers/media/platform/mxc/output/mxc_vout.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/output/mxc_vout.c 2015-11-30 17:56:13.616135330 +0100 @@ -0,0 +1,2265 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define UYVY_BLACK (0x00800080) +#define RGB_BLACK (0x0) +#define UV_BLACK (0x80) +#define Y_BLACK (0x0) + +#define MAX_FB_NUM 6 +#define FB_BUFS 3 +#define VDOA_FB_BUFS (FB_BUFS - 1) +#define VALID_HEIGHT_1080P (1080) +#define FRAME_HEIGHT_1080P (1088) +#define FRAME_WIDTH_1080P (1920) +#define CHECK_TILED_1080P_DISPLAY(vout) \ + ((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) || \ + ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\ + ((vout)->task.input.width == FRAME_WIDTH_1080P) && \ + ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \ + ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \ + (((vout)->task.input.crop.h == FRAME_HEIGHT_1080P) || \ + ((vout)->task.input.crop.h == VALID_HEIGHT_1080P)) && \ + ((vout)->task.output.width == FRAME_WIDTH_1080P) && \ + ((vout)->task.output.height == VALID_HEIGHT_1080P) && \ + ((vout)->task.output.crop.w == FRAME_WIDTH_1080P) && \ + ((vout)->task.output.crop.h == VALID_HEIGHT_1080P)) +#define CHECK_TILED_1080P_STREAM(vout) \ + ((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) || \ + ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\ + ((vout)->task.input.width == FRAME_WIDTH_1080P) && \ + ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \ + ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \ + ((vout)->task.input.crop.h == FRAME_HEIGHT_1080P)) +#define IS_PLANAR_PIXEL_FORMAT(format) \ + (format == IPU_PIX_FMT_NV12 || \ + format == IPU_PIX_FMT_YUV420P2 || \ + format == IPU_PIX_FMT_YUV420P || \ + format == IPU_PIX_FMT_YVU420P || \ + format == IPU_PIX_FMT_YUV422P || \ + format == IPU_PIX_FMT_YVU422P || \ + format == IPU_PIX_FMT_YUV444P) + +#define NSEC_PER_FRAME_30FPS (33333333) + +struct mxc_vout_fb { + char *name; + int ipu_id; + struct v4l2_rect crop_bounds; + unsigned int disp_fmt; + bool disp_support_csc; + bool disp_support_windows; +}; + +struct dma_mem { + void *vaddr; + dma_addr_t paddr; + size_t size; +}; + +struct mxc_vout_output { + int open_cnt; + struct fb_info *fbi; + unsigned long fb_smem_start; + unsigned long fb_smem_len; + struct video_device *vfd; + struct mutex mutex; + struct mutex task_lock; + enum v4l2_buf_type type; + + struct videobuf_queue vbq; + spinlock_t vbq_lock; + + struct list_head queue_list; + struct list_head active_list; + + struct v4l2_rect crop_bounds; + unsigned int disp_fmt; + struct mxcfb_pos win_pos; + bool disp_support_windows; + bool disp_support_csc; + + bool fmt_init; + bool release; + bool linear_bypass_pp; + bool vdoa_1080p; + bool tiled_bypass_pp; + struct v4l2_rect in_rect; + struct ipu_task task; + struct ipu_task vdoa_task; + struct dma_mem vdoa_work; + struct dma_mem vdoa_output[VDOA_FB_BUFS]; + + bool timer_stop; + struct hrtimer timer; + struct workqueue_struct *v4l_wq; + struct work_struct disp_work; + unsigned long frame_count; + unsigned long vdi_frame_cnt; + ktime_t start_ktime; + + int ctrl_rotate; + int ctrl_vflip; + int ctrl_hflip; + + dma_addr_t disp_bufs[FB_BUFS]; + + struct videobuf_buffer *pre1_vb; + struct videobuf_buffer *pre2_vb; +}; + +struct mxc_vout_dev { + struct device *dev; + struct v4l2_device v4l2_dev; + struct mxc_vout_output *out[MAX_FB_NUM]; + int out_num; +}; + +/* Driver Configuration macros */ +#define VOUT_NAME "mxc_vout" + +/* Variables configurable through module params*/ +static int debug; +static int vdi_rate_double; +static int video_nr = 16; + +/* Module parameters */ +module_param(video_nr, int, S_IRUGO); +MODULE_PARM_DESC(video_nr, "video device numbers"); +module_param(debug, int, 0600); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); +module_param(vdi_rate_double, int, 0600); +MODULE_PARM_DESC(vdi_rate_double, "vdi frame rate double on/off"); + +static const struct v4l2_fmtdesc mxc_formats[] = { + { + .description = "RGB565", + .pixelformat = V4L2_PIX_FMT_RGB565, + }, + { + .description = "BGR24", + .pixelformat = V4L2_PIX_FMT_BGR24, + }, + { + .description = "RGB24", + .pixelformat = V4L2_PIX_FMT_RGB24, + }, + { + .description = "RGB32", + .pixelformat = V4L2_PIX_FMT_RGB32, + }, + { + .description = "BGR32", + .pixelformat = V4L2_PIX_FMT_BGR32, + }, + { + .description = "NV12", + .pixelformat = V4L2_PIX_FMT_NV12, + }, + { + .description = "UYVY", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, + { + .description = "YUYV", + .pixelformat = V4L2_PIX_FMT_YUYV, + }, + { + .description = "YUV422 planar", + .pixelformat = V4L2_PIX_FMT_YUV422P, + }, + { + .description = "YUV444", + .pixelformat = V4L2_PIX_FMT_YUV444, + }, + { + .description = "YUV420", + .pixelformat = V4L2_PIX_FMT_YUV420, + }, + { + .description = "YVU420", + .pixelformat = V4L2_PIX_FMT_YVU420, + }, + { + .description = "TILED NV12P", + .pixelformat = IPU_PIX_FMT_TILED_NV12, + }, + { + .description = "TILED NV12F", + .pixelformat = IPU_PIX_FMT_TILED_NV12F, + }, + { + .description = "YUV444 planar", + .pixelformat = IPU_PIX_FMT_YUV444P, + }, +}; + +#define NUM_MXC_VOUT_FORMATS (ARRAY_SIZE(mxc_formats)) + +#define DEF_INPUT_WIDTH 320 +#define DEF_INPUT_HEIGHT 240 + +static int mxc_vidioc_streamoff(struct file *file, void *fh, + enum v4l2_buf_type i); + +static struct mxc_vout_fb g_fb_setting[MAX_FB_NUM]; +static int config_disp_output(struct mxc_vout_output *vout); +static void release_disp_output(struct mxc_vout_output *vout); + +static unsigned int get_frame_size(struct mxc_vout_output *vout) +{ + unsigned int size; + + if (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) + size = TILED_NV12_FRAME_SIZE(vout->task.input.width, + vout->task.input.height); + else if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) { + size = TILED_NV12_FRAME_SIZE(vout->task.input.width, + vout->task.input.height/2); + size *= 2; + } else + size = vout->task.input.width * vout->task.input.height * + fmt_to_bpp(vout->task.input.format)/8; + + return size; +} + +static void free_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf) +{ + dma_free_coherent(vout->vbq.dev, buf->size, buf->vaddr, buf->paddr); + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "free dma size:0x%x, paddr:0x%x\n", + buf->size, buf->paddr); + memset(buf, 0, sizeof(*buf)); +} + +static int alloc_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf) +{ + + buf->vaddr = dma_alloc_coherent(vout->vbq.dev, buf->size, &buf->paddr, + GFP_DMA | GFP_KERNEL); + if (!buf->vaddr) { + v4l2_err(vout->vfd->v4l2_dev, + "cannot get dma buf size:0x%x\n", buf->size); + return -ENOMEM; + } + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr); + return 0; +} + +static ipu_channel_t get_ipu_channel(struct fb_info *fbi) +{ + ipu_channel_t ipu_ch = CHAN_NONE; + mm_segment_t old_fs; + + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN, + (unsigned long)&ipu_ch); + set_fs(old_fs); + } + + return ipu_ch; +} + +static unsigned int get_ipu_fmt(struct fb_info *fbi) +{ + mm_segment_t old_fs; + unsigned int fb_fmt; + + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + fbi->fbops->fb_ioctl(fbi, MXCFB_GET_DIFMT, + (unsigned long)&fb_fmt); + set_fs(old_fs); + } + + return fb_fmt; +} + +static void update_display_setting(void) +{ + int i; + struct fb_info *fbi; + struct v4l2_rect bg_crop_bounds[2]; + + for (i = 0; i < num_registered_fb; i++) { + fbi = registered_fb[i]; + + memset(&g_fb_setting[i], 0, sizeof(struct mxc_vout_fb)); + + if (!strncmp(fbi->fix.id, "DISP3", 5)) + g_fb_setting[i].ipu_id = 0; + else + g_fb_setting[i].ipu_id = 1; + + g_fb_setting[i].name = fbi->fix.id; + g_fb_setting[i].crop_bounds.left = 0; + g_fb_setting[i].crop_bounds.top = 0; + g_fb_setting[i].crop_bounds.width = fbi->var.xres; + g_fb_setting[i].crop_bounds.height = fbi->var.yres; + g_fb_setting[i].disp_fmt = get_ipu_fmt(fbi); + + if (get_ipu_channel(fbi) == MEM_BG_SYNC) { + bg_crop_bounds[g_fb_setting[i].ipu_id] = + g_fb_setting[i].crop_bounds; + g_fb_setting[i].disp_support_csc = true; + } else if (get_ipu_channel(fbi) == MEM_FG_SYNC) { + g_fb_setting[i].disp_support_csc = true; + g_fb_setting[i].disp_support_windows = true; + } + } + + for (i = 0; i < num_registered_fb; i++) { + fbi = registered_fb[i]; + + if (get_ipu_channel(fbi) == MEM_FG_SYNC) + g_fb_setting[i].crop_bounds = + bg_crop_bounds[g_fb_setting[i].ipu_id]; + } +} + +/* called after g_fb_setting filled by update_display_setting */ +static int update_setting_from_fbi(struct mxc_vout_output *vout, + struct fb_info *fbi) +{ + int i; + bool found = false; + + for (i = 0; i < MAX_FB_NUM; i++) { + if (g_fb_setting[i].name) { + if (!strcmp(fbi->fix.id, g_fb_setting[i].name)) { + vout->crop_bounds = g_fb_setting[i].crop_bounds; + vout->disp_fmt = g_fb_setting[i].disp_fmt; + vout->disp_support_csc = + g_fb_setting[i].disp_support_csc; + vout->disp_support_windows = + g_fb_setting[i].disp_support_windows; + found = true; + break; + } + } + } + + if (!found) { + v4l2_err(vout->vfd->v4l2_dev, "can not find output\n"); + return -EINVAL; + } + strlcpy(vout->vfd->name, fbi->fix.id, sizeof(vout->vfd->name)); + + memset(&vout->task, 0, sizeof(struct ipu_task)); + + vout->task.input.width = DEF_INPUT_WIDTH; + vout->task.input.height = DEF_INPUT_HEIGHT; + vout->task.input.crop.pos.x = 0; + vout->task.input.crop.pos.y = 0; + vout->task.input.crop.w = DEF_INPUT_WIDTH; + vout->task.input.crop.h = DEF_INPUT_HEIGHT; + + vout->task.output.width = vout->crop_bounds.width; + vout->task.output.height = vout->crop_bounds.height; + vout->task.output.crop.pos.x = 0; + vout->task.output.crop.pos.y = 0; + vout->task.output.crop.w = vout->crop_bounds.width; + vout->task.output.crop.h = vout->crop_bounds.height; + if (colorspaceofpixel(vout->disp_fmt) == YUV_CS) + vout->task.output.format = IPU_PIX_FMT_UYVY; + else + vout->task.output.format = IPU_PIX_FMT_RGB565; + + return 0; +} + +static inline unsigned long get_jiffies(struct timeval *t) +{ + struct timeval cur; + + if (t->tv_usec >= 1000000) { + t->tv_sec += t->tv_usec / 1000000; + t->tv_usec = t->tv_usec % 1000000; + } + + do_gettimeofday(&cur); + if ((t->tv_sec < cur.tv_sec) + || ((t->tv_sec == cur.tv_sec) && (t->tv_usec < cur.tv_usec))) + return jiffies; + + if (t->tv_usec < cur.tv_usec) { + cur.tv_sec = t->tv_sec - cur.tv_sec - 1; + cur.tv_usec = t->tv_usec + 1000000 - cur.tv_usec; + } else { + cur.tv_sec = t->tv_sec - cur.tv_sec; + cur.tv_usec = t->tv_usec - cur.tv_usec; + } + + return jiffies + timeval_to_jiffies(&cur); +} + +static bool deinterlace_3_field(struct mxc_vout_output *vout) +{ + return (vout->task.input.deinterlace.enable && + (vout->task.input.deinterlace.motion != HIGH_MOTION)); +} + +static int set_field_fmt(struct mxc_vout_output *vout, enum v4l2_field field) +{ + struct ipu_deinterlace *deinterlace = &vout->task.input.deinterlace; + + switch (field) { + /* Images are in progressive format, not interlaced */ + case V4L2_FIELD_NONE: + case V4L2_FIELD_ANY: + deinterlace->enable = false; + deinterlace->field_fmt = 0; + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "Progressive frame.\n"); + break; + case V4L2_FIELD_INTERLACED_TB: + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "Enable deinterlace TB.\n"); + deinterlace->enable = true; + deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_TOP; + break; + case V4L2_FIELD_INTERLACED_BT: + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "Enable deinterlace BT.\n"); + deinterlace->enable = true; + deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_BOTTOM; + break; + default: + v4l2_err(vout->vfd->v4l2_dev, + "field format:%d not supported yet!\n", field); + return -EINVAL; + } + + if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) { + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "tiled fmt enable deinterlace.\n"); + deinterlace->enable = true; + } + + if (deinterlace->enable && vdi_rate_double) + deinterlace->field_fmt |= IPU_DEINTERLACE_RATE_EN; + + return 0; +} + +static bool is_pp_bypass(struct mxc_vout_output *vout) +{ + if ((IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) || + (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format)) + return false; + if ((vout->task.input.width == vout->task.output.width) && + (vout->task.input.height == vout->task.output.height) && + (vout->task.input.crop.w == vout->task.output.crop.w) && + (vout->task.input.crop.h == vout->task.output.crop.h) && + (vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) && + !vout->task.input.deinterlace.enable) { + if (vout->disp_support_csc) + return true; + else if (!need_csc(vout->task.input.format, vout->disp_fmt)) + return true; + /* + * input crop show to full output which can show based on + * xres_virtual/yres_virtual + */ + } else if ((vout->task.input.crop.w == vout->task.output.crop.w) && + (vout->task.output.crop.w == vout->task.output.width) && + (vout->task.input.crop.h == vout->task.output.crop.h) && + (vout->task.output.crop.h == + vout->task.output.height) && + (vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) && + !vout->task.input.deinterlace.enable) { + if (vout->disp_support_csc) + return true; + else if (!need_csc(vout->task.input.format, vout->disp_fmt)) + return true; + } + return false; +} + +static void setup_buf_timer(struct mxc_vout_output *vout, + struct videobuf_buffer *vb) +{ + ktime_t expiry_time, now; + + /* if timestamp is 0, then default to 30fps */ + if ((vb->ts.tv_sec == 0) && (vb->ts.tv_usec == 0)) + expiry_time = ktime_add_ns(vout->start_ktime, + NSEC_PER_FRAME_30FPS * vout->frame_count); + else + expiry_time = timeval_to_ktime(vb->ts); + + now = hrtimer_cb_get_time(&vout->timer); + if ((now.tv64 > expiry_time.tv64)) { + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "warning: timer timeout already expired.\n"); + expiry_time = now; + } + + hrtimer_start(&vout->timer, expiry_time, HRTIMER_MODE_ABS); + + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "timer handler next " + "schedule: %lldnsecs\n", expiry_time.tv64); +} + +static int show_buf(struct mxc_vout_output *vout, int idx, + struct ipu_pos *ipos) +{ + struct fb_info *fbi = vout->fbi; + struct fb_var_screeninfo var; + int ret; + u32 fb_base = 0; + + memcpy(&var, &fbi->var, sizeof(var)); + + if (vout->linear_bypass_pp || vout->tiled_bypass_pp) { + /* + * crack fb base + * NOTE: should not do other fb operation during v4l2 + */ + console_lock(); + fb_base = fbi->fix.smem_start; + fbi->fix.smem_start = vout->task.output.paddr; + fbi->var.yoffset = ipos->y + 1; + var.xoffset = ipos->x; + var.yoffset = ipos->y; + var.vmode |= FB_VMODE_YWRAP; + ret = fb_pan_display(fbi, &var); + fbi->fix.smem_start = fb_base; + console_unlock(); + } else { + console_lock(); + var.yoffset = idx * fbi->var.yres; + var.vmode &= ~FB_VMODE_YWRAP; + ret = fb_pan_display(fbi, &var); + console_unlock(); + } + + return ret; +} + +static void disp_work_func(struct work_struct *work) +{ + struct mxc_vout_output *vout = + container_of(work, struct mxc_vout_output, disp_work); + struct videobuf_queue *q = &vout->vbq; + struct videobuf_buffer *vb, *vb_next = NULL; + unsigned long flags = 0; + struct ipu_pos ipos; + int ret = 0; + u32 in_fmt = 0; + u32 vdi_cnt = 0; + u32 vdi_frame; + u32 index = 0; + u32 ocrop_h = 0; + u32 o_height = 0; + u32 tiled_interlaced = 0; + bool tiled_fmt = false; + + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work begin one frame\n"); + + spin_lock_irqsave(q->irqlock, flags); + + if (list_empty(&vout->active_list)) { + v4l2_warn(vout->vfd->v4l2_dev, + "no entry in active_list, should not be here\n"); + spin_unlock_irqrestore(q->irqlock, flags); + return; + } + + vb = list_first_entry(&vout->active_list, + struct videobuf_buffer, queue); + ret = set_field_fmt(vout, vb->field); + if (ret < 0) { + spin_unlock_irqrestore(q->irqlock, flags); + return; + } + if (deinterlace_3_field(vout)) { + if (list_is_singular(&vout->active_list)) { + if (list_empty(&vout->queue_list)) { + vout->timer_stop = true; + spin_unlock_irqrestore(q->irqlock, flags); + v4l2_warn(vout->vfd->v4l2_dev, + "no enough entry for 3 fields " + "deinterlacer\n"); + return; + } + + /* + * We need to use the next vb even if it is + * not on the active list. + */ + vb_next = list_first_entry(&vout->queue_list, + struct videobuf_buffer, queue); + } else + vb_next = list_first_entry(vout->active_list.next, + struct videobuf_buffer, queue); + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "cur field_fmt:%d, next field_fmt:%d.\n", + vb->field, vb_next->field); + /* repeat the last field during field format changing */ + if ((vb->field != vb_next->field) && + (vb_next->field != V4L2_FIELD_NONE)) + vb_next = vb; + } + + spin_unlock_irqrestore(q->irqlock, flags); + +vdi_frame_rate_double: + mutex_lock(&vout->task_lock); + + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "v4l2 frame_cnt:%ld, vb_field:%d, fmt:%d\n", + vout->frame_count, vb->field, + vout->task.input.deinterlace.field_fmt); + if (vb->memory == V4L2_MEMORY_USERPTR) + vout->task.input.paddr = vb->baddr; + else + vout->task.input.paddr = videobuf_to_dma_contig(vb); + + if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN) + index = vout->vdi_frame_cnt % FB_BUFS; + else + index = vout->frame_count % FB_BUFS; + if (vout->linear_bypass_pp) { + vout->task.output.paddr = vout->task.input.paddr; + ipos.x = vout->task.input.crop.pos.x; + ipos.y = vout->task.input.crop.pos.y; + } else { + if (deinterlace_3_field(vout)) { + if (vb->memory == V4L2_MEMORY_USERPTR) + vout->task.input.paddr_n = vb_next->baddr; + else + vout->task.input.paddr_n = + videobuf_to_dma_contig(vb_next); + } + vout->task.output.paddr = vout->disp_bufs[index]; + if (vout->vdoa_1080p) { + o_height = vout->task.output.height; + ocrop_h = vout->task.output.crop.h; + vout->task.output.height = FRAME_HEIGHT_1080P; + vout->task.output.crop.h = FRAME_HEIGHT_1080P; + } + tiled_fmt = + (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) || + (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format); + if (vout->tiled_bypass_pp) { + ipos.x = vout->task.input.crop.pos.x; + ipos.y = vout->task.input.crop.pos.y; + } else if (tiled_fmt) { + vout->vdoa_task.input.paddr = vout->task.input.paddr; + if (deinterlace_3_field(vout)) + vout->vdoa_task.input.paddr_n = + vout->task.input.paddr_n; + vout->vdoa_task.output.paddr = vout->vdoa_work.paddr; + ret = ipu_queue_task(&vout->vdoa_task); + if (ret < 0) { + mutex_unlock(&vout->task_lock); + goto err; + } + vout->task.input.paddr = vout->vdoa_task.output.paddr; + in_fmt = vout->task.input.format; + vout->task.input.format = vout->vdoa_task.output.format; + if (vout->task.input.deinterlace.enable) { + tiled_interlaced = 1; + vout->task.input.deinterlace.enable = 0; + } + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "tiled queue task\n"); + } + ret = ipu_queue_task(&vout->task); + if ((!vout->tiled_bypass_pp) && tiled_fmt) + vout->task.input.format = in_fmt; + if (tiled_interlaced) + vout->task.input.deinterlace.enable = 1; + if (ret < 0) { + mutex_unlock(&vout->task_lock); + goto err; + } + if (vout->vdoa_1080p) { + vout->task.output.crop.h = ocrop_h; + vout->task.output.height = o_height; + } + } + + mutex_unlock(&vout->task_lock); + + ret = show_buf(vout, index, &ipos); + if (ret < 0) + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "show buf with ret %d\n", ret); + + if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN) { + vdi_frame = vout->task.input.deinterlace.field_fmt + & IPU_DEINTERLACE_RATE_FRAME1; + if (vdi_frame) + vout->task.input.deinterlace.field_fmt &= + ~IPU_DEINTERLACE_RATE_FRAME1; + else + vout->task.input.deinterlace.field_fmt |= + IPU_DEINTERLACE_RATE_FRAME1; + vout->vdi_frame_cnt++; + vdi_cnt++; + if (vdi_cnt < IPU_DEINTERLACE_MAX_FRAME) + goto vdi_frame_rate_double; + } + spin_lock_irqsave(q->irqlock, flags); + + list_del(&vb->queue); + + /* + * The videobuf before the last one has been shown. Set + * VIDEOBUF_DONE state here to avoid tearing issue in ic bypass + * case, which makes sure a buffer being shown will not be + * dequeued to be overwritten. It also brings side-effect that + * the last 2 buffers can not be dequeued correctly, apps need + * to take care of it. + */ + if (vout->pre2_vb) { + vout->pre2_vb->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->pre2_vb->done); + vout->pre2_vb = NULL; + } + + if (vout->linear_bypass_pp) { + vout->pre2_vb = vout->pre1_vb; + vout->pre1_vb = vb; + } else { + if (vout->pre1_vb) { + vout->pre1_vb->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->pre1_vb->done); + vout->pre1_vb = NULL; + } + vb->state = VIDEOBUF_DONE; + wake_up_interruptible(&vb->done); + } + + vout->frame_count++; + + /* pick next queue buf to setup timer */ + if (list_empty(&vout->queue_list)) + vout->timer_stop = true; + else { + vb = list_first_entry(&vout->queue_list, + struct videobuf_buffer, queue); + setup_buf_timer(vout, vb); + } + + spin_unlock_irqrestore(q->irqlock, flags); + + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work finish one frame\n"); + + return; +err: + v4l2_err(vout->vfd->v4l2_dev, "display work fail ret = %d\n", ret); + vout->timer_stop = true; + vb->state = VIDEOBUF_ERROR; + return; +} + +static enum hrtimer_restart mxc_vout_timer_handler(struct hrtimer *timer) +{ + struct mxc_vout_output *vout = container_of(timer, + struct mxc_vout_output, + timer); + struct videobuf_queue *q = &vout->vbq; + struct videobuf_buffer *vb; + unsigned long flags = 0; + + spin_lock_irqsave(q->irqlock, flags); + + /* + * put first queued entry into active, if previous entry did not + * finish, setup current entry's timer again. + */ + if (list_empty(&vout->queue_list)) { + spin_unlock_irqrestore(q->irqlock, flags); + return HRTIMER_NORESTART; + } + + /* move videobuf from queued list to active list */ + vb = list_first_entry(&vout->queue_list, + struct videobuf_buffer, queue); + list_del(&vb->queue); + list_add_tail(&vb->queue, &vout->active_list); + + if (queue_work(vout->v4l_wq, &vout->disp_work) == 0) { + v4l2_warn(vout->vfd->v4l2_dev, + "disp work was in queue already, queue buf again next time\n"); + list_del(&vb->queue); + list_add(&vb->queue, &vout->queue_list); + spin_unlock_irqrestore(q->irqlock, flags); + return HRTIMER_NORESTART; + } + + vb->state = VIDEOBUF_ACTIVE; + + spin_unlock_irqrestore(q->irqlock, flags); + + return HRTIMER_NORESTART; +} + +/* Video buffer call backs */ + +/* + * Buffer setup function is called by videobuf layer when REQBUF ioctl is + * called. This is used to setup buffers and return size and count of + * buffers allocated. After the call to this buffer, videobuf layer will + * setup buffer queue depending on the size and count of buffers + */ +static int mxc_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct mxc_vout_output *vout = q->priv_data; + unsigned int frame_size; + + if (!vout) + return -EINVAL; + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) + return -EINVAL; + + frame_size = get_frame_size(vout); + *size = PAGE_ALIGN(frame_size); + + return 0; +} + +/* + * This function will be called when VIDIOC_QBUF ioctl is called. + * It prepare buffers before give out for the display. This function + * converts user space virtual address into physical address if userptr memory + * exchange mechanism is used. + */ +static int mxc_vout_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + vb->state = VIDEOBUF_PREPARED; + return 0; +} + +/* + * Buffer queue funtion will be called from the videobuf layer when _QBUF + * ioctl is called. It is used to enqueue buffer, which is ready to be + * displayed. + * This function is protected by q->irqlock. + */ +static void mxc_vout_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct mxc_vout_output *vout = q->priv_data; + struct videobuf_buffer *active_vb; + + list_add_tail(&vb->queue, &vout->queue_list); + vb->state = VIDEOBUF_QUEUED; + + if (vout->timer_stop) { + if (deinterlace_3_field(vout) && + !list_empty(&vout->active_list)) { + active_vb = list_first_entry(&vout->active_list, + struct videobuf_buffer, queue); + setup_buf_timer(vout, active_vb); + } else { + setup_buf_timer(vout, vb); + } + vout->timer_stop = false; + } +} + +/* + * Buffer release function is called from videobuf layer to release buffer + * which are already allocated + */ +static void mxc_vout_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static int mxc_vout_mmap(struct file *file, struct vm_area_struct *vma) +{ + int ret; + struct mxc_vout_output *vout = file->private_data; + + if (!vout) + return -ENODEV; + + ret = videobuf_mmap_mapper(&vout->vbq, vma); + if (ret < 0) + v4l2_err(vout->vfd->v4l2_dev, + "offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + + return ret; +} + +static int mxc_vout_release(struct file *file) +{ + unsigned int ret = 0; + struct videobuf_queue *q; + struct mxc_vout_output *vout = file->private_data; + + if (!vout) + return 0; + + if (--vout->open_cnt == 0) { + q = &vout->vbq; + if (q->streaming) + mxc_vidioc_streamoff(file, vout, vout->type); + else { + release_disp_output(vout); + videobuf_queue_cancel(q); + } + destroy_workqueue(vout->v4l_wq); + ret = videobuf_mmap_free(q); + } + + return ret; +} + +static int mxc_vout_open(struct file *file) +{ + struct mxc_vout_output *vout = NULL; + int ret = 0; + + vout = video_drvdata(file); + + if (vout == NULL) + return -ENODEV; + + if (vout->open_cnt++ == 0) { + vout->ctrl_rotate = 0; + vout->ctrl_vflip = 0; + vout->ctrl_hflip = 0; + update_display_setting(); + ret = update_setting_from_fbi(vout, vout->fbi); + if (ret < 0) + goto err; + + vout->v4l_wq = create_singlethread_workqueue("v4l2q"); + if (!vout->v4l_wq) { + v4l2_err(vout->vfd->v4l2_dev, + "Could not create work queue\n"); + ret = -ENOMEM; + goto err; + } + + INIT_WORK(&vout->disp_work, disp_work_func); + + INIT_LIST_HEAD(&vout->queue_list); + INIT_LIST_HEAD(&vout->active_list); + + vout->fmt_init = false; + vout->frame_count = 0; + vout->vdi_frame_cnt = 0; + + vout->win_pos.x = 0; + vout->win_pos.y = 0; + vout->release = true; + } + + file->private_data = vout; + +err: + return ret; +} + +/* + * V4L2 ioctls + */ +static int mxc_vidioc_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct mxc_vout_output *vout = fh; + + strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); + strlcpy(cap->card, vout->vfd->name, sizeof(cap->card)); + cap->bus_info[0] = '\0'; + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT; + + return 0; +} + +static int mxc_vidioc_enum_fmt_vid_out(struct file *file, void *fh, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index >= NUM_MXC_VOUT_FORMATS) + return -EINVAL; + + strlcpy(fmt->description, mxc_formats[fmt->index].description, + sizeof(fmt->description)); + fmt->pixelformat = mxc_formats[fmt->index].pixelformat; + + return 0; +} + +static int mxc_vidioc_g_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mxc_vout_output *vout = fh; + struct v4l2_rect rect; + + f->fmt.pix.width = vout->task.input.width; + f->fmt.pix.height = vout->task.input.height; + f->fmt.pix.pixelformat = vout->task.input.format; + f->fmt.pix.sizeimage = get_frame_size(vout); + + if (f->fmt.pix.priv) { + rect.left = vout->task.input.crop.pos.x; + rect.top = vout->task.input.crop.pos.y; + rect.width = vout->task.input.crop.w; + rect.height = vout->task.input.crop.h; + if (copy_to_user((void __user *)f->fmt.pix.priv, + &rect, sizeof(rect))) + return -EFAULT; + } + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "frame_size:0x%x, pix_fmt:0x%x\n", + f->fmt.pix.sizeimage, + vout->task.input.format); + + return 0; +} + +static inline int ipu_try_task(struct mxc_vout_output *vout) +{ + int ret; + struct ipu_task *task = &vout->task; + +again: + ret = ipu_check_task(task); + if (ret != IPU_CHECK_OK) { + if (ret > IPU_CHECK_ERR_MIN) { + if (ret == IPU_CHECK_ERR_SPLIT_INPUTW_OVER || + ret == IPU_CHECK_ERR_W_DOWNSIZE_OVER) { + task->input.crop.w -= 8; + goto again; + } + if (ret == IPU_CHECK_ERR_SPLIT_INPUTH_OVER || + ret == IPU_CHECK_ERR_H_DOWNSIZE_OVER) { + task->input.crop.h -= 8; + goto again; + } + if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) { + if (vout->disp_support_windows) { + task->output.width -= 8; + task->output.crop.w = + task->output.width; + } else + task->output.crop.w -= 8; + goto again; + } + if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) { + if (vout->disp_support_windows) { + task->output.height -= 8; + task->output.crop.h = + task->output.height; + } else + task->output.crop.h -= 8; + goto again; + } + ret = -EINVAL; + } + } else + ret = 0; + + return ret; +} + +static inline int vdoaipu_try_task(struct mxc_vout_output *vout) +{ + int ret; + int is_1080p_stream; + size_t size; + struct ipu_task *ipu_task = &vout->task; + struct ipu_crop *icrop = &ipu_task->input.crop; + struct ipu_task *vdoa_task = &vout->vdoa_task; + u32 deinterlace = 0; + u32 in_fmt; + + if (vout->task.input.deinterlace.enable) + deinterlace = 1; + + memset(vdoa_task, 0, sizeof(*vdoa_task)); + vdoa_task->output.format = IPU_PIX_FMT_NV12; + memcpy(&vdoa_task->input, &ipu_task->input, + sizeof(ipu_task->input)); + if ((icrop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (icrop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) { + vdoa_task->input.crop.w = + ALIGN(icrop->w, IPU_PIX_FMT_TILED_NV12_MBALIGN); + vdoa_task->input.crop.h = + ALIGN(icrop->h, IPU_PIX_FMT_TILED_NV12_MBALIGN); + } + vdoa_task->output.width = vdoa_task->input.crop.w; + vdoa_task->output.height = vdoa_task->input.crop.h; + vdoa_task->output.crop.w = vdoa_task->input.crop.w; + vdoa_task->output.crop.h = vdoa_task->input.crop.h; + + size = PAGE_ALIGN(vdoa_task->input.crop.w * + vdoa_task->input.crop.h * + fmt_to_bpp(vdoa_task->output.format)/8); + if (size > vout->vdoa_work.size) { + if (vout->vdoa_work.vaddr) + free_dma_buf(vout, &vout->vdoa_work); + vout->vdoa_work.size = size; + ret = alloc_dma_buf(vout, &vout->vdoa_work); + if (ret < 0) + return ret; + } + ret = ipu_check_task(vdoa_task); + if (ret != IPU_CHECK_OK) + return -EINVAL; + + is_1080p_stream = CHECK_TILED_1080P_STREAM(vout); + if (is_1080p_stream) + ipu_task->input.crop.h = VALID_HEIGHT_1080P; + in_fmt = ipu_task->input.format; + ipu_task->input.format = vdoa_task->output.format; + ipu_task->input.height = vdoa_task->output.height; + ipu_task->input.width = vdoa_task->output.width; + if (deinterlace) + ipu_task->input.deinterlace.enable = 0; + ret = ipu_try_task(vout); + if (deinterlace) + ipu_task->input.deinterlace.enable = 1; + ipu_task->input.format = in_fmt; + + return ret; +} + +static int mxc_vout_try_task(struct mxc_vout_output *vout) +{ + int ret = 0; + struct ipu_output *output = &vout->task.output; + struct ipu_input *input = &vout->task.input; + struct ipu_crop *crop = &input->crop; + u32 o_height = 0; + u32 ocrop_h = 0; + bool tiled_fmt = false; + bool tiled_need_pp = false; + + vout->vdoa_1080p = CHECK_TILED_1080P_DISPLAY(vout); + if (vout->vdoa_1080p) { + input->crop.h = FRAME_HEIGHT_1080P; + o_height = output->height; + ocrop_h = output->crop.h; + output->height = FRAME_HEIGHT_1080P; + output->crop.h = FRAME_HEIGHT_1080P; + } + + if ((IPU_PIX_FMT_TILED_NV12 == input->format) || + (IPU_PIX_FMT_TILED_NV12F == input->format)) { + if ((input->width % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (input->height % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN)) { + v4l2_err(vout->vfd->v4l2_dev, + "ERR: tiled fmt needs 16 pixel align.\n"); + return -EINVAL; + } + if ((crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) + tiled_need_pp = true; + } else { + crop->w -= crop->w % 8; + crop->h -= crop->h % 8; + } + /* assume task.output already set by S_CROP */ + vout->linear_bypass_pp = is_pp_bypass(vout); + if (vout->linear_bypass_pp) { + v4l2_info(vout->vfd->v4l2_dev, "Bypass IC.\n"); + output->format = input->format; + } else { + /* if need CSC, choose IPU-DP or IPU_IC do it */ + if (vout->disp_support_csc) { + if (colorspaceofpixel(input->format) == YUV_CS) + output->format = IPU_PIX_FMT_UYVY; + else + output->format = IPU_PIX_FMT_RGB565; + } else { + if (colorspaceofpixel(vout->disp_fmt) == YUV_CS) + output->format = IPU_PIX_FMT_UYVY; + else + output->format = IPU_PIX_FMT_RGB565; + } + + vout->tiled_bypass_pp = false; + if ((IPU_PIX_FMT_TILED_NV12 == input->format) || + (IPU_PIX_FMT_TILED_NV12F == input->format)) { + /* check resize/rotate/flip, or csc task */ + if (!(tiled_need_pp || + (IPU_ROTATE_NONE != output->rotate) || + (input->crop.w != output->crop.w) || + (input->crop.h != output->crop.h) || + (!vout->disp_support_csc && + (colorspaceofpixel(vout->disp_fmt) == RGB_CS))) + ) { + /* IC bypass */ + output->format = IPU_PIX_FMT_NV12; + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "tiled bypass pp\n"); + vout->tiled_bypass_pp = true; + } + tiled_fmt = true; + } + + if ((!vout->tiled_bypass_pp) && tiled_fmt) + ret = vdoaipu_try_task(vout); + else + ret = ipu_try_task(vout); + } + + if (vout->vdoa_1080p) { + output->height = o_height; + output->crop.h = ocrop_h; + } + + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "icrop.w:%u, icrop.h:%u, iw:%u, ih:%u," + "ocrop.w:%u, ocrop.h:%u, ow:%u, oh:%u\n", + input->crop.w, input->crop.h, + input->width, input->height, + output->crop.w, output->crop.h, + output->width, output->height); + return ret; +} + +static int mxc_vout_try_format(struct mxc_vout_output *vout, + struct v4l2_format *f) +{ + int ret = 0; + struct v4l2_rect rect; + + if ((f->fmt.pix.field != V4L2_FIELD_NONE) && + (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format)) { + v4l2_err(vout->vfd->v4l2_dev, + "progressive tiled fmt should used V4L2_FIELD_NONE!\n"); + return -EINVAL; + } + + if (f->fmt.pix.priv && copy_from_user(&rect, + (void __user *)f->fmt.pix.priv, sizeof(rect))) + return -EFAULT; + + vout->task.input.width = f->fmt.pix.width; + vout->task.input.height = f->fmt.pix.height; + vout->task.input.format = f->fmt.pix.pixelformat; + + ret = set_field_fmt(vout, f->fmt.pix.field); + if (ret < 0) + return ret; + + if (f->fmt.pix.priv) { + vout->task.input.crop.pos.x = rect.left; + vout->task.input.crop.pos.y = rect.top; + vout->task.input.crop.w = rect.width; + vout->task.input.crop.h = rect.height; + } else { + vout->task.input.crop.pos.x = 0; + vout->task.input.crop.pos.y = 0; + vout->task.input.crop.w = f->fmt.pix.width; + vout->task.input.crop.h = f->fmt.pix.height; + } + memcpy(&vout->in_rect, &vout->task.input.crop, sizeof(vout->in_rect)); + + ret = mxc_vout_try_task(vout); + if (!ret) { + if (f->fmt.pix.priv) { + rect.width = vout->task.input.crop.w; + rect.height = vout->task.input.crop.h; + if (copy_to_user((void __user *)f->fmt.pix.priv, + &rect, sizeof(rect))) + ret = -EFAULT; + } else { + f->fmt.pix.width = vout->task.input.crop.w; + f->fmt.pix.height = vout->task.input.crop.h; + } + } + + return ret; +} + +static bool mxc_vout_need_fb_reconfig(struct mxc_vout_output *vout, + struct mxc_vout_output *pre_vout) +{ + if (!vout->vbq.streaming) + return false; + + if (vout->tiled_bypass_pp) + return true; + + if (vout->linear_bypass_pp != pre_vout->linear_bypass_pp) + return true; + + /* cropped output resolution or format are changed */ + if (vout->task.output.format != pre_vout->task.output.format || + vout->task.output.crop.w != pre_vout->task.output.crop.w || + vout->task.output.crop.h != pre_vout->task.output.crop.h) + return true; + + /* overlay: window position or resolution are changed */ + if (vout->disp_support_windows && + (vout->win_pos.x != pre_vout->win_pos.x || + vout->win_pos.y != pre_vout->win_pos.y || + vout->task.output.width != pre_vout->task.output.width || + vout->task.output.height != pre_vout->task.output.height)) + return true; + + /* background: cropped position is changed */ + if (!vout->disp_support_windows && + (vout->task.output.crop.pos.x != + pre_vout->task.output.crop.pos.x || + vout->task.output.crop.pos.y != + pre_vout->task.output.crop.pos.y)) + return true; + + return false; +} + +static int mxc_vidioc_s_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mxc_vout_output *vout = fh; + int ret = 0; + + if (vout->vbq.streaming) + return -EBUSY; + + mutex_lock(&vout->task_lock); + ret = mxc_vout_try_format(vout, f); + if (ret >= 0) + vout->fmt_init = true; + mutex_unlock(&vout->task_lock); + + return ret; +} + +static int mxc_vidioc_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cropcap) +{ + struct mxc_vout_output *vout = fh; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + cropcap->bounds = vout->crop_bounds; + cropcap->defrect = vout->crop_bounds; + + return 0; +} + +static int mxc_vidioc_g_crop(struct file *file, void *fh, + struct v4l2_crop *crop) +{ + struct mxc_vout_output *vout = fh; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + if (vout->disp_support_windows) { + crop->c.left = vout->win_pos.x; + crop->c.top = vout->win_pos.y; + crop->c.width = vout->task.output.width; + crop->c.height = vout->task.output.height; + } else { + if (vout->task.output.crop.w && vout->task.output.crop.h) { + crop->c.left = vout->task.output.crop.pos.x; + crop->c.top = vout->task.output.crop.pos.y; + crop->c.width = vout->task.output.crop.w; + crop->c.height = vout->task.output.crop.h; + } else { + crop->c.left = 0; + crop->c.top = 0; + crop->c.width = vout->task.output.width; + crop->c.height = vout->task.output.height; + } + } + + return 0; +} + +static int mxc_vidioc_s_crop(struct file *file, void *fh, + const struct v4l2_crop *crop) +{ + struct mxc_vout_output *vout = fh, *pre_vout; + struct v4l2_rect *b = &vout->crop_bounds; + struct v4l2_crop fix_up_crop; + int ret = 0; + + memcpy(&fix_up_crop, crop, sizeof(*crop)); + + if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + if (crop->c.width < 0 || crop->c.height < 0) + return -EINVAL; + + if (crop->c.width == 0) + fix_up_crop.c.width = b->width - b->left; + if (crop->c.height == 0) + fix_up_crop.c.height = b->height - b->top; + + if (crop->c.top < b->top) + fix_up_crop.c.top = b->top; + if (crop->c.top >= b->top + b->height) + fix_up_crop.c.top = b->top + b->height - 1; + if (crop->c.height > b->top - crop->c.top + b->height) + fix_up_crop.c.height = + b->top - fix_up_crop.c.top + b->height; + + if (crop->c.left < b->left) + fix_up_crop.c.left = b->left; + if (crop->c.left >= b->left + b->width) + fix_up_crop.c.left = b->left + b->width - 1; + if (crop->c.width > b->left - crop->c.left + b->width) + fix_up_crop.c.width = + b->left - fix_up_crop.c.left + b->width; + + /* stride line limitation */ + fix_up_crop.c.height -= fix_up_crop.c.height % 8; + fix_up_crop.c.width -= fix_up_crop.c.width % 8; + if ((fix_up_crop.c.width <= 0) || (fix_up_crop.c.height <= 0) || + ((fix_up_crop.c.left + fix_up_crop.c.width) > + (b->left + b->width)) || + ((fix_up_crop.c.top + fix_up_crop.c.height) > + (b->top + b->height))) { + v4l2_err(vout->vfd->v4l2_dev, "s_crop err: %d, %d, %d, %d", + fix_up_crop.c.left, fix_up_crop.c.top, + fix_up_crop.c.width, fix_up_crop.c.height); + return -EINVAL; + } + + /* the same setting, return */ + if (vout->disp_support_windows) { + if ((vout->win_pos.x == fix_up_crop.c.left) && + (vout->win_pos.y == fix_up_crop.c.top) && + (vout->task.output.crop.w == fix_up_crop.c.width) && + (vout->task.output.crop.h == fix_up_crop.c.height)) + return 0; + } else { + if ((vout->task.output.crop.pos.x == fix_up_crop.c.left) && + (vout->task.output.crop.pos.y == fix_up_crop.c.top) && + (vout->task.output.crop.w == fix_up_crop.c.width) && + (vout->task.output.crop.h == fix_up_crop.c.height)) + return 0; + } + + pre_vout = vmalloc(sizeof(*pre_vout)); + if (!pre_vout) + return -ENOMEM; + + /* wait current work finish */ + if (vout->vbq.streaming) + flush_workqueue(vout->v4l_wq); + + mutex_lock(&vout->task_lock); + + memcpy(pre_vout, vout, sizeof(*vout)); + + if (vout->disp_support_windows) { + vout->task.output.crop.pos.x = 0; + vout->task.output.crop.pos.y = 0; + vout->win_pos.x = fix_up_crop.c.left; + vout->win_pos.y = fix_up_crop.c.top; + vout->task.output.width = fix_up_crop.c.width; + vout->task.output.height = fix_up_crop.c.height; + } else { + vout->task.output.crop.pos.x = fix_up_crop.c.left; + vout->task.output.crop.pos.y = fix_up_crop.c.top; + } + + vout->task.output.crop.w = fix_up_crop.c.width; + vout->task.output.crop.h = fix_up_crop.c.height; + + /* + * must S_CROP before S_FMT, for fist time S_CROP, will not check + * ipu task, it will check in S_FMT, after S_FMT, S_CROP should + * check ipu task too. + */ + if (vout->fmt_init) { + memcpy(&vout->task.input.crop, &vout->in_rect, + sizeof(vout->in_rect)); + ret = mxc_vout_try_task(vout); + if (ret < 0) { + v4l2_err(vout->vfd->v4l2_dev, + "vout check task failed\n"); + memcpy(vout, pre_vout, sizeof(*vout)); + goto done; + } + + if (mxc_vout_need_fb_reconfig(vout, pre_vout)) { + ret = config_disp_output(vout); + if (ret < 0) + v4l2_err(vout->vfd->v4l2_dev, + "Config display output failed\n"); + } + } + +done: + vfree(pre_vout); + mutex_unlock(&vout->task_lock); + + return ret; +} + +static int mxc_vidioc_queryctrl(struct file *file, void *fh, + struct v4l2_queryctrl *ctrl) +{ + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_ROTATE: + ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0); + break; + case V4L2_CID_VFLIP: + ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); + break; + case V4L2_CID_HFLIP: + ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); + break; + case V4L2_CID_MXC_MOTION: + ret = v4l2_ctrl_query_fill(ctrl, 0, 2, 1, 0); + break; + default: + ctrl->name[0] = '\0'; + ret = -EINVAL; + } + return ret; +} + +static int mxc_vidioc_g_ctrl(struct file *file, void *fh, + struct v4l2_control *ctrl) +{ + int ret = 0; + struct mxc_vout_output *vout = fh; + + switch (ctrl->id) { + case V4L2_CID_ROTATE: + ctrl->value = vout->ctrl_rotate; + break; + case V4L2_CID_VFLIP: + ctrl->value = vout->ctrl_vflip; + break; + case V4L2_CID_HFLIP: + ctrl->value = vout->ctrl_hflip; + break; + case V4L2_CID_MXC_MOTION: + if (vout->task.input.deinterlace.enable) + ctrl->value = vout->task.input.deinterlace.motion; + else + ctrl->value = 0; + break; + default: + ret = -EINVAL; + } + return ret; +} + +static void setup_task_rotation(struct mxc_vout_output *vout) +{ + if (vout->ctrl_rotate == 0) { + if (vout->ctrl_vflip && vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_180; + else if (vout->ctrl_vflip) + vout->task.output.rotate = IPU_ROTATE_VERT_FLIP; + else if (vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP; + else + vout->task.output.rotate = IPU_ROTATE_NONE; + } else if (vout->ctrl_rotate == 90) { + if (vout->ctrl_vflip && vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_90_LEFT; + else if (vout->ctrl_vflip) + vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP; + else if (vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP; + else + vout->task.output.rotate = IPU_ROTATE_90_RIGHT; + } else if (vout->ctrl_rotate == 180) { + if (vout->ctrl_vflip && vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_NONE; + else if (vout->ctrl_vflip) + vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP; + else if (vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_VERT_FLIP; + else + vout->task.output.rotate = IPU_ROTATE_180; + } else if (vout->ctrl_rotate == 270) { + if (vout->ctrl_vflip && vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_90_RIGHT; + else if (vout->ctrl_vflip) + vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP; + else if (vout->ctrl_hflip) + vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP; + else + vout->task.output.rotate = IPU_ROTATE_90_LEFT; + } +} + +static int mxc_vidioc_s_ctrl(struct file *file, void *fh, + struct v4l2_control *ctrl) +{ + int ret = 0; + struct mxc_vout_output *vout = fh, *pre_vout; + + pre_vout = vmalloc(sizeof(*pre_vout)); + if (!pre_vout) + return -ENOMEM; + + /* wait current work finish */ + if (vout->vbq.streaming) + flush_workqueue(vout->v4l_wq); + + mutex_lock(&vout->task_lock); + + memcpy(pre_vout, vout, sizeof(*vout)); + + switch (ctrl->id) { + case V4L2_CID_ROTATE: + { + vout->ctrl_rotate = (ctrl->value/90) * 90; + if (vout->ctrl_rotate > 270) + vout->ctrl_rotate = 270; + setup_task_rotation(vout); + break; + } + case V4L2_CID_VFLIP: + { + vout->ctrl_vflip = ctrl->value; + setup_task_rotation(vout); + break; + } + case V4L2_CID_HFLIP: + { + vout->ctrl_hflip = ctrl->value; + setup_task_rotation(vout); + break; + } + case V4L2_CID_MXC_MOTION: + { + vout->task.input.deinterlace.motion = ctrl->value; + break; + } + default: + ret = -EINVAL; + goto done; + } + + if (vout->fmt_init) { + memcpy(&vout->task.input.crop, &vout->in_rect, + sizeof(vout->in_rect)); + ret = mxc_vout_try_task(vout); + if (ret < 0) { + v4l2_err(vout->vfd->v4l2_dev, + "vout check task failed\n"); + memcpy(vout, pre_vout, sizeof(*vout)); + goto done; + } + + if (mxc_vout_need_fb_reconfig(vout, pre_vout)) { + ret = config_disp_output(vout); + if (ret < 0) + v4l2_err(vout->vfd->v4l2_dev, + "Config display output failed\n"); + } + } + +done: + vfree(pre_vout); + mutex_unlock(&vout->task_lock); + + return ret; +} + +static int mxc_vidioc_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *req) +{ + int ret = 0; + struct mxc_vout_output *vout = fh; + struct videobuf_queue *q = &vout->vbq; + + if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + /* should not be here after streaming, videobuf_reqbufs will control */ + mutex_lock(&vout->task_lock); + + ret = videobuf_reqbufs(q, req); + + mutex_unlock(&vout->task_lock); + return ret; +} + +static int mxc_vidioc_querybuf(struct file *file, void *fh, + struct v4l2_buffer *b) +{ + int ret; + struct mxc_vout_output *vout = fh; + + ret = videobuf_querybuf(&vout->vbq, b); + if (!ret) { + /* return physical address */ + struct videobuf_buffer *vb = vout->vbq.bufs[b->index]; + if (b->flags & V4L2_BUF_FLAG_MAPPED) + b->m.offset = videobuf_to_dma_contig(vb); + } + + return ret; +} + +static int mxc_vidioc_qbuf(struct file *file, void *fh, + struct v4l2_buffer *buffer) +{ + struct mxc_vout_output *vout = fh; + + return videobuf_qbuf(&vout->vbq, buffer); +} + +static int mxc_vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct mxc_vout_output *vout = fh; + + if (!vout->vbq.streaming) + return -EINVAL; + + if (file->f_flags & O_NONBLOCK) + return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 1); + else + return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 0); +} + +static int set_window_position(struct mxc_vout_output *vout, + struct mxcfb_pos *pos) +{ + struct fb_info *fbi = vout->fbi; + mm_segment_t old_fs; + int ret = 0; + + if (vout->disp_support_windows) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS, + (unsigned long)pos); + set_fs(old_fs); + } + + return ret; +} + +static int config_disp_output(struct mxc_vout_output *vout) +{ + struct dma_mem *buf = NULL; + struct fb_info *fbi = vout->fbi; + struct fb_var_screeninfo var; + struct mxcfb_pos pos; + int i, fb_num, ret; + u32 fb_base; + u32 size; + u32 display_buf_size; + u32 *pixel = NULL; + u32 color; + int j; + + memcpy(&var, &fbi->var, sizeof(var)); + fb_base = fbi->fix.smem_start; + + var.xres = vout->task.output.width; + var.yres = vout->task.output.height; + if (vout->linear_bypass_pp || vout->tiled_bypass_pp) { + fb_num = 1; + /* input crop */ + if (vout->task.input.width > vout->task.output.width) + var.xres_virtual = vout->task.input.width; + else + var.xres_virtual = var.xres; + if (vout->task.input.height > vout->task.output.height) + var.yres_virtual = vout->task.input.height; + else + var.yres_virtual = var.yres; + var.rotate = vout->task.output.rotate; + var.vmode |= FB_VMODE_YWRAP; + } else { + fb_num = FB_BUFS; + var.xres_virtual = var.xres; + var.yres_virtual = fb_num * var.yres; + var.vmode &= ~FB_VMODE_YWRAP; + } + var.bits_per_pixel = fmt_to_bpp(vout->task.output.format); + var.nonstd = vout->task.output.format; + + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "set display fb to %d %d\n", + var.xres, var.yres); + + /* + * To setup the overlay fb from scratch without + * the last time overlay fb position or resolution's + * impact, we take the following steps: + * - blank fb + * - set fb position to the starting point + * - reconfigure fb + * - set fb position to a specific point + * - unblank fb + * This procedure applies to non-overlay fbs as well. + */ + console_lock(); + fbi->flags |= FBINFO_MISC_USEREVENT; + fb_blank(fbi, FB_BLANK_POWERDOWN); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + console_unlock(); + + pos.x = 0; + pos.y = 0; + ret = set_window_position(vout, &pos); + if (ret < 0) { + v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position " + "to starting point\n"); + return ret; + } + + /* Init display channel through fb API */ + var.yoffset = 0; + var.activate |= FB_ACTIVATE_FORCE; + console_lock(); + fbi->flags |= FBINFO_MISC_USEREVENT; + ret = fb_set_var(fbi, &var); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + console_unlock(); + if (ret < 0) { + v4l2_err(vout->vfd->v4l2_dev, + "ERR:%s fb_set_var ret:%d\n", __func__, ret); + return ret; + } + + ret = set_window_position(vout, &vout->win_pos); + if (ret < 0) { + v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position\n"); + return ret; + } + + if (vout->linear_bypass_pp || vout->tiled_bypass_pp) + display_buf_size = fbi->fix.line_length * fbi->var.yres_virtual; + else + display_buf_size = fbi->fix.line_length * fbi->var.yres; + for (i = 0; i < fb_num; i++) + vout->disp_bufs[i] = fbi->fix.smem_start + i * display_buf_size; + if (vout->tiled_bypass_pp) { + size = PAGE_ALIGN(vout->task.input.crop.w * + vout->task.input.crop.h * + fmt_to_bpp(vout->task.output.format)/8); + if (size > vout->vdoa_output[0].size) { + for (i = 0; i < VDOA_FB_BUFS; i++) { + buf = &vout->vdoa_output[i]; + if (buf->vaddr) + free_dma_buf(vout, buf); + buf->size = size; + ret = alloc_dma_buf(vout, buf); + if (ret < 0) + goto err; + } + } + for (i = fb_num; i < (fb_num + VDOA_FB_BUFS); i++) + vout->disp_bufs[i] = + vout->vdoa_output[i - fb_num].paddr; + } + vout->fb_smem_len = fbi->fix.smem_len; + vout->fb_smem_start = fbi->fix.smem_start; + if (fb_base != fbi->fix.smem_start) { + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, + "realloc fb mem size:0x%x@0x%lx,old paddr @0x%x\n", + fbi->fix.smem_len, fbi->fix.smem_start, fb_base); + } + + /* fill black when video config changed */ + color = colorspaceofpixel(vout->task.output.format) == YUV_CS ? + UYVY_BLACK : RGB_BLACK; + if (IS_PLANAR_PIXEL_FORMAT(vout->task.output.format)) { + size = display_buf_size * 8 / + fmt_to_bpp(vout->task.output.format); + memset(fbi->screen_base, Y_BLACK, size); + memset(fbi->screen_base + size, UV_BLACK, + display_buf_size - size); + } else { + pixel = (u32 *)fbi->screen_base; + for (i = 0; i < (display_buf_size >> 2); i++) + *pixel++ = color; + } + console_lock(); + fbi->flags |= FBINFO_MISC_USEREVENT; + ret = fb_blank(fbi, FB_BLANK_UNBLANK); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + console_unlock(); + vout->release = false; + + return ret; +err: + for (j = i - 1; j >= 0; j--) { + buf = &vout->vdoa_output[j]; + if (buf->vaddr) + free_dma_buf(vout, buf); + } + return ret; +} + +static inline void wait_for_vsync(struct mxc_vout_output *vout) +{ + struct fb_info *fbi = vout->fbi; + mm_segment_t old_fs; + + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC, + (unsigned long)NULL); + set_fs(old_fs); + } + + return; +} + +static void release_disp_output(struct mxc_vout_output *vout) +{ + struct fb_info *fbi = vout->fbi; + struct mxcfb_pos pos; + + if (vout->release) + return; + console_lock(); + fbi->flags |= FBINFO_MISC_USEREVENT; + fb_blank(fbi, FB_BLANK_POWERDOWN); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + console_unlock(); + + /* restore pos to 0,0 avoid fb pan display hang? */ + pos.x = 0; + pos.y = 0; + set_window_position(vout, &pos); + + if (get_ipu_channel(fbi) == MEM_BG_SYNC) { + console_lock(); + fbi->fix.smem_start = vout->disp_bufs[0]; + fbi->flags |= FBINFO_MISC_USEREVENT; + fb_blank(fbi, FB_BLANK_UNBLANK); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + console_unlock(); + + } + + vout->release = true; +} + +static int mxc_vidioc_streamon(struct file *file, void *fh, + enum v4l2_buf_type i) +{ + struct mxc_vout_output *vout = fh; + struct videobuf_queue *q = &vout->vbq; + int ret; + + if (q->streaming) { + v4l2_err(vout->vfd->v4l2_dev, + "video output already run\n"); + ret = -EBUSY; + goto done; + } + + if (deinterlace_3_field(vout) && list_is_singular(&q->stream)) { + v4l2_err(vout->vfd->v4l2_dev, + "deinterlacing: need queue 2 frame before streamon\n"); + ret = -EINVAL; + goto done; + } + + ret = config_disp_output(vout); + if (ret < 0) { + v4l2_err(vout->vfd->v4l2_dev, + "Config display output failed\n"); + goto done; + } + + hrtimer_init(&vout->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); + vout->timer.function = mxc_vout_timer_handler; + vout->timer_stop = true; + + vout->start_ktime = hrtimer_cb_get_time(&vout->timer); + + vout->pre1_vb = NULL; + vout->pre2_vb = NULL; + + ret = videobuf_streamon(q); +done: + return ret; +} + +static int mxc_vidioc_streamoff(struct file *file, void *fh, + enum v4l2_buf_type i) +{ + struct mxc_vout_output *vout = fh; + struct videobuf_queue *q = &vout->vbq; + int ret = 0; + + if (q->streaming) { + flush_workqueue(vout->v4l_wq); + + hrtimer_cancel(&vout->timer); + + /* + * Wait for 2 vsyncs to make sure + * frames are drained on triple + * buffer. + */ + wait_for_vsync(vout); + wait_for_vsync(vout); + + release_disp_output(vout); + + ret = videobuf_streamoff(&vout->vbq); + } + INIT_LIST_HEAD(&vout->queue_list); + INIT_LIST_HEAD(&vout->active_list); + + return ret; +} + +static const struct v4l2_ioctl_ops mxc_vout_ioctl_ops = { + .vidioc_querycap = mxc_vidioc_querycap, + .vidioc_enum_fmt_vid_out = mxc_vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = mxc_vidioc_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = mxc_vidioc_s_fmt_vid_out, + .vidioc_cropcap = mxc_vidioc_cropcap, + .vidioc_g_crop = mxc_vidioc_g_crop, + .vidioc_s_crop = mxc_vidioc_s_crop, + .vidioc_queryctrl = mxc_vidioc_queryctrl, + .vidioc_g_ctrl = mxc_vidioc_g_ctrl, + .vidioc_s_ctrl = mxc_vidioc_s_ctrl, + .vidioc_reqbufs = mxc_vidioc_reqbufs, + .vidioc_querybuf = mxc_vidioc_querybuf, + .vidioc_qbuf = mxc_vidioc_qbuf, + .vidioc_dqbuf = mxc_vidioc_dqbuf, + .vidioc_streamon = mxc_vidioc_streamon, + .vidioc_streamoff = mxc_vidioc_streamoff, +}; + +static const struct v4l2_file_operations mxc_vout_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .mmap = mxc_vout_mmap, + .open = mxc_vout_open, + .release = mxc_vout_release, +}; + +static struct video_device mxc_vout_template = { + .name = "MXC Video Output", + .fops = &mxc_vout_fops, + .ioctl_ops = &mxc_vout_ioctl_ops, + .release = video_device_release, +}; + +static struct videobuf_queue_ops mxc_vout_vbq_ops = { + .buf_setup = mxc_vout_buffer_setup, + .buf_prepare = mxc_vout_buffer_prepare, + .buf_release = mxc_vout_buffer_release, + .buf_queue = mxc_vout_buffer_queue, +}; + +static void mxc_vout_free_output(struct mxc_vout_dev *dev) +{ + int i; + int j; + struct mxc_vout_output *vout; + struct video_device *vfd; + + for (i = 0; i < dev->out_num; i++) { + vout = dev->out[i]; + vfd = vout->vfd; + if (vout->vdoa_work.vaddr) + free_dma_buf(vout, &vout->vdoa_work); + for (j = 0; j < VDOA_FB_BUFS; j++) { + if (vout->vdoa_output[j].vaddr) + free_dma_buf(vout, &vout->vdoa_output[j]); + } + if (vfd) { + if (!video_is_registered(vfd)) + video_device_release(vfd); + else + video_unregister_device(vfd); + } + kfree(vout); + } +} + +static int mxc_vout_setup_output(struct mxc_vout_dev *dev) +{ + struct videobuf_queue *q; + struct fb_info *fbi; + struct mxc_vout_output *vout; + int i, ret = 0; + + update_display_setting(); + + /* all output/overlay based on fb */ + for (i = 0; i < num_registered_fb; i++) { + fbi = registered_fb[i]; + + vout = kzalloc(sizeof(struct mxc_vout_output), GFP_KERNEL); + if (!vout) { + ret = -ENOMEM; + break; + } + + dev->out[dev->out_num] = vout; + dev->out_num++; + + vout->fbi = fbi; + vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + vout->vfd = video_device_alloc(); + if (!vout->vfd) { + ret = -ENOMEM; + break; + } + + *vout->vfd = mxc_vout_template; + vout->vfd->dev_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-4.1.13.orig/drivers/media/platform/mxc/v4l2-extra.h linux-4.1.13/drivers/media/platform/mxc/v4l2-extra.h --- linux-4.1.13.orig/drivers/media/platform/mxc/v4l2-extra.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/media/platform/mxc/v4l2-extra.h 2015-11-30 17:56:13.616135330 +0100 @@ -0,0 +1,11 @@ +/* +struct v4l2_send_command_control { + __u32 id; + __u32 value0; + __u32 value1; + char debug[256]; +}; +*/ + +#define VIDIOC_SEND_COMMAND _IOWR('V', 92, struct v4l2_send_command_control) + diff -Nur linux-4.1.13.orig/drivers/media/v4l2-core/Kconfig linux-4.1.13/drivers/media/v4l2-core/Kconfig --- linux-4.1.13.orig/drivers/media/v4l2-core/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/v4l2-core/Kconfig 2015-11-30 17:56:13.616135330 +0100 @@ -44,6 +44,10 @@ tristate depends on VIDEOBUF2_CORE +config VIDEO_V4L2_INT_DEVICE + tristate + depends on VIDEO_V4L2 + # Used by drivers that need Videobuf modules config VIDEOBUF_GEN tristate diff -Nur linux-4.1.13.orig/drivers/media/v4l2-core/Makefile linux-4.1.13/drivers/media/v4l2-core/Makefile --- linux-4.1.13.orig/drivers/media/v4l2-core/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/v4l2-core/Makefile 2015-11-30 17:56:13.616135330 +0100 @@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o +obj-$(CONFIG_V4L2_INT_DEVICE) += v4l2-int-device.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o diff -Nur linux-4.1.13.orig/drivers/media/v4l2-core/v4l2-compat-ioctl32.c linux-4.1.13/drivers/media/v4l2-core/v4l2-compat-ioctl32.c --- linux-4.1.13.orig/drivers/media/v4l2-core/v4l2-compat-ioctl32.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/v4l2-core/v4l2-compat-ioctl32.c 2015-11-30 17:56:13.616135330 +0100 @@ -251,7 +251,8 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || + put_user(kp->type, &up->type)) return -EFAULT; return __put_v4l2_format32(kp, up); } @@ -259,8 +260,8 @@ static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format))) - return -EFAULT; + copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) + return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); } @@ -330,7 +331,7 @@ __u32 reserved; }; -static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, enum v4l2_memory memory) { void __user *up_pln; @@ -359,7 +360,7 @@ return 0; } -static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, enum v4l2_memory memory) { if (copy_in_user(up32, up, 2 * sizeof(__u32)) || @@ -429,7 +430,7 @@ * by passing a very big num_planes value */ uplane = compat_alloc_user_space(num_planes * sizeof(struct v4l2_plane)); - kp->m.planes = (__force struct v4l2_plane *)uplane; + kp->m.planes = uplane; while (--num_planes >= 0) { ret = get_v4l2_plane32(uplane, uplane32, kp->memory); @@ -500,7 +501,7 @@ if (num_planes == 0) return 0; - uplane = (__force struct v4l2_plane __user *)kp->m.planes; + uplane = kp->m.planes; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); @@ -542,16 +543,7 @@ __u32 capability; __u32 flags; compat_caddr_t base; - struct { - __u32 width; - __u32 height; - __u32 pixelformat; - __u32 field; - __u32 bytesperline; - __u32 sizeimage; - __u32 colorspace; - __u32 priv; - } fmt; + struct v4l2_pix_format fmt; }; static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) @@ -561,10 +553,10 @@ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || get_user(tmp, &up->base) || get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags) || - copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) + get_user(kp->flags, &up->flags)) return -EFAULT; - kp->base = (__force void *)compat_ptr(tmp); + kp->base = compat_ptr(tmp); + get_v4l2_pix_format(&kp->fmt, &up->fmt); return 0; } @@ -575,9 +567,9 @@ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || put_user(tmp, &up->base) || put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags) || - copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) + put_user(kp->flags, &up->flags)) return -EFAULT; + put_v4l2_pix_format(&kp->fmt, &up->fmt); return 0; } @@ -669,15 +661,11 @@ n * sizeof(struct v4l2_ext_control32))) return -EFAULT; kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); - kp->controls = (__force struct v4l2_ext_control *)kcontrols; + kp->controls = kcontrols; while (--n >= 0) { - u32 id; - if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; - if (get_user(id, &kcontrols->id)) - return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(kcontrols->id)) { void __user *s; if (get_user(p, &ucontrols->string)) @@ -695,8 +683,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = - (__force struct v4l2_ext_control __user *)kp->controls; + struct v4l2_ext_control __user *kcontrols = kp->controls; int n = kp->count; compat_caddr_t p; @@ -718,14 +705,11 @@ while (--n >= 0) { unsigned size = sizeof(*ucontrols); - u32 id; - if (get_user(id, &kcontrols->id)) - return -EFAULT; /* Do not modify the pointer when copying a pointer control. The contents of the pointer was changed, not the pointer itself. */ - if (ctrl_is_pointer(id)) + if (ctrl_is_pointer(kcontrols->id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -754,14 +738,14 @@ copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || put_user(kp->pending, &up->pending) || put_user(kp->sequence, &up->sequence) || - compat_put_timespec(&kp->timestamp, &up->timestamp) || + put_compat_timespec(&kp->timestamp, &up->timestamp) || put_user(kp->id, &up->id) || copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) return -EFAULT; return 0; } -struct v4l2_edid32 { +struct v4l2_subdev_edid32 { __u32 pad; __u32 start_block; __u32 blocks; @@ -769,31 +753,31 @@ compat_caddr_t edid; }; -static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) { u32 tmp; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_subdev_edid32)) || get_user(kp->pad, &up->pad) || get_user(kp->start_block, &up->start_block) || get_user(kp->blocks, &up->blocks) || get_user(tmp, &up->edid) || copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - kp->edid = (__force u8 *)compat_ptr(tmp); + kp->edid = compat_ptr(tmp); return 0; } -static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) { u32 tmp = (u32)((unsigned long)kp->edid); - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_subdev_edid32)) || put_user(kp->pad, &up->pad) || put_user(kp->start_block, &up->start_block) || put_user(kp->blocks, &up->blocks) || put_user(tmp, &up->edid) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -837,7 +821,7 @@ struct v4l2_ext_controls v2ecs; struct v4l2_event v2ev; struct v4l2_create_buffers v2crt; - struct v4l2_edid v2edid; + struct v4l2_subdev_edid v2edid; unsigned long vx; int vi; } karg; @@ -987,9 +971,9 @@ err = put_v4l2_event32(&karg.v2ev, up); break; - case VIDIOC_G_EDID: - case VIDIOC_S_EDID: - err = put_v4l2_edid32(&karg.v2edid, up); + case VIDIOC_SUBDEV_G_EDID: + case VIDIOC_SUBDEV_S_EDID: + err = put_v4l2_subdev_edid32(&karg.v2edid, up); break; case VIDIOC_G_FMT: @@ -1027,14 +1011,104 @@ if (!file->f_op->unlocked_ioctl) return ret; - if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE) + switch (cmd) { + case VIDIOC_QUERYCAP: + case VIDIOC_RESERVED: + case VIDIOC_ENUM_FMT: + case VIDIOC_G_FMT32: + case VIDIOC_S_FMT32: + case VIDIOC_REQBUFS: + case VIDIOC_QUERYBUF32: + case VIDIOC_G_FBUF32: + case VIDIOC_S_FBUF32: + case VIDIOC_OVERLAY32: + case VIDIOC_QBUF32: + case VIDIOC_EXPBUF: + case VIDIOC_DQBUF32: + case VIDIOC_STREAMON32: + case VIDIOC_STREAMOFF32: + case VIDIOC_G_PARM: + case VIDIOC_S_PARM: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_ENUMSTD32: + case VIDIOC_ENUMINPUT32: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + case VIDIOC_G_AUDIO: + case VIDIOC_S_AUDIO: + case VIDIOC_QUERYCTRL: + case VIDIOC_QUERYMENU: + case VIDIOC_G_INPUT32: + case VIDIOC_S_INPUT32: + case VIDIOC_G_OUTPUT32: + case VIDIOC_S_OUTPUT32: + case VIDIOC_ENUMOUTPUT: + case VIDIOC_G_AUDOUT: + case VIDIOC_S_AUDOUT: + case VIDIOC_G_MODULATOR: + case VIDIOC_S_MODULATOR: + case VIDIOC_S_FREQUENCY: + case VIDIOC_G_FREQUENCY: + case VIDIOC_CROPCAP: + case VIDIOC_G_CROP: + case VIDIOC_S_CROP: + case VIDIOC_G_SELECTION: + case VIDIOC_S_SELECTION: + case VIDIOC_G_JPEGCOMP: + case VIDIOC_S_JPEGCOMP: + case VIDIOC_QUERYSTD: + case VIDIOC_TRY_FMT32: + case VIDIOC_ENUMAUDIO: + case VIDIOC_ENUMAUDOUT: + case VIDIOC_G_PRIORITY: + case VIDIOC_S_PRIORITY: + case VIDIOC_G_SLICED_VBI_CAP: + case VIDIOC_LOG_STATUS: + case VIDIOC_G_EXT_CTRLS32: + case VIDIOC_S_EXT_CTRLS32: + case VIDIOC_TRY_EXT_CTRLS32: + case VIDIOC_ENUM_FRAMESIZES: + case VIDIOC_ENUM_FRAMEINTERVALS: + case VIDIOC_G_ENC_INDEX: + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: + case VIDIOC_DECODER_CMD: + 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: + case VIDIOC_DQEVENT: + case VIDIOC_DQEVENT32: + case VIDIOC_SUBSCRIBE_EVENT: + case VIDIOC_UNSUBSCRIBE_EVENT: + case VIDIOC_CREATE_BUFS32: + case VIDIOC_PREPARE_BUF32: + case VIDIOC_ENUM_DV_TIMINGS: + case VIDIOC_QUERY_DV_TIMINGS: + case VIDIOC_DV_TIMINGS_CAP: + case VIDIOC_ENUM_FREQ_BANDS: + case VIDIOC_SUBDEV_G_EDID32: + case VIDIOC_SUBDEV_S_EDID32: ret = do_video_ioctl(file, cmd, arg); - else if (vdev->fops->compat_ioctl32) - ret = vdev->fops->compat_ioctl32(file, cmd, arg); + break; - if (ret == -ENOIOCTLCMD) - pr_warn("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", - _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd); + default: + if (vdev->fops->compat_ioctl32) + ret = vdev->fops->compat_ioctl32(file, cmd, arg); + + if (ret == -ENOIOCTLCMD) + printk(KERN_WARNING "compat_ioctl32: " + "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", + _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), + cmd); + break; + } return ret; } EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); diff -Nur linux-4.1.13.orig/drivers/media/v4l2-core/v4l2-dev.c linux-4.1.13/drivers/media/v4l2-core/v4l2-dev.c --- linux-4.1.13.orig/drivers/media/v4l2-core/v4l2-dev.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/v4l2-core/v4l2-dev.c 2015-11-30 17:56:13.616135330 +0100 @@ -563,6 +563,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); diff -Nur linux-4.1.13.orig/drivers/media/v4l2-core/v4l2-ioctl.c linux-4.1.13/drivers/media/v4l2-core/v4l2-ioctl.c --- linux-4.1.13.orig/drivers/media/v4l2-core/v4l2-ioctl.c 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/media/v4l2-core/v4l2-ioctl.c 2015-11-30 17:56:13.616135330 +0100 @@ -26,6 +26,7 @@ #include #include #include +#include #include #define CREATE_TRACE_POINTS @@ -649,6 +650,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; @@ -2002,6 +2017,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) { @@ -2256,6 +2283,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-4.1.13.orig/drivers/mfd/Kconfig linux-4.1.13/drivers/mfd/Kconfig --- linux-4.1.13.orig/drivers/mfd/Kconfig 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/mfd/Kconfig 2015-11-30 17:56:13.616135330 +0100 @@ -207,6 +207,13 @@ Additional drivers must be enabled in order to use the specific features 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_DLN2 tristate "Diolan DLN2 support" select MFD_CORE @@ -1466,5 +1473,13 @@ System Registers are the platform configuration block on the ARM Ltd. Versatile Express board. +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-4.1.13.orig/drivers/mfd/Makefile linux-4.1.13/drivers/mfd/Makefile --- linux-4.1.13.orig/drivers/mfd/Makefile 2015-11-09 23:34:10.000000000 +0100 +++ linux-4.1.13/drivers/mfd/Makefile 2015-11-30 17:56:13.616135330 +0100 @@ -185,3 +185,5 @@ intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o +obj-$(CONFIG_MFD_MXC_HDMI) += mxc-hdmi-core.o +obj-$(CONFIG_MFD_TDA1997X) += tda1997x-core.o diff -Nur linux-4.1.13.orig/drivers/mfd/mxc-hdmi-core.c linux-4.1.13/drivers/mfd/mxc-hdmi-core.c --- linux-4.1.13.orig/drivers/mfd/mxc-hdmi-core.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.1.13/drivers/mfd/mxc-hdmi-core.c 2015-11-30 17:56:13.620135063 +0100 @@ -0,0 +1,795 @@ +/* + * 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