Merge "gpu: ion: Add support for device tree." into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
new file mode 100644
index 0000000..a39356c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -0,0 +1,78 @@
+DCVS Core Info
+
+This data describes specific DCVS tuning data for a specific core (CPU, GPU,
+etc).
+
+Required properties:
+
+- qcom,core-max-time-us: Maximum time limit in micorseconds for switching clock rate.
+ Limited to this value if switching time takes longer than this limit. Typical value is 100000.
+- qcom,algo-slack-time-us: Time in microseconds after which the QoS guarantee will kick in
+ and the clock rate will increased as necessary. Typical value is about 30000.
+- qcom,algo-disable-pc-threshold: If core frequency (kHz) is higher than this value, power collapse is disallowed. Set to 0 for GPU.
+- qcom,algo-ss-window-size: Steady state window size in microseconds.
+- qcom,algo-ss-util-pct: When determining the steady state level, this percentage value is used to provide headroom
+ from the utilized cpu to the selected level.
+- qcom,algo-ee-max-util-pct: When determining the level with the lowest energy, any level that exceeds this busy
+ percentage, for the measured work in the last window, is disqualified for performance reasons.
+- qcom,algo-ss-iobusy-conv: Used to convert correlation time into assumed IO Busy time, which is removed
+ from measured elapsed time when computing cpu utilization.
+
+
+A number of frequency levels are represented as sub-nodes:
+
+required properties:
+- reg: The index of the frequency entry
+- qcom,freq The frequency of the DVS entry (in kHZ)
+- qcom,idle-energy: The idle energy cost of the entry (in micro watts)
+- qcom,active-energy: The active energy cost of the entry (in micro watts)
+
+Sample:
+
+qcom,kgsl-3d0@fdb00000 {
+ ...
+ qcom,dcvs-core-info {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,dcvs-core-info";
+
+ qcom,core-max-time-us = <100000>;
+ qcom,algo-slack-time-us = <39000>;
+ qcom,algo-disable-pc-threshold = <86000>;
+ qcom,algo-ss-window-size = <1000000>;
+ qcom,algo-ss-util-pct = <95>;
+ qcom,algo-em-max-util-pct = <97>;
+ qcom,algo-ss-iobusy-conv = <100>;
+
+ qcom,dcvs-freq@0 {
+ reg = <0>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <333932>;
+ };
+
+ qcom,dcvs-freq@1 {
+ reg = <1>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <497532>;
+ };
+
+ qcom,dcvs-freq@2 {
+ reg = <2>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <707610>;
+ };
+
+ qcom,dcvs-freq@3 {
+ reg = <3>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <844545>;
+ };
+ };
+ ...
+};
+
diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
new file mode 100644
index 0000000..d50a21c
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
@@ -0,0 +1,40 @@
+Adreno Power Levels
+
+The Adreno GPU definition should include a variable number of power levels
+defining the GPU and bus frequencies for the levels that the GPU can operate at.
+
+Required properties:
+
+- compatible: The compatible name for the object (qcom,gpu-pwrlevels)
+
+Each powerlevel definition is as follows:
+
+- reg: Index of the power level (lower is considered higher
+ performance)
+- qcom,gpu-freq: The GPU frequency for the power level (in HZ)
+- qcom,bus-freq: An index representing the bus scaling usecase appropriate
+ for the power level
+- qcom,io-fraction: A number indicating the fraction of the CPU I/O busy that
+ this operating point should represent.
+
+Sample usage:
+
+qcom,kgsl-3d0@fdb00000 {
+ ...
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <5000000000>;
+ qcom,bus-freq = <3>;
+ qcom,io_fraction = <0>;
+ };
+ };
+
+ ...
+};
+
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
new file mode 100644
index 0000000..16925fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -0,0 +1,159 @@
+Qualcomm GPU
+
+Qualcomm Adreno GPU
+
+Required properties:
+- label: A string used as a descriptive name for the device.
+- compatible: Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d"
+- reg: Specifies the base address and address size for this device.
+- interrupts: Interrupt mapping for GPU IRQ.
+- interrupt-names: String property to describe the name of the interrupt.
+- qcom,id: An integer used as an identification number for the device.
+
+- qcom,clk-map: A bit map value for clocks controlled by kgsl.
+ KGSL_CLK_SRC 0x00000001
+ KGSL_CLK_CORE 0x00000002
+ KGSL_CLK_IFACE 0x00000004
+ KGSL_CLK_MEM 0x00000008
+ KGSL_CLK_MEM_IFACE 0x00000010
+ KGSL_CLK_AXI 0x00000020
+
+Bus Scaling Data:
+- qcom,grp3d-vectors: A series of 4 cell properties, format of which is:
+ <src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 1
+ <src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 2
+ <.. .. .. ..>, <.. .. .. ..>; // For Bus Scaling Usecase n
+ This property is a series of all vectors for all Bus Scaling Usecases.
+ Each set of vectors for each usecase describes bandwidth votes for a combination
+ of src/dst ports. The driver will set the desired use case based on the selected
+ power level and the desired bandwidth vote will be registered for the port pairs.
+ Current values of src are:
+ 0 = MSM_BUS_MASTER_GRAPHICS_3D
+ 1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1
+ 2 = MSM_BUS_MASTER_V_OCMEM_GFX3D
+ Current values of dst are:
+ 0 = MSM_BUS_SLAVE_EBI_CH0
+ 1 = MSM_BUS_SLAVE_OCMEM
+ ab: Represents aggregated bandwidth. This value is 0 for Graphics.
+ ib: Represents instantaneous bandwidth. This value has a range <0 8000 MB/s>
+- qcom,grp3d-num-vectors-per-usecase: This represents the number of vectors in each Bus Scaling Usecase.
+- qcom,grp3d-num-bus-scale-usecases: This is the the number of Bus Scaling use cases defined in the vectors property
+
+GDSC Oxili Regulators:
+- vddcx-supply: Phandle for vddcx regulator device node.
+- vdd-supply: Phandle for vdd regulator device node.
+
+IOMMU Data:
+- iommu: Phandle for the KGSL IOMMU device node
+
+GPU Power levels:
+- qcom,gpu-pwrlevels: Container for the GPU Power Levels (see
+ adreno-pwrlevels.txt)
+
+DCVS Core info
+- qcom,dcvs-core-info Container for the DCVS core info (see
+ dcvs-core-info.txt)
+
+Optional Properties:
+- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
+ and when coming back out of resume
+- qcom,idle-timeout: This property represents the time in microseconds for idle timeout.
+- qcom,nap-allowed: Boolean. <0> or <1> to disable/enable nap.
+- qcom,chipid: If it exists this property is used to replace
+ the chip identification read from the GPU hardware.
+ This is used to override faulty hardware readings.
+
+Example of A330 GPU in MSM8974:
+
+/ {
+ qcom,kgsl-3d0@fdb00000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ reg = <0xfdb00000 0x20000>;
+ reg-names = "kgsl_3d0_reg_memory";
+ interrupts = <0 33 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x03030000>;
+
+ /* Power Settings */
+
+ qcom,initial-pwrlevel = <1>;
+ qcom,idle-timeout = <83>; //<HZ/12>
+ qcom,nap-allowed = <1>;
+ qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
+
+ /* Bus Scale Settings */
+ qcom,grp3d-vectors = <0 0 0 0>, <2 1 0 0>,
+ <0 0 0 2000>, <2 1 0 3000>,
+ <0 0 0 4000>, <2 1 0 5000>,
+ <0 0 0 6400>, <2 1 0 7600>;
+ qcom,grp3d-num-vectors-per-usecase = <2>;
+ qcom,grp3d-num-bus-scale-usecases = <4>;
+
+ /* GDSC oxili regulators */
+ vddcx-supply = <&gdsc_oxili_cx>;
+ vdd-supply = <&gdsc_oxili_gx>;
+
+ /* IOMMU Data */
+ iommu = <&kgsl>;
+
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <5000000000>;
+ qcom,bus-freq = <3>;
+ qcom,io-fraction = <0>;
+ };
+ };
+
+ qcom,dcvs-core-info {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,dcvs-core-info";
+
+ qcom,core-max-time-us = <100000>;
+ qcom,algo-slack-time-us = <39000>;
+ qcom,algo-disable-pc-threshold = <86000>;
+ qcom,algo-ss-window-size = <1000000>;
+ qcom,algo-ss-util-pct = <95>;
+ qcom,algo-em-max-util-pct = <97>;
+ qcom,algo-ss-iobusy-conv = <100>;
+
+ qcom,dcvs-freq@0 {
+ reg = <0>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <333932>;
+ };
+
+ qcom,dcvs-freq@1 {
+ reg = <1>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <497532>;
+ };
+
+ qcom,dcvs-freq@2 {
+ reg = <2>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <707610>;
+ };
+
+ qcom,dcvs-freq@3 {
+ reg = <3>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <844545>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-server.txt b/Documentation/devicetree/bindings/media/video/msm-cam-server.txt
new file mode 100644
index 0000000..2b6f513
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-server.txt
@@ -0,0 +1,11 @@
+* Qualcomm MSM Camera Server
+
+Required properties:
+- compatible :
+ - "qcom,cam_server"
+
+Example:
+
+ qcom,cam_server {
+ compatible = "qcom,cam_server";
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
new file mode 100644
index 0000000..75916e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CCI
+
+Required properties:
+- cell-index: cci hardware core index
+- compatible :
+ - "qcom,cci"
+- reg : offset and length of the register set for the device
+ for the cci operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the cci interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+ property defined.
+
+Example:
+
+ qcom,cci@0xfda0c000 {
+ cell-index = <0>;
+ compatible = "qcom,cci";
+ reg = <0xfda0c000 0x300>;
+ reg-names = "cci";
+ interrupts = <0 50 0>;
+ interrupt-names = "cci";
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
new file mode 100644
index 0000000..5cf0154
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
@@ -0,0 +1,25 @@
+* Qualcomm MSM CPP
+
+Required properties:
+- cell-index: cpp hardware core index
+- compatible :
+ - "qcom,cpp"
+- reg : offset and length of the register set for the device
+ for the cpp operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the cpp interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+ property defined.
+- vdd-supply: phandle to GDSC regulator controlling VFE & CPP core.
+
+Example:
+
+ qcom,cpp@0xfda04000 {
+ cell-index = <0>;
+ compatible = "qcom,cpp";
+ reg = <0xfda04000 0x100>;
+ reg-names = "cpp";
+ interrupts = <0 49 0>;
+ interrupt-names = "cpp";
+ vdd-supply = <&gdsc_vfe>;
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt b/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt
new file mode 100644
index 0000000..90bdbda
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CSI Phy
+
+Required properties:
+- cell-index: csi phy hardware core index
+- compatible :
+ - "qcom,csiphy"
+- reg : offset and length of the register set for the device
+ for the csiphy operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the csiphy interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+ property defined.
+
+Example:
+
+ qcom,csiphy@fda0ac00 {
+ cell-index = <0>;
+ compatible = "qcom,csiphy";
+ reg = <0xfda0ac00 0x200>;
+ reg-names = "csiphy";
+ interrupts = <0 78 0>;
+ interrupt-names = "csiphy";
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-csid.txt b/Documentation/devicetree/bindings/media/video/msm-csid.txt
new file mode 100644
index 0000000..76a2825
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-csid.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CSID
+
+Required properties:
+- cell-index: csid hardware core index
+- compatible :
+ - "qcom,csid"
+- reg : offset and length of the register set for the device
+ for the csid operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the csid interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+ property defined.
+
+Example:
+
+ qcom,csid@fda08000 {
+ cell-index = <0>;
+ compatible = "qcom,csid";
+ reg = <0xfda08000 0x200>;
+ reg-names = "csid";
+ interrupts = <0 51 0>;
+ interrupt-names = "csiphy";
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt b/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt
new file mode 100644
index 0000000..63fb7d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt
@@ -0,0 +1,18 @@
+* Qualcomm MSM IRQ Router
+
+Required properties:
+- cell-index: irq router hardware core index
+- compatible :
+ - "qcom,irqrouter"
+- reg : offset and length of the register set for the device
+ for the irqrouter operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+
+Example:
+
+ qcom,irqrouter@0xfda0c000 {
+ cell-index = <0>;
+ compatible = "qcom,irqrouter";
+ reg = <0xfda00000 0x100>;
+ reg-names = "irqrouter";
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-ispif.txt b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
new file mode 100644
index 0000000..ff33b17
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM ISPIF
+
+Required properties:
+- cell-index: ispif hardware core index
+- compatible :
+ - "qcom,ispif"
+- reg : offset and length of the register set for the device
+ for the ispif operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the ispif interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+ property defined.
+
+Example:
+
+ qcom,ispif@0xfda0a000 {
+ cell-index = <0>;
+ compatible = "qcom,ispif";
+ reg = <0xfda0a000 0x300>;
+ reg-names = "ispif";
+ interrupts = <0 55 0>;
+ interrupt-names = "ispif";
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-jpeg.txt b/Documentation/devicetree/bindings/media/video/msm-jpeg.txt
new file mode 100644
index 0000000..41e0b3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-jpeg.txt
@@ -0,0 +1,25 @@
+* Qualcomm MSM JPEG
+
+Required properties:
+- cell-index: jpeg hardware core index
+- compatible :
+ - "qcom,jpeg"
+- reg : offset and length of the register set for the device
+ for the jpeg operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the jpeg interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+ property defined.
+- vdd-supply: phandle to GDSC regulator controlling JPEG core.
+
+Example:
+
+ qcom,jpeg@0xfda20000 {
+ cell-index = <0>;
+ compatible = "qcom,jpeg";
+ reg = <0xfda20000 0x400>;
+ reg-names = "jpeg";
+ interrupts = <0 60 0>;
+ interrupt-names = "jpeg";
+ vdd-supply = <&gdsc_jpeg>;
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
new file mode 100644
index 0000000..7a70cac
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
@@ -0,0 +1,25 @@
+* Qualcomm MSM VFE
+
+Required properties:
+- cell-index: vfe hardware core index
+- compatible :
+ - "qcom,vfe"
+- reg : offset and length of the register set for the device
+ for the vfe operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the vfe interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+ property defined.
+- vdd-supply: phandle to GDSC regulator controlling VFE core.
+
+Example:
+
+ qcom,vfe@0xfda10000 {
+ cell-index = <0>;
+ compatible = "qcom,vfe";
+ reg = <0xfda10000 0x1000>;
+ reg-names = "vfe";
+ interrupts = <0 58 0>;
+ interrupt-names = "vfe";
+ vdd-supply = <&gdsc_vfe>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 95ddf34..0516dff 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -49,3 +49,70 @@
qcom,hsusb-otg-pclk-src-name = "dfab_usb_clk";
qcom,hsusb-otg-pmic-id-irq = <47>
};
+
+BAM:
+
+Required properties:
+- compatible: should be "qcom,usb-bam-msm"
+- regs: offset and length of the register set in the memory map
+- interrupts: IRQ line
+- qcom,usb-active-bam: active BAM type. Can be one of
+ 0 - HSUSB_BAM
+ 1 - HSIC_BAM
+- qcom,usb-total-bam-num: total number of BAMs that are supported
+- qcom,usb-bam-num-pipes: max number of pipes that can be used
+- qcom,usb-base-address: physical base address of the BAM
+
+A number of USB BAM pipe parameters are represented as sub-nodes:
+
+Subnode Required:
+- label: a string describing the pipe's direction and use
+- qcom,usb-bam-type: BAM type. Can be one of
+ 0 - HSUSB_BAM
+ 1 - HSIC_BAM
+- qcom,src-bam-physical-address: source BAM physical address
+- qcom,src-bam-pipe-index: source BAM pipe index
+- qcom,dst-bam-physical-address: destination BAM physical address
+- qcom,dst-bam-pipe-index: destination BAM pipe index
+- qcom,data-fifo-offset: data fifo offset address
+- qcom,data-fifo-size: data fifo size
+- qcom,descriptor-fifo-offset: descriptor fifo offset address
+- qcom,descriptor-fifo-size: descriptor fifo size
+
+Example USB BAM controller device node:
+
+ qcom,usbbam@f9304000 {
+ compatible = "qcom,usb-bam-msm";
+ reg = <0xf9304000 0x9000>;
+ interrupts = <0 132 0>;
+ qcom,usb-active-bam = <0>;
+ qcom,usb-total-bam-num = <1>;
+ qcom,usb-bam-num-pipes = <16>;
+ qcom,usb-base-address = <0xf9200000>;
+
+ qcom,pipe1 {
+ label = "usb-to-peri-qdss-dwc3";
+ qcom,usb-bam-type = <0>;
+ qcom,src-bam-physical-address = <0>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0>;
+ qcom,data-fifo-size = <0>;
+ qcom,descriptor-fifo-offset = <0>;
+ qcom,descriptor-fifo-size = <0>;
+ };
+
+ qcom,pipe2 {
+ label = "peri-to-usb-qdss-dwc3";
+ qcom,usb-bam-type = <0>;
+ qcom,src-bam-physical-address = <0xfc37C000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0xf9304000>;
+ qcom,dst-bam-pipe-index = <2>;
+ qcom,data-fifo-offset = <0xf0000>;
+ qcom,data-fifo-size = <0x4000>;
+ qcom,descriptor-fifo-offset = <0xf4000>;
+ qcom,descriptor-fifo-size = <0x1400>;
+ };
+ };
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
new file mode 100644
index 0000000..a972d7f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -0,0 +1,126 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+/ {
+ qcom,kgsl-3d0@fdb00000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ reg = <0xfdb00000 0x20000>;
+ reg-names = "kgsl_3d0_reg_memory";
+ interrupts = <0 33 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x03030000>;
+
+ qcom,initial-pwrlevel = <1>;
+
+ qcom,idle-timeout = <83>; //<HZ/12>
+ qcom,nap-allowed = <1>;
+ qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
+
+ /* Bus Scale Settings */
+ qcom,grp3d-vectors = <0 0 0 0>, <2 1 0 0>,
+ <0 0 0 2000>, <2 1 0 3000>,
+ <0 0 0 4000>, <2 1 0 5000>,
+ <0 0 0 6400>, <2 1 0 7600>;
+ qcom,grp3d-num-vectors-per-usecase = <2>;
+ qcom,grp3d-num-bus-scale-usecases = <4>;
+
+ /* GDSC oxili regulators */
+ vddcx-supply = <&gdsc_oxili_cx>;
+ vdd-supply = <&gdsc_oxili_gx>;
+
+ /* Power levels */
+
+ /* IOMMU Data */
+ iommu = <&kgsl_iommu>;
+
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <500000000>;
+ qcom,bus-freq = <3>;
+ qcom,io-fraction = <0>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <333000000>;
+ qcom,bus-freq = <2>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <200000000>;
+ qcom,bus-freq = <1>;
+ qcom,io-fraction = <100>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <27000000>;
+ qcom,bus-freq = <0>;
+ qcom,io-fraction = <0>;
+ };
+ };
+
+ qcom,dcvs-core-info {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,dcvs-core-info";
+
+ qcom,core-max-time-us = <100000>;
+ qcom,algo-slack-time-us = <39000>;
+ qcom,algo-disable-pc-threshold = <86000>;
+ qcom,algo-ss-window-size = <1000000>;
+ qcom,algo-ss-util-pct = <95>;
+ qcom,algo-em-max-util-pct = <97>;
+ qcom,algo-ss-iobusy-conv = <100>;
+
+ qcom,dcvs-freq@0 {
+ reg = <0>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <333932>;
+ };
+
+ qcom,dcvs-freq@1 {
+ reg = <1>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <497532>;
+ };
+
+ qcom,dcvs-freq@2 {
+ reg = <2>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <707610>;
+ };
+
+ qcom,dcvs-freq@3 {
+ reg = <3>;
+ qcom,freq = <0>;
+ qcom,idle-energy = <0>;
+ qcom,active-energy = <844545>;
+ };
+ };
+
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index b376544..a187223 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -127,9 +127,9 @@
rpm-regulator-smpb3 {
status = "okay";
pm8841_s3: regulator-s3 {
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- qcom,init-voltage = <1150000>;
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,init-voltage = <1050000>;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index d34849c..12f46a3 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -14,6 +14,7 @@
/include/ "msm8974_pm.dtsi"
/include/ "msm8974-iommu.dtsi"
/include/ "msm-gdsc.dtsi"
+/include/ "msm8974-gpu.dtsi"
/ {
model = "Qualcomm MSM 8974";
@@ -599,8 +600,8 @@
reg-names = "tsens_physical", "tsens_eeprom_physical";
interrupts = <0 184 0>;
qcom,sensors = <11>;
- qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
- 1176 1176>;
+ qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+ 3200 3200>;
};
qcom,msm-rtb {
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index f3b2219..a51b76d 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -417,8 +417,6 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
-CONFIG_MSM_IOMMU=y
-# CONFIG_IOMMU_PGTABLES_L2 is not set
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 4748496..5d19237 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -419,8 +419,6 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
-CONFIG_MSM_IOMMU=y
-# CONFIG_IOMMU_PGTABLES_L2 is not set
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 66e71fc..795a5a7 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -285,6 +285,8 @@
CONFIG_INPUT_MISC=y
CONFIG_INPUT_PMIC8XXX_PWRKEY=y
CONFIG_INPUT_UINPUT=y
+CONFIG_STM_LIS3DH=y
+CONFIG_INPUT_MPU3050=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_N_SMUX=y
CONFIG_N_SMUX_LOOPBACK=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 3731845..4674584 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -289,6 +289,8 @@
CONFIG_INPUT_MISC=y
CONFIG_INPUT_PMIC8XXX_PWRKEY=y
CONFIG_INPUT_UINPUT=y
+CONFIG_STM_LIS3DH=y
+CONFIG_INPUT_MPU3050=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_N_SMUX=y
CONFIG_N_SMUX_LOOPBACK=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 00b4164..655908b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -52,6 +52,10 @@
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -147,6 +151,8 @@
CONFIG_POWER_SUPPLY=y
# CONFIG_BATTERY_MSM is not set
# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_MEDIA_SUPPORT=y
@@ -237,8 +243,6 @@
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-CONFIG_EARLY_PRINTK=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_SHA256=y
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 94aa75e..bc81696 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -37,9 +37,11 @@
#endif
/*
- * The fixup involves disabling interrupts during execution of the WFE
- * instruction. This could potentially lead to deadlock if a thread is trying
- * to acquire a spinlock which is being released from an interrupt context.
+ * The fixup involves disabling FIQs during execution of the WFE instruction.
+ * This could potentially lead to deadlock if a thread is trying to acquire a
+ * spinlock which is being released from an FIQ. This should not be a problem
+ * because FIQs are handled by the secure environment and do not directly
+ * manipulate spinlocks.
*/
#ifdef CONFIG_MSM_KRAIT_WFE_FIXUP
#define WFE_SAFE(fixup, tmp) \
@@ -47,7 +49,7 @@
" cmp " fixup ", #0\n" \
" wfeeq\n" \
" beq 10f\n" \
-" cpsid if\n" \
+" cpsid f\n" \
" mrc p15, 7, " fixup ", c15, c0, 5\n" \
" bic " fixup ", " fixup ", #0x10000\n" \
" mcr p15, 7, " fixup ", c15, c0, 5\n" \
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 7c44acd..7a8c2d6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -966,7 +966,7 @@
* SP points to a minimal amount of processor-private memory, the address
* of which is copied into r0 for the mode specific abort handler.
*/
- .macro vector_stub, name, mode, correction=0
+ .macro vector_stub, name, mode, fixup, correction=0
.align 5
vector_\name:
@@ -995,6 +995,18 @@
and lr, lr, #0x0f
THUMB( adr r0, 1f )
THUMB( ldr lr, [r0, lr, lsl #2] )
+ .if \fixup
+#ifdef CONFIG_MSM_KRAIT_WFE_FIXUP
+ ldr r0, .krait_fixup
+ ldr r0, [r0]
+ cmp r0, #0
+ beq 10f
+ mrc p15, 7, r0, c15, c0, 5
+ orr r0, r0, #0x10000
+ mcr p15, 7, r0, c15, c0, 5
+10: isb
+#endif
+ .endif
mov r0, sp
ARM( ldr lr, [pc, lr, lsl #2] )
movs pc, lr @ branch to handler in SVC mode
@@ -1010,7 +1022,7 @@
/*
* Interrupt dispatcher
*/
- vector_stub irq, IRQ_MODE, 4
+ vector_stub irq, IRQ_MODE, 1, 4
.long __irq_usr @ 0 (USR_26 / USR_32)
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
@@ -1033,7 +1045,7 @@
* Data abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
- vector_stub dabt, ABT_MODE, 8
+ vector_stub dabt, ABT_MODE, 0, 8
.long __dabt_usr @ 0 (USR_26 / USR_32)
.long __dabt_invalid @ 1 (FIQ_26 / FIQ_32)
@@ -1056,7 +1068,7 @@
* Prefetch abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
- vector_stub pabt, ABT_MODE, 4
+ vector_stub pabt, ABT_MODE, 0, 4
.long __pabt_usr @ 0 (USR_26 / USR_32)
.long __pabt_invalid @ 1 (FIQ_26 / FIQ_32)
@@ -1079,7 +1091,7 @@
* Undef instr entry dispatcher
* Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*/
- vector_stub und, UND_MODE
+ vector_stub und, UND_MODE, 0
.long __und_usr @ 0 (USR_26 / USR_32)
.long __und_invalid @ 1 (FIQ_26 / FIQ_32)
@@ -1131,6 +1143,8 @@
.LCvswi:
.word vector_swi
+.krait_fixup:
+ .word msm_krait_need_wfe_fixup
.globl __stubs_end
__stubs_end:
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 33b153f..b6ce351 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -251,7 +251,7 @@
obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-7627a-all.o
obj-$(CONFIG_MACH_MSM7627A_QRD3) += board-qrd7627a.o board-7627a-all.o
obj-$(CONFIG_MACH_MSM7627A_EVB) += board-qrd7627a.o board-7627a-all.o
-obj-$(CONFIG_ARCH_MSM8625) += devices-msm7x27a.o clock-pcom-lookup.o mpm-8625.o
+obj-$(CONFIG_ARCH_MSM8625) += msm_smem_iface.o devices-msm7x27a.o clock-pcom-lookup.o mpm-8625.o
obj-$(CONFIG_MACH_MSM8625_RUMI3) += board-msm7x27a.o
obj-$(CONFIG_MACH_MSM8625_SURF) += board-msm7x27a.o board-7627a-all.o
obj-$(CONFIG_MACH_MSM8625_EVB) += board-qrd7627a.o board-7627a-all.o
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 8c89014..22275b4 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -23,7 +23,7 @@
#include "acpuclock-krait.h"
/* Corner type vreg VDD values */
-#define LVL_NONE RPM_REGULATOR_CORNER_RETENTION
+#define LVL_NONE RPM_REGULATOR_CORNER_NONE
#define LVL_LOW RPM_REGULATOR_CORNER_SVS_SOC
#define LVL_NOM RPM_REGULATOR_CORNER_NORMAL
#define LVL_HIGH RPM_REGULATOR_CORNER_SUPER_TURBO
@@ -94,11 +94,10 @@
};
static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(400), /* At least 50 MHz on bus. */
- [1] = BW_MBPS(800), /* At least 100 MHz on bus. */
- [2] = BW_MBPS(1334), /* At least 167 MHz on bus. */
- [3] = BW_MBPS(2666), /* At least 200 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 333 MHz on bus. */
+ [0] = BW_MBPS(552), /* At least 69 MHz on bus. */
+ [1] = BW_MBPS(1112), /* At least 139 MHz on bus. */
+ [2] = BW_MBPS(2224), /* At least 278 MHz on bus. */
+ [3] = BW_MBPS(4448), /* At least 556 MHz on bus. */
};
static struct msm_bus_scale_pdata bus_scale_data __initdata = {
@@ -109,31 +108,59 @@
};
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 2, 0 }, LVL_LOW, 1050000, 2 },
- [1] = { { 384000, HFPLL, 2, 0, 40 }, LVL_NOM, 1050000, 2 },
- [2] = { { 460800, HFPLL, 2, 0, 48 }, LVL_NOM, 1050000, 2 },
- [3] = { { 537600, HFPLL, 1, 0, 28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 576000, HFPLL, 1, 0, 30 }, LVL_NOM, 1050000, 3 },
- [5] = { { 652800, HFPLL, 1, 0, 34 }, LVL_NOM, 1050000, 3 },
- [6] = { { 729600, HFPLL, 1, 0, 38 }, LVL_NOM, 1050000, 3 },
- [7] = { { 806400, HFPLL, 1, 0, 42 }, LVL_NOM, 1050000, 3 },
- [8] = { { 883200, HFPLL, 1, 0, 46 }, LVL_NOM, 1050000, 4 },
- [9] = { { 960000, HFPLL, 1, 0, 50 }, LVL_NOM, 1050000, 4 },
- [10] = { { 1036800, HFPLL, 1, 0, 54 }, LVL_NOM, 1050000, 4 },
+ [0] = { { 300000, PLL_0, 0, 2, 0 }, LVL_LOW, 950000, 0 },
+ [1] = { { 384000, HFPLL, 2, 0, 40 }, LVL_NOM, 950000, 1 },
+ [2] = { { 460800, HFPLL, 2, 0, 48 }, LVL_NOM, 950000, 1 },
+ [3] = { { 537600, HFPLL, 1, 0, 28 }, LVL_NOM, 950000, 2 },
+ [4] = { { 576000, HFPLL, 1, 0, 30 }, LVL_NOM, 950000, 2 },
+ [5] = { { 652800, HFPLL, 1, 0, 34 }, LVL_NOM, 950000, 2 },
+ [6] = { { 729600, HFPLL, 1, 0, 38 }, LVL_NOM, 950000, 2 },
+ [7] = { { 806400, HFPLL, 1, 0, 42 }, LVL_NOM, 950000, 2 },
+ [8] = { { 883200, HFPLL, 1, 0, 46 }, LVL_HIGH, 1050000, 2 },
+ [9] = { { 960000, HFPLL, 1, 0, 50 }, LVL_HIGH, 1050000, 2 },
+ [10] = { { 1036800, HFPLL, 1, 0, 54 }, LVL_HIGH, 1050000, 3 },
+ [11] = { { 1113600, HFPLL, 1, 0, 58 }, LVL_HIGH, 1050000, 3 },
+ [12] = { { 1190400, HFPLL, 1, 0, 62 }, LVL_HIGH, 1050000, 3 },
+ [13] = { { 1267200, HFPLL, 1, 0, 66 }, LVL_HIGH, 1050000, 3 },
+ [14] = { { 1344000, HFPLL, 1, 0, 70 }, LVL_HIGH, 1050000, 3 },
+ [15] = { { 1420800, HFPLL, 1, 0, 74 }, LVL_HIGH, 1050000, 3 },
+ [16] = { { 1497600, HFPLL, 1, 0, 78 }, LVL_HIGH, 1050000, 3 },
+ [17] = { { 1574400, HFPLL, 1, 0, 82 }, LVL_HIGH, 1050000, 3 },
+ [18] = { { 1651200, HFPLL, 1, 0, 86 }, LVL_HIGH, 1050000, 3 },
+ [19] = { { 1728000, HFPLL, 1, 0, 90 }, LVL_HIGH, 1050000, 3 },
+ [20] = { { 1804800, HFPLL, 1, 0, 94 }, LVL_HIGH, 1050000, 3 },
+ [21] = { { 1881600, HFPLL, 1, 0, 98 }, LVL_HIGH, 1050000, 3 },
+ [22] = { { 1958400, HFPLL, 1, 0, 102 }, LVL_HIGH, 1050000, 3 },
+ [23] = { { 2035200, HFPLL, 1, 0, 106 }, LVL_HIGH, 1050000, 3 },
+ [24] = { { 2112000, HFPLL, 1, 0, 110 }, LVL_HIGH, 1050000, 3 },
+ [25] = { { 2188800, HFPLL, 1, 0, 114 }, LVL_HIGH, 1050000, 3 },
};
static struct acpu_level acpu_freq_tbl[] __initdata = {
- { 1, { 300000, PLL_0, 0, 2, 0 }, L2(0), 1050000, 3200000 },
- { 1, { 384000, HFPLL, 2, 0, 40 }, L2(1), 1050000, 3200000 },
- { 1, { 460800, HFPLL, 2, 0, 48 }, L2(2), 1050000, 3200000 },
- { 1, { 537600, HFPLL, 1, 0, 28 }, L2(3), 1050000, 3200000 },
- { 1, { 576000, HFPLL, 1, 0, 30 }, L2(4), 1050000, 3200000 },
- { 1, { 652800, HFPLL, 1, 0, 34 }, L2(5), 1050000, 3200000 },
- { 1, { 729600, HFPLL, 1, 0, 38 }, L2(6), 1050000, 3200000 },
- { 1, { 806400, HFPLL, 1, 0, 42 }, L2(7), 1050000, 3200000 },
- { 1, { 883200, HFPLL, 1, 0, 46 }, L2(8), 1050000, 3200000 },
- { 1, { 960000, HFPLL, 1, 0, 50 }, L2(9), 1050000, 3200000 },
- { 1, { 1036800, HFPLL, 1, 0, 54 }, L2(10), 1050000, 3200000 },
+ { 1, { 300000, PLL_0, 0, 2, 0 }, L2(0), 950000, 3200000 },
+ { 1, { 384000, HFPLL, 2, 0, 40 }, L2(3), 950000, 3200000 },
+ { 1, { 460800, HFPLL, 2, 0, 48 }, L2(3), 950000, 3200000 },
+ { 1, { 537600, HFPLL, 1, 0, 28 }, L2(5), 950000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 0, 30 }, L2(5), 950000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 0, 34 }, L2(5), 950000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 0, 38 }, L2(5), 950000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 0, 42 }, L2(7), 950000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 0, 46 }, L2(7), 950000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 0, 50 }, L2(7), 950000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 0, 54 }, L2(7), 950000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 0, 58 }, L2(12), 1050000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 0, 62 }, L2(12), 1050000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 0, 66 }, L2(12), 1050000, 3200000 },
+ { 0, { 1344000, HFPLL, 1, 0, 70 }, L2(15), 1050000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 0, 74 }, L2(15), 1050000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 0, 78 }, L2(15), 1050000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 0, 82 }, L2(20), 1050000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 0, 86 }, L2(20), 1050000, 3200000 },
+ { 0, { 1728000, HFPLL, 1, 0, 90 }, L2(20), 1050000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 0, 94 }, L2(25), 1050000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 0, 98 }, L2(25), 1050000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 0, 102 }, L2(25), 1050000, 3200000 },
+ { 0, { 1996800, HFPLL, 1, 0, 104 }, L2(25), 1050000, 3200000 },
{ 0, { 0 } }
};
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 1c19442..7898cf6 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -788,7 +788,7 @@
static struct gpiomux_setting mdm2ap_status_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting mdm2ap_errfatal_cfg = {
@@ -828,6 +828,7 @@
{
.gpio = 49,
.settings = {
+ [GPIOMUX_ACTIVE] = &mdm2ap_status_cfg,
[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
}
},
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 678eb9e..879434d 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -127,6 +127,7 @@
/* TABLA CODEC RESET */
PM8921_GPIO_OUTPUT(34, 1, MED),
PM8921_GPIO_OUTPUT(13, 0, HIGH), /* PCIE_CLK_PWR_EN */
+ PM8921_GPIO_INPUT(12, PM_GPIO_PULL_UP_30), /* PCIE_WAKE_N */
};
static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 6317685..0fad463 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -128,7 +128,8 @@
#define PCIE_AXI_BAR_PHYS 0x08000000
#define PCIE_AXI_BAR_SIZE SZ_128M
-/* PCIe power enable pmic gpio */
+/* PCIe pmic gpios */
+#define PCIE_WAKE_N_PMIC_GPIO 12
#define PCIE_PWR_EN_PMIC_GPIO 13
#define PCIE_RST_N_PMIC_MPP 1
@@ -1726,6 +1727,12 @@
.mdm2ap_vddmin_gpio = 80,
};
+static struct gpiomux_setting mdm2ap_status_gpio_run_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct mdm_platform_data mdm_platform_data = {
.mdm_version = "3.0",
.ramdump_delay_ms = 2000,
@@ -1734,6 +1741,7 @@
.vddmin_resource = &mdm_vddmin_rscs,
.peripheral_platform_device = &apq8064_device_hsic_host,
.ramdump_timeout_ms = 120000,
+ .mdm2ap_status_gpio_run_cfg = &mdm2ap_status_gpio_run_cfg,
};
static struct tsens_platform_data apq_tsens_pdata = {
@@ -2075,6 +2083,7 @@
.gpio = msm_pcie_gpio_info,
.axi_addr = PCIE_AXI_BAR_PHYS,
.axi_size = PCIE_AXI_BAR_SIZE,
+ .wake_n = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PCIE_WAKE_N_PMIC_GPIO),
};
static int __init mpq8064_pcie_enabled(void)
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 5851990..67be99a 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -759,6 +759,16 @@
},
};
+static struct msm_gpiomux_config hap_lvl_shft_config_sglte[] __initdata = {
+ {
+ .gpio = 89,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config,
+ [GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config,
+ },
+ },
+};
+
static struct msm_gpiomux_config sglte_configs[] __initdata = {
/* AP2MDM_STATUS */
{
@@ -979,8 +989,9 @@
}
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
- msm_gpiomux_install(msm8960_ethernet_configs,
- ARRAY_SIZE(msm8960_ethernet_configs));
+ if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE)
+ msm_gpiomux_install(msm8960_ethernet_configs,
+ ARRAY_SIZE(msm8960_ethernet_configs));
#endif
msm_gpiomux_install(msm8960_gsbi_configs,
@@ -1007,9 +1018,15 @@
#endif
if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
- machine_is_msm8960_liquid() || machine_is_msm8960_cdp())
- msm_gpiomux_install(hap_lvl_shft_config,
- ARRAY_SIZE(hap_lvl_shft_config));
+ machine_is_msm8960_liquid() || machine_is_msm8960_cdp()) {
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+ msm_gpiomux_install(hap_lvl_shft_config_sglte,
+ ARRAY_SIZE(hap_lvl_shft_config_sglte));
+
+ else
+ msm_gpiomux_install(hap_lvl_shft_config,
+ ARRAY_SIZE(hap_lvl_shft_config));
+ }
#ifdef CONFIG_USB_EHCI_MSM_HSIC
if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 63eef4a..dc28b83 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -109,7 +109,6 @@
#define KS8851_RST_GPIO 89
#define KS8851_IRQ_GPIO 90
-#define HAP_SHIFT_LVL_OE_GPIO 47
#define MHL_GPIO_INT 4
#define MHL_GPIO_RESET 15
@@ -1706,6 +1705,8 @@
},
};
+#define HAP_SHIFT_LVL_OE_GPIO 47
+#define HAP_SHIFT_LVL_OE_GPIO_SGLTE 89
#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33)
#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
@@ -1714,8 +1715,13 @@
static int isa1200_power(int on)
{
int rc = 0;
+ int hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO;
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+ hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO_SGLTE;
+
+
+ gpio_set_value(hap_oe_gpio, !!on);
rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
@@ -1728,13 +1734,14 @@
return 0;
err_xo_vote:
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
+ gpio_set_value(hap_oe_gpio, !on);
return rc;
}
static int isa1200_dev_setup(bool enable)
{
int rc = 0;
+ int hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO;
struct pm_gpio hap_gpio_config = {
.direction = PM_GPIO_DIR_OUT,
@@ -1747,6 +1754,9 @@
.output_value = 0,
};
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+ hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO_SGLTE;
+
if (enable == true) {
rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
if (rc) {
@@ -1762,14 +1772,14 @@
return rc;
}
- rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
+ rc = gpio_request(hap_oe_gpio, "hap_shft_lvl_oe");
if (rc) {
pr_err("%s: unable to request gpio %d (%d)\n",
- __func__, HAP_SHIFT_LVL_OE_GPIO, rc);
+ __func__, hap_oe_gpio, rc);
return rc;
}
- rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
+ rc = gpio_direction_output(hap_oe_gpio, 0);
if (rc) {
pr_err("%s: Unable to set direction\n", __func__);
goto free_gpio;
@@ -1783,7 +1793,7 @@
goto gpio_set_dir;
}
} else {
- gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+ gpio_free(hap_oe_gpio);
msm_xo_put(xo_handle_d1);
}
@@ -1791,9 +1801,9 @@
return 0;
gpio_set_dir:
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
+ gpio_set_value(hap_oe_gpio, 0);
free_gpio:
- gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+ gpio_free(hap_oe_gpio);
return rc;
}
@@ -2333,7 +2343,7 @@
.rst_gpio = KS8851_RST_GPIO,
};
-static struct spi_board_info spi_board_info[] __initdata = {
+static struct spi_board_info spi_eth_info[] __initdata = {
{
.modalias = "ks8851",
.irq = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
@@ -2343,6 +2353,8 @@
.mode = SPI_MODE_0,
.platform_data = &spi_eth_pdata
},
+};
+static struct spi_board_info spi_board_info[] __initdata = {
{
.modalias = "dsi_novatek_3d_panel_spi",
.max_speed_hz = 10800000,
@@ -2909,7 +2921,7 @@
ARRAY_SIZE(sii_device_info),
},
{
- I2C_LIQUID,
+ I2C_LIQUID | I2C_FFA,
MSM_8960_GSBI10_QUP_I2C_BUS_ID,
msm_isa1200_board_info,
ARRAY_SIZE(msm_isa1200_board_info),
@@ -3013,10 +3025,12 @@
msm8960_device_qup_spi_gsbi1.dev.platform_data =
&msm8960_qup_spi_gsbi1_pdata;
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+ if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE)
+ spi_register_board_info(spi_eth_info, ARRAY_SIZE(spi_eth_info));
msm8960_init_pmic();
- if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2 &&
- (machine_is_msm8960_mtp())) || machine_is_msm8960_liquid())
+ if (machine_is_msm8960_liquid() || (machine_is_msm8960_mtp() &&
+ (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)))
msm_isa1200_board_info[0].platform_data = &isa1200_1_pdata;
msm8960_i2c_init();
msm8960_gfx_init();
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 3726941..e305fe6 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -81,6 +81,7 @@
"gpio_disp_reset",
};
+static char lcdc_splash_is_enabled(void);
static int lcdc_truly_gpio_init(void)
{
int i;
@@ -103,7 +104,12 @@
lcdc_truly_gpio_table[i]);
goto truly_gpio_fail;
}
- rc = gpio_direction_output(lcdc_truly_gpio_table[i], 0);
+ if (lcdc_splash_is_enabled())
+ rc = gpio_direction_output(
+ lcdc_truly_gpio_table[i], 1);
+ else
+ rc = gpio_direction_output(
+ lcdc_truly_gpio_table[i], 0);
if (rc < 0) {
pr_err("Error direct lcdc gpio:%d\n",
lcdc_truly_gpio_table[i]);
@@ -247,6 +253,7 @@
static int sku3_lcdc_power_save(int on)
{
int rc = 0;
+ static int cont_splash_done;
if (on) {
sku3_lcdc_lcd_camera_power_onoff(1);
@@ -257,6 +264,11 @@
return rc;
}
+ if (lcdc_splash_is_enabled() && !cont_splash_done) {
+ cont_splash_done = 1;
+ return rc;
+ }
+
if (lcdc_truly_gpio_initialized) {
/*LCD reset*/
gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 1);
@@ -778,8 +790,14 @@
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = 97,
.mdp_rev = MDP_REV_303,
+ .cont_splash_enabled = 0x1,
};
+static char lcdc_splash_is_enabled()
+{
+ return mdp_pdata.cont_splash_enabled;
+}
+
#define GPIO_LCDC_BRDG_PD 128
#define GPIO_LCDC_BRDG_RESET_N 129
#define GPIO_LCD_DSI_SEL 125
@@ -1142,11 +1160,11 @@
}
static int qrd3_dsi_gpio_initialized;
+static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
static int mipi_dsi_panel_qrd3_power(int on)
{
int rc = 0;
- static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
if (!qrd3_dsi_gpio_initialized) {
pmapp_disp_backlight_init();
@@ -1155,21 +1173,42 @@
if (rc < 0)
return rc;
- gpio_reg_2p85v = regulator_get(&mipi_dsi_device.dev,
- "lcd_vdd");
- if (IS_ERR(gpio_reg_2p85v)) {
- pr_err("%s:ext_2p85v regulator get failed", __func__);
- return -EINVAL;
- }
-
- gpio_reg_1p8v = regulator_get(&mipi_dsi_device.dev,
- "lcd_vddi");
- if (IS_ERR(gpio_reg_1p8v)) {
- pr_err("%s:ext_1p8v regulator get failed", __func__);
- return -EINVAL;
- }
-
qrd3_dsi_gpio_initialized = 1;
+
+ if (mdp_pdata.cont_splash_enabled) {
+ rc = gpio_tlmm_config(GPIO_CFG(
+ GPIO_QRD3_LCD_BACKLIGHT_EN, 0, GPIO_CFG_OUTPUT,
+ GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
+ return rc;
+ }
+ rc = gpio_direction_output(GPIO_QRD3_LCD_BACKLIGHT_EN,
+ 1);
+ if (rc < 0) {
+ pr_err("failed to enable backlight\n");
+ gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
+ return rc;
+ }
+
+ /*Configure LCD Bridge reset*/
+ rc = gpio_tlmm_config(qrd3_mipi_dsi_gpio[0],
+ GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("Failed to enable LCD Bridge reset enable\n");
+ return rc;
+ }
+
+ rc = gpio_direction_output(GPIO_QRD3_LCD_BRDG_RESET_N,
+ 1);
+
+ if (rc < 0) {
+ pr_err("Failed GPIO bridge Reset\n");
+ gpio_free(GPIO_QRD3_LCD_BRDG_RESET_N);
+ return rc;
+ }
+ return 0;
+ }
}
if (on) {
@@ -1246,6 +1285,7 @@
return rc;
}
+static char mipi_dsi_splash_is_enabled(void);
static int mipi_dsi_panel_power(int on)
{
int rc = 0;
@@ -1268,9 +1308,15 @@
.dsi_power_save = mipi_dsi_panel_power,
.dsi_client_reset = msm_fb_dsi_client_reset,
.get_lane_config = msm_fb_get_lane_config,
+ .splash_is_enabled = mipi_dsi_splash_is_enabled,
};
#endif
+static char mipi_dsi_splash_is_enabled(void)
+{
+ return mdp_pdata.cont_splash_enabled;
+}
+
static char prim_panel_name[PANEL_NAME_MAX_LEN];
static int __init prim_display_setup(char *param)
{
@@ -1280,6 +1326,8 @@
}
early_param("prim_display", prim_display_setup);
+static int disable_splash;
+
void msm7x27a_set_display_params(char *prim_panel)
{
if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
@@ -1288,10 +1336,22 @@
pr_debug("msm_fb_pdata.prim_panel_name %s\n",
msm_fb_pdata.prim_panel_name);
}
+ if (strnlen(msm_fb_pdata.prim_panel_name, PANEL_NAME_MAX_LEN)) {
+ if (strncmp((char *)msm_fb_pdata.prim_panel_name,
+ "mipi_cmd_nt35510_wvga",
+ strnlen("mipi_cmd_nt35510_wvga",
+ PANEL_NAME_MAX_LEN)) &&
+ strncmp((char *)msm_fb_pdata.prim_panel_name,
+ "mipi_video_nt35510_wvga",
+ strnlen("mipi_video_nt35510_wvga",
+ PANEL_NAME_MAX_LEN)))
+ disable_splash = 1;
+ }
}
void __init msm_fb_add_devices(void)
{
+ int rc = 0;
msm7x27a_set_display_params(prim_panel_name);
if (machine_is_msm7627a_qrd1())
platform_add_devices(qrd_fb_devices,
@@ -1300,15 +1360,22 @@
|| machine_is_msm8625_evt()) {
mipi_NT35510_pdata.bl_lock = 1;
mipi_NT35516_pdata.bl_lock = 1;
+ if (disable_splash)
+ mdp_pdata.cont_splash_enabled = 0x0;
+
+
platform_add_devices(evb_fb_devices,
ARRAY_SIZE(evb_fb_devices));
} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
sku3_lcdc_lcd_camera_power_init();
+ mdp_pdata.cont_splash_enabled = 0x1;
platform_add_devices(qrd3_fb_devices,
ARRAY_SIZE(qrd3_fb_devices));
- } else
+ } else {
+ mdp_pdata.cont_splash_enabled = 0x0;
platform_add_devices(msm_fb_devices,
ARRAY_SIZE(msm_fb_devices));
+ }
msm_fb_register_device("mdp", &mdp_pdata);
if (machine_is_msm7625a_surf() || machine_is_msm7x27a_surf() ||
@@ -1318,4 +1385,26 @@
#ifdef CONFIG_FB_MSM_MIPI_DSI
msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
#endif
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()) {
+ gpio_reg_2p85v = regulator_get(&mipi_dsi_device.dev,
+ "lcd_vdd");
+ if (IS_ERR(gpio_reg_2p85v))
+ pr_err("%s:ext_2p85v regulator get failed", __func__);
+
+ gpio_reg_1p8v = regulator_get(&mipi_dsi_device.dev,
+ "lcd_vddi");
+ if (IS_ERR(gpio_reg_1p8v))
+ pr_err("%s:ext_1p8v regulator get failed", __func__);
+
+ if (mdp_pdata.cont_splash_enabled) {
+ /*Enable EXT_2.85 and 1.8 regulators*/
+ rc = regulator_enable(gpio_reg_2p85v);
+ if (rc < 0)
+ pr_err("%s: reg enable failed\n", __func__);
+ rc = regulator_enable(gpio_reg_1p8v);
+ if (rc < 0)
+ pr_err("%s: reg enable failed\n", __func__);
+ }
+ }
}
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 56b774d..1827773 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3200,12 +3200,36 @@
F_END
};
+static struct branch_clk dsi1_reset_clk = {
+ .b = {
+ .reset_reg = SW_RESET_CORE_REG,
+ .reset_mask = BIT(7),
+ .halt_check = NOCHECK,
+ },
+ .c = {
+ .dbg_name = "dsi1_reset_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(dsi1_reset_clk.c),
+ },
+};
+
+static struct branch_clk dsi2_reset_clk = {
+ .b = {
+ .reset_reg = SW_RESET_CORE_REG,
+ .reset_mask = BIT(25),
+ .halt_check = NOCHECK,
+ },
+ .c = {
+ .dbg_name = "dsi2_reset_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(dsi2_reset_clk.c),
+ },
+};
+
static struct rcg_clk dsi1_byte_clk = {
.b = {
.ctl_reg = DSI1_BYTE_CC_REG,
.en_mask = BIT(0),
- .reset_reg = SW_RESET_CORE_REG,
- .reset_mask = BIT(7),
.halt_reg = DBG_BUS_VEC_B_REG,
.halt_bit = 21,
.retain_reg = DSI1_BYTE_CC_REG,
@@ -3228,8 +3252,6 @@
.b = {
.ctl_reg = DSI2_BYTE_CC_REG,
.en_mask = BIT(0),
- .reset_reg = SW_RESET_CORE_REG,
- .reset_mask = BIT(25),
.halt_reg = DBG_BUS_VEC_B_REG,
.halt_bit = 20,
.retain_reg = DSI2_BYTE_CC_REG,
@@ -3252,7 +3274,6 @@
.b = {
.ctl_reg = DSI1_ESC_CC_REG,
.en_mask = BIT(0),
- .reset_reg = SW_RESET_CORE_REG,
.halt_reg = DBG_BUS_VEC_I_REG,
.halt_bit = 1,
},
@@ -4543,6 +4564,7 @@
}
static struct clk_freq_tbl clk_tbl_pcm_492[] = {
{ .ns_val = BIT(10) /* external input */ },
+ F_PCM( 256000, pll4, 4, 1, 480),
F_PCM( 512000, pll4, 4, 1, 240),
F_PCM( 768000, pll4, 4, 1, 160),
F_PCM( 1024000, pll4, 4, 1, 120),
@@ -4559,6 +4581,7 @@
static struct clk_freq_tbl clk_tbl_pcm_393[] = {
{ .ns_val = BIT(10) /* external input */ },
+ F_PCM( 256000, pll4, 4, 1, 384),
F_PCM( 512000, pll4, 4, 1, 192),
F_PCM( 768000, pll4, 4, 1, 128),
F_PCM( 1024000, pll4, 4, 1, 96),
@@ -5433,6 +5456,9 @@
CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
+ CLK_LOOKUP("reset1_clk", dsi1_reset_clk.c, "footswitch-8x60.4"),
+ CLK_LOOKUP("reset2_clk", dsi2_reset_clk.c, "footswitch-8x60.4"),
+
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
CLK_LOOKUP("krait1_mclk", krait1_m_clk, ""),
@@ -5750,6 +5776,9 @@
CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
+ CLK_LOOKUP("reset1_clk", dsi1_reset_clk.c, "footswitch-8x60.4"),
+ CLK_LOOKUP("reset2_clk", dsi2_reset_clk.c, "footswitch-8x60.4"),
+
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
CLK_LOOKUP("krait1_mclk", krait1_m_clk, ""),
@@ -6075,6 +6104,8 @@
CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
+ CLK_LOOKUP("reset1_clk", dsi1_reset_clk.c, "footswitch-8x60.4"),
+
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
CLK_LOOKUP("krait1_mclk", krait1_m_clk, ""),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 8076571..658b3dc 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -760,6 +760,9 @@
static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, 0);
static DEFINE_CLK_VOTER(pnoc_sdcc4_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_qseecom_clk, &pnoc_clk.c, 0);
+
static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
F(125000000, gpll0, 1, 5, 24),
F_END
@@ -4353,72 +4356,76 @@
};
struct measure_mux_entry measure_mux[] = {
- {&gcc_bam_dma_ahb_clk.c, GCC_BASE, 0x00e8},
- {&gcc_blsp1_ahb_clk.c, GCC_BASE, 0x0090},
- {&gcc_blsp1_qup1_i2c_apps_clk.c, GCC_BASE, 0x0093},
- {&gcc_blsp1_qup1_spi_apps_clk.c, GCC_BASE, 0x0092},
- {&gcc_blsp1_qup2_i2c_apps_clk.c, GCC_BASE, 0x0098},
- {&gcc_blsp1_qup2_spi_apps_clk.c, GCC_BASE, 0x0096},
- {&gcc_blsp1_qup3_i2c_apps_clk.c, GCC_BASE, 0x009c},
- {&gcc_blsp1_qup3_spi_apps_clk.c, GCC_BASE, 0x009b},
- {&gcc_blsp1_qup4_i2c_apps_clk.c, GCC_BASE, 0x00a1},
- {&gcc_blsp1_qup4_spi_apps_clk.c, GCC_BASE, 0x00a0},
- {&gcc_blsp1_qup5_i2c_apps_clk.c, GCC_BASE, 0x00a5},
- {&gcc_blsp1_qup5_spi_apps_clk.c, GCC_BASE, 0x00a4},
- {&gcc_blsp1_qup6_i2c_apps_clk.c, GCC_BASE, 0x00aa},
- {&gcc_blsp1_qup6_spi_apps_clk.c, GCC_BASE, 0x00a9},
- {&gcc_blsp1_uart1_apps_clk.c, GCC_BASE, 0x0094},
- {&gcc_blsp1_uart2_apps_clk.c, GCC_BASE, 0x0099},
- {&gcc_blsp1_uart3_apps_clk.c, GCC_BASE, 0x009d},
- {&gcc_blsp1_uart4_apps_clk.c, GCC_BASE, 0x00a2},
- {&gcc_blsp1_uart5_apps_clk.c, GCC_BASE, 0x00a6},
- {&gcc_blsp1_uart6_apps_clk.c, GCC_BASE, 0x00ab},
- {&gcc_blsp2_ahb_clk.c, GCC_BASE, 0x00b0},
- {&gcc_blsp2_qup1_i2c_apps_clk.c, GCC_BASE, 0x00b3},
- {&gcc_blsp2_qup1_spi_apps_clk.c, GCC_BASE, 0x00b2},
- {&gcc_blsp2_qup2_i2c_apps_clk.c, GCC_BASE, 0x00b8},
- {&gcc_blsp2_qup2_spi_apps_clk.c, GCC_BASE, 0x00b6},
- {&gcc_blsp2_qup3_i2c_apps_clk.c, GCC_BASE, 0x00bc},
- {&gcc_blsp2_qup3_spi_apps_clk.c, GCC_BASE, 0x00bb},
- {&gcc_blsp2_qup4_i2c_apps_clk.c, GCC_BASE, 0x00c1},
- {&gcc_blsp2_qup4_spi_apps_clk.c, GCC_BASE, 0x00c0},
- {&gcc_blsp2_qup5_i2c_apps_clk.c, GCC_BASE, 0x00c5},
- {&gcc_blsp2_qup5_spi_apps_clk.c, GCC_BASE, 0x00c4},
- {&gcc_blsp2_qup6_i2c_apps_clk.c, GCC_BASE, 0x00ca},
- {&gcc_blsp2_qup6_spi_apps_clk.c, GCC_BASE, 0x00c9},
- {&gcc_blsp2_uart1_apps_clk.c, GCC_BASE, 0x00b4},
- {&gcc_blsp2_uart2_apps_clk.c, GCC_BASE, 0x00b9},
- {&gcc_blsp2_uart3_apps_clk.c, GCC_BASE, 0x00bd},
- {&gcc_blsp2_uart4_apps_clk.c, GCC_BASE, 0x00c2},
- {&gcc_blsp2_uart5_apps_clk.c, GCC_BASE, 0x00c6},
- {&gcc_blsp2_uart6_apps_clk.c, GCC_BASE, 0x00cb},
- {&gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x0100},
- {&gcc_ocmem_noc_cfg_ahb_clk.c, GCC_BASE, 0x0029},
- {&gcc_mmss_noc_cfg_ahb_clk.c, GCC_BASE, 0x002A},
- {&gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
- {&gcc_ce1_clk.c, GCC_BASE, 0x0140},
- {&gcc_ce2_clk.c, GCC_BASE, 0x0148},
- {&gcc_pdm2_clk.c, GCC_BASE, 0x00da},
- {&gcc_pdm_ahb_clk.c, GCC_BASE, 0x00d8},
- {&gcc_prng_ahb_clk.c, GCC_BASE, 0x00e0},
- {&gcc_sdcc1_ahb_clk.c, GCC_BASE, 0x0071},
- {&gcc_sdcc1_apps_clk.c, GCC_BASE, 0x0070},
- {&gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0079},
- {&gcc_sdcc2_apps_clk.c, GCC_BASE, 0x0078},
- {&gcc_sdcc3_ahb_clk.c, GCC_BASE, 0x0081},
- {&gcc_sdcc3_apps_clk.c, GCC_BASE, 0x0080},
- {&gcc_sdcc4_ahb_clk.c, GCC_BASE, 0x0089},
- {&gcc_sdcc4_apps_clk.c, GCC_BASE, 0x0088},
- {&gcc_tsif_ahb_clk.c, GCC_BASE, 0x00f0},
- {&gcc_tsif_ref_clk.c, GCC_BASE, 0x00f1},
+ {&gcc_pdm_ahb_clk.c, GCC_BASE, 0x00d0},
+ {&gcc_blsp2_qup1_i2c_apps_clk.c, GCC_BASE, 0x00ab},
+ {&gcc_blsp2_qup3_spi_apps_clk.c, GCC_BASE, 0x00b3},
+ {&gcc_blsp2_uart5_apps_clk.c, GCC_BASE, 0x00be},
{&gcc_usb30_master_clk.c, GCC_BASE, 0x0050},
+ {&gcc_blsp2_qup3_i2c_apps_clk.c, GCC_BASE, 0x00b4},
+ {&gcc_usb_hsic_system_clk.c, GCC_BASE, 0x0059},
+ {&gcc_blsp2_uart3_apps_clk.c, GCC_BASE, 0x00b5},
+ {&gcc_usb_hsic_io_cal_clk.c, GCC_BASE, 0x005b},
+ {&gcc_ce2_axi_clk.c, GCC_BASE, 0x0141},
+ {&gcc_sdcc3_ahb_clk.c, GCC_BASE, 0x0079},
+ {&gcc_blsp1_qup5_i2c_apps_clk.c, GCC_BASE, 0x009d},
+ {&gcc_blsp1_qup1_spi_apps_clk.c, GCC_BASE, 0x008a},
+ {&gcc_blsp2_uart4_apps_clk.c, GCC_BASE, 0x00ba},
+ {&gcc_ce2_clk.c, GCC_BASE, 0x0140},
+ {&gcc_blsp1_uart2_apps_clk.c, GCC_BASE, 0x0091},
+ {&gcc_sdcc1_ahb_clk.c, GCC_BASE, 0x0069},
+ {&gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
+ {&gcc_tsif_ahb_clk.c, GCC_BASE, 0x00e8},
+ {&gcc_sdcc4_ahb_clk.c, GCC_BASE, 0x0081},
+ {&gcc_blsp1_qup4_spi_apps_clk.c, GCC_BASE, 0x0098},
+ {&gcc_blsp2_qup4_spi_apps_clk.c, GCC_BASE, 0x00b8},
+ {&gcc_blsp1_qup3_spi_apps_clk.c, GCC_BASE, 0x0093},
+ {&gcc_blsp1_qup6_i2c_apps_clk.c, GCC_BASE, 0x00a2},
+ {&gcc_blsp2_qup6_i2c_apps_clk.c, GCC_BASE, 0x00c2},
+ {&gcc_bam_dma_ahb_clk.c, GCC_BASE, 0x00e0},
+ {&gcc_sdcc3_apps_clk.c, GCC_BASE, 0x0078},
+ {&gcc_usb_hs_system_clk.c, GCC_BASE, 0x0060},
+ {&gcc_blsp1_ahb_clk.c, GCC_BASE, 0x0088},
+ {&gcc_sdcc1_apps_clk.c, GCC_BASE, 0x0068},
+ {&gcc_blsp2_qup5_i2c_apps_clk.c, GCC_BASE, 0x00bd},
+ {&gcc_blsp1_uart4_apps_clk.c, GCC_BASE, 0x009a},
+ {&gcc_blsp2_qup2_spi_apps_clk.c, GCC_BASE, 0x00ae},
+ {&gcc_blsp2_qup6_spi_apps_clk.c, GCC_BASE, 0x00c1},
+ {&gcc_blsp2_uart2_apps_clk.c, GCC_BASE, 0x00b1},
+ {&gcc_blsp1_qup2_spi_apps_clk.c, GCC_BASE, 0x008e},
+ {&gcc_usb_hsic_ahb_clk.c, GCC_BASE, 0x0058},
+ {&gcc_blsp1_uart3_apps_clk.c, GCC_BASE, 0x0095},
{&gcc_usb30_mock_utmi_clk.c, GCC_BASE, 0x0052},
- {&gcc_usb_hs_ahb_clk.c, GCC_BASE, 0x0069},
- {&gcc_usb_hs_system_clk.c, GCC_BASE, 0x0068},
- {&gcc_usb_hsic_ahb_clk.c, GCC_BASE, 0x0060},
- {&gcc_usb_hsic_clk.c, GCC_BASE, 0x0062},
- {&gcc_usb_hsic_io_cal_clk.c, GCC_BASE, 0x0063},
- {&gcc_usb_hsic_system_clk.c, GCC_BASE, 0x0061},
+ {&gcc_ce1_axi_clk.c, GCC_BASE, 0x0139},
+ {&gcc_sdcc4_apps_clk.c, GCC_BASE, 0x0080},
+ {&gcc_blsp1_qup5_spi_apps_clk.c, GCC_BASE, 0x009c},
+ {&gcc_usb_hs_ahb_clk.c, GCC_BASE, 0x0061},
+ {&gcc_blsp1_qup6_spi_apps_clk.c, GCC_BASE, 0x00a1},
+ {&gcc_blsp2_qup2_i2c_apps_clk.c, GCC_BASE, 0x00b0},
+ {&gcc_prng_ahb_clk.c, GCC_BASE, 0x00d8},
+ {&gcc_blsp1_qup3_i2c_apps_clk.c, GCC_BASE, 0x0094},
+ {&gcc_usb_hsic_clk.c, GCC_BASE, 0x005a},
+ {&gcc_blsp1_uart6_apps_clk.c, GCC_BASE, 0x00a3},
+ {&gcc_sdcc2_apps_clk.c, GCC_BASE, 0x0070},
+ {&gcc_tsif_ref_clk.c, GCC_BASE, 0x00e9},
+ {&gcc_blsp1_uart1_apps_clk.c, GCC_BASE, 0x008c},
+ {&gcc_blsp2_qup5_spi_apps_clk.c, GCC_BASE, 0x00bc},
+ {&gcc_blsp1_qup4_i2c_apps_clk.c, GCC_BASE, 0x0099},
+ {&gcc_mmss_noc_cfg_ahb_clk.c, GCC_BASE, 0x002a},
+ {&gcc_blsp2_ahb_clk.c, GCC_BASE, 0x00a8},
+ {&gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x00f8},
+ {&gcc_ce1_ahb_clk.c, GCC_BASE, 0x013a},
+ {&gcc_pdm2_clk.c, GCC_BASE, 0x00d2},
+ {&gcc_blsp2_qup4_i2c_apps_clk.c, GCC_BASE, 0x00b9},
+ {&gcc_ce2_ahb_clk.c, GCC_BASE, 0x0142},
+ {&gcc_blsp1_uart5_apps_clk.c, GCC_BASE, 0x009e},
+ {&gcc_blsp2_qup1_spi_apps_clk.c, GCC_BASE, 0x00aa},
+ {&gcc_blsp1_qup2_i2c_apps_clk.c, GCC_BASE, 0x0090},
+ {&gcc_blsp2_uart1_apps_clk.c, GCC_BASE, 0x00ac},
+ {&gcc_blsp1_qup1_i2c_apps_clk.c, GCC_BASE, 0x008b},
+ {&gcc_blsp2_uart6_apps_clk.c, GCC_BASE, 0x00c3},
+ {&gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0071},
+ {&gcc_ocmem_noc_cfg_ahb_clk.c, GCC_BASE, 0x0029},
+ {&gcc_ce1_clk.c, GCC_BASE, 0x0138},
{&mmss_mmssnoc_ahb_clk.c, MMSS_BASE, 0x0001},
{&mmss_mmssnoc_axi_clk.c, MMSS_BASE, 0x0004},
{&ocmemnoc_clk.c, MMSS_BASE, 0x0007},
@@ -4970,11 +4977,8 @@
CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
- /* TODO: Remove dummy clocks as soon as they become unnecessary */
- CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
- CLK_DUMMY("mem_clk", NULL, "msm_sps", OFF),
- CLK_DUMMY("bus_clk", NULL, "scm", OFF),
- CLK_DUMMY("bus_clk", NULL, "qseecom", OFF),
+ CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+ CLK_LOOKUP("bus_clk", pnoc_qseecom_clk.c, "qseecom"),
CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index ac26acf..1f0bd2c 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -1837,6 +1837,8 @@
{ .name = "lut_clk" },
{ .name = "tv_src_clk" },
{ .name = "tv_clk" },
+ { .name = "reset1_clk" },
+ { .name = "reset2_clk" },
{ 0 }
},
.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 7cb6e95..fa24ba9 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -425,6 +425,7 @@
{ .name = "lut_clk" },
{ .name = "tv_src_clk" },
{ .name = "tv_clk" },
+ { .name = "reset1_clk" },
{ 0 }
},
.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 3d1926c..724eed8 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2151,6 +2151,8 @@
{ .name = "lut_clk" },
{ .name = "tv_src_clk" },
{ .name = "tv_clk" },
+ { .name = "reset1_clk" },
+ { .name = "reset2_clk" },
{ 0 }
},
.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index c4877cc..6ec12c1 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -32,6 +32,7 @@
struct platform_device *peripheral_platform_device;
const unsigned int ramdump_timeout_ms;
int image_upgrade_supported;
+ struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
index 4f140cc..4e22b0f 100644
--- a/arch/arm/mach-msm/include/mach/msm_hsusb.h
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
@@ -202,8 +202,4 @@
struct clk *ebi1_clk;
};
-int msm_ep_config(struct usb_ep *ep);
-int msm_ep_unconfig(struct usb_ep *ep);
-int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size);
-
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_pcie.h b/arch/arm/mach-msm/include/mach/msm_pcie.h
index 8bc4317..74f0f5b 100644
--- a/arch/arm/mach-msm/include/mach/msm_pcie.h
+++ b/arch/arm/mach-msm/include/mach/msm_pcie.h
@@ -22,7 +22,7 @@
MSM_PCIE_MAX_GPIO
};
-/* gpio info structrue */
+/* gpio info structure */
struct msm_pcie_gpio_info_t {
char *name;
uint32_t num;
@@ -32,8 +32,10 @@
/* msm pcie platfrom data */
struct msm_pcie_platform {
struct msm_pcie_gpio_info_t *gpio;
+
uint32_t axi_addr;
uint32_t axi_size;
+ uint32_t wake_n;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index ec135a3..47313a7 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -12,6 +12,7 @@
#ifndef _USB_BAM_H_
#define _USB_BAM_H_
+#include "sps.h"
/**
* SPS Pipes direction.
@@ -43,7 +44,7 @@
* @return 0 on success, negative value on error
*
*/
-int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx);
+int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx);
/**
* Register a wakeup callback from peer BAM.
@@ -57,8 +58,40 @@
*/
int usb_bam_register_wake_cb(u8 idx,
int (*callback)(void *), void* param);
+
+/**
+ * Disconnect USB-to-Periperal SPS connection.
+ *
+ * @idx - Connection index.
+ *
+ * @return 0 on success, negative value on error
+ */
+int usb_bam_disconnect_pipe(u8 idx);
+
+/**
+ * Returns usb bam connection parameters.
+ *
+ * @conn_idx - Connection index.
+ *
+ * @usb_bam_pipe_dir - Usb pipe direction to/from peripheral.
+ *
+ * @usb_bam_handle - Usb bam handle.
+ *
+ * @usb_bam_pipe_idx - Usb bam pipe index.
+ *
+ * @peer_pipe_idx - Peer pipe index.
+ *
+ * @desc_fifo - Descriptor fifo parameters.
+ *
+ * @data_fifo - Data fifo parameters.
+ *
+ */
+void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+ u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+ struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo);
+
#else
-static inline int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
{
return -ENODEV;
}
@@ -68,6 +101,18 @@
{
return -ENODEV;
}
+
+static inline int usb_bam_disconnect_pipe(u8 idx)
+{
+ return -ENODEV;
+}
+
+static inline void get_bam2bam_connection_info(u8 conn_idx,
+ enum usb_bam_pipe_dir pipe_dir, u32 *usb_bam_handle,
+ u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+ struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
+{
+ return;
+}
#endif
#endif /* _USB_BAM_H_ */
-
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 6b40cda..d1865e4 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -30,6 +30,7 @@
#include <linux/workqueue.h>
#include <linux/clk.h>
#include <linux/mfd/pmic8058.h>
+#include <linux/msm_charm.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <mach/mdm2.h>
@@ -37,7 +38,7 @@
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
#include <mach/rpm.h>
-#include <linux/msm_charm.h>
+#include <mach/gpiomux.h>
#include "msm_watchdog.h"
#include "mdm_private.h"
#include "sysmon.h"
@@ -68,6 +69,13 @@
#define SFR_MAX_RETRIES 10
#define SFR_RETRY_INTERVAL 1000
+enum gpio_update_config {
+ GPIO_UPDATE_BOOTING_CONFIG = 1,
+ GPIO_UPDATE_RUNNING_CONFIG,
+};
+static int mdm2ap_status_valid_old_config;
+static struct gpiomux_setting mdm2ap_status_old_config;
+
static irqreturn_t mdm_vddmin_change(int irq, void *dev_id)
{
int value = gpio_get_value(
@@ -163,6 +171,37 @@
static DECLARE_DELAYED_WORK(mdm2ap_status_check_work, mdm2ap_status_check);
+static void mdm_update_gpio_configs(enum gpio_update_config gpio_config)
+{
+ /* Some gpio configuration may need updating after modem bootup.*/
+ switch (gpio_config) {
+ case GPIO_UPDATE_RUNNING_CONFIG:
+ if (mdm_drv->pdata->mdm2ap_status_gpio_run_cfg) {
+ if (msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
+ GPIOMUX_ACTIVE,
+ mdm_drv->pdata->mdm2ap_status_gpio_run_cfg,
+ &mdm2ap_status_old_config))
+ pr_err("%s: failed updating running gpio config\n",
+ __func__);
+ else
+ mdm2ap_status_valid_old_config = 1;
+ }
+ break;
+ case GPIO_UPDATE_BOOTING_CONFIG:
+ if (mdm2ap_status_valid_old_config) {
+ msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
+ GPIOMUX_ACTIVE,
+ &mdm2ap_status_old_config,
+ NULL);
+ mdm2ap_status_valid_old_config = 0;
+ }
+ break;
+ default:
+ pr_err("%s: called with no config\n", __func__);
+ break;
+ }
+}
+
long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -205,11 +244,10 @@
else
first_boot = 0;
- /* Start a timer to check that the mdm2ap_status gpio
- * goes high.
+ /* If successful, start a timer to check that the mdm2ap_status
+ * gpio goes high.
*/
-
- if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ if (!status && gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
schedule_delayed_work(&mdm2ap_status_check_work,
msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
break;
@@ -266,6 +304,9 @@
pr_debug("%s: status:%d\n", __func__, value);
if (mdm_drv->mdm_ready && mdm_drv->ops->status_cb)
mdm_drv->ops->status_cb(mdm_drv, value);
+
+ /* Update gpio configuration to "running" config. */
+ mdm_update_gpio_configs(GPIO_UPDATE_RUNNING_CONFIG);
}
static DECLARE_WORK(mdm_status_work, mdm_status_fn);
@@ -364,6 +405,7 @@
static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
{
mdm_drv->mdm_ready = 0;
+ cancel_delayed_work(&mdm2ap_status_check_work);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
if (mdm_drv->pdata->ramdump_delay_ms > 0) {
/* Wait for the external modem to complete
@@ -371,10 +413,13 @@
*/
msleep(mdm_drv->pdata->ramdump_delay_ms);
}
- if (!mdm_drv->mdm_unexpected_reset_occurred)
+ if (!mdm_drv->mdm_unexpected_reset_occurred) {
mdm_drv->ops->reset_mdm_cb(mdm_drv);
- else
+ /* Update gpio configuration to "booting" config. */
+ mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+ } else {
mdm_drv->mdm_unexpected_reset_occurred = 0;
+ }
return 0;
}
@@ -404,6 +449,7 @@
const struct subsys_desc *crashed_subsys)
{
mdm_drv->mdm_ram_dump_status = 0;
+ cancel_delayed_work(&mdm2ap_status_check_work);
if (want_dumps) {
mdm_drv->boot_type = CHARM_RAM_DUMPS;
complete(&mdm_needs_reload);
@@ -416,8 +462,11 @@
pr_info("%s: mdm modem ramdumps completed.\n",
__func__);
INIT_COMPLETION(mdm_ram_dumps);
- if (!mdm_drv->pdata->no_powerdown_after_ramdumps)
+ if (!mdm_drv->pdata->no_powerdown_after_ramdumps) {
mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+ /* Update gpio configuration to "booting" config. */
+ mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+ }
}
return mdm_drv->mdm_ram_dump_status;
}
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index a5f8bcc..a65cd21 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -22,6 +22,8 @@
#include <linux/of.h>
#include <linux/cpu.h>
#include <linux/platform_device.h>
+#include <mach/scm.h>
+#include <mach/msm_memory_dump.h>
#define MODULE_NAME "msm_watchdog"
#define WDT0_ACCSCSSNBARK_INT 0
@@ -32,7 +34,8 @@
#define WDT0_BARK_TIME 0x10
#define WDT0_BITE_TIME 0x14
-#define MASK_SIZE 32
+#define MASK_SIZE 32
+#define SCM_SET_REGSAVE_CMD 0x2
struct msm_watchdog_data {
unsigned int __iomem phys_base;
@@ -47,6 +50,7 @@
unsigned long long last_pet;
unsigned min_slack_ticks;
unsigned long long min_slack_ns;
+ void *scm_regsave;
cpumask_t alive_mask;
struct work_struct init_dogwork_struct;
struct delayed_work dogwork_struct;
@@ -242,6 +246,44 @@
return IRQ_HANDLED;
}
+static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
+{
+ int ret;
+ struct msm_client_dump dump_entry;
+ struct {
+ unsigned addr;
+ int len;
+ } cmd_buf;
+
+ wdog_dd->scm_regsave = (void *)__get_free_page(GFP_KERNEL);
+ if (wdog_dd->scm_regsave) {
+ cmd_buf.addr = virt_to_phys(wdog_dd->scm_regsave);
+ cmd_buf.len = PAGE_SIZE;
+ ret = scm_call(SCM_SVC_UTIL, SCM_SET_REGSAVE_CMD,
+ &cmd_buf, sizeof(cmd_buf), NULL, 0);
+ if (ret)
+ pr_err("Setting register save address failed.\n"
+ "Registers won't be dumped on a dog "
+ "bite\n");
+ dump_entry.id = MSM_CPU_CTXT;
+ dump_entry.start_addr = virt_to_phys(wdog_dd->scm_regsave);
+ dump_entry.end_addr = dump_entry.start_addr + PAGE_SIZE;
+ ret = msm_dump_table_register(&dump_entry);
+ if (ret)
+ pr_err("Setting cpu dump region failed\n"
+ "Registers wont be dumped during cpu hang\n");
+ } else {
+ pr_err("Allocating register save space failed\n"
+ "Registers won't be dumped on a dog bite\n");
+ /*
+ * No need to bail if allocation fails. Simply don't
+ * send the command, and the secure side will reset
+ * without saving registers.
+ */
+ }
+}
+
+
static void init_watchdog_work(struct work_struct *work)
{
struct msm_watchdog_data *wdog_dd = container_of(work,
@@ -252,6 +294,7 @@
delay_time = msecs_to_jiffies(wdog_dd->pet_time);
wdog_dd->min_slack_ticks = UINT_MAX;
wdog_dd->min_slack_ns = ULLONG_MAX;
+ configure_bark_dump(wdog_dd);
timeout = (wdog_dd->bark_time * WDT_HZ)/1000;
__raw_writel(timeout, wdog_dd->base + WDT0_BARK_TIME);
__raw_writel(timeout + 3*WDT_HZ, wdog_dd->base + WDT0_BITE_TIME);
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
index d954b53..709c8e8 100644
--- a/arch/arm/mach-msm/pcie.c
+++ b/arch/arm/mach-msm/pcie.c
@@ -619,6 +619,7 @@
msm_pcie_dev.pdev = pdev;
pdata = pdev->dev.platform_data;
msm_pcie_dev.gpio = pdata->gpio;
+ msm_pcie_dev.wake_n = pdata->wake_n;
msm_pcie_dev.vreg = msm_pcie_vreg_info;
msm_pcie_dev.clk = msm_pcie_clk_info;
msm_pcie_dev.res = msm_pcie_res_info;
@@ -706,6 +707,26 @@
DECLARE_PCI_FIXUP_EARLY(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
msm_pcie_fixup_early);
+/* enable wake_n interrupt during suspend */
+static void msm_pcie_fixup_suspend(struct pci_dev *dev)
+{
+ PCIE_DBG("enabling wake_n\n");
+ if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+ enable_irq(msm_pcie_dev.wake_n);
+}
+DECLARE_PCI_FIXUP_SUSPEND(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+ msm_pcie_fixup_suspend);
+
+/* disable wake_n interrupt when system is not in suspend */
+static void msm_pcie_fixup_resume(struct pci_dev *dev)
+{
+ PCIE_DBG("disabling wake_n\n");
+ if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+ disable_irq(msm_pcie_dev.wake_n);
+}
+DECLARE_PCI_FIXUP_RESUME(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+ msm_pcie_fixup_resume);
+
/*
* actual physical (BAR) address of the device resources starts from
* MSM_PCIE_DEV_BAR_ADDR; the system axi address for the device resources starts
diff --git a/arch/arm/mach-msm/pcie.h b/arch/arm/mach-msm/pcie.h
index fba6b11..d7cce3e 100644
--- a/arch/arm/mach-msm/pcie.h
+++ b/arch/arm/mach-msm/pcie.h
@@ -68,6 +68,8 @@
uint32_t axi_bar_end;
struct resource dev_mem_res;
+
+ uint32_t wake_n;
};
extern uint32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev);
diff --git a/arch/arm/mach-msm/pcie_irq.c b/arch/arm/mach-msm/pcie_irq.c
index d915561..5a44a17 100644
--- a/arch/arm/mach-msm/pcie_irq.c
+++ b/arch/arm/mach-msm/pcie_irq.c
@@ -39,7 +39,13 @@
static DECLARE_BITMAP(msi_irq_in_use, NR_PCIE_MSI_IRQS);
-irqreturn_t handle_msi_irq(int irq, void *data)
+static irqreturn_t handle_wake_irq(int irq, void *data)
+{
+ PCIE_DBG("\n");
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_msi_irq(int irq, void *data)
{
int i, j;
unsigned long val;
@@ -87,15 +93,32 @@
/* register handler for physical MSI interrupt line */
rc = request_irq(PCIE20_INT_MSI, handle_msi_irq, IRQF_TRIGGER_RISING,
"msm_pcie_msi", dev);
- if (rc)
+ if (rc) {
pr_err("Unable to allocate msi interrupt\n");
+ goto out;
+ }
+ /* register handler for PCIE_WAKE_N interrupt line */
+ rc = request_irq(dev->wake_n, handle_wake_irq, IRQF_TRIGGER_FALLING,
+ "msm_pcie_wake", dev);
+ if (rc) {
+ pr_err("Unable to allocate wake interrupt\n");
+ free_irq(PCIE20_INT_MSI, dev);
+ goto out;
+ }
+
+ enable_irq_wake(dev->wake_n);
+
+ /* PCIE_WAKE_N should be enabled only during system suspend */
+ disable_irq(dev->wake_n);
+out:
return rc;
}
void __exit msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
{
free_irq(PCIE20_INT_MSI, dev);
+ free_irq(dev->wake_n, dev);
}
void msm_pcie_destroy_irq(unsigned int irq)
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 58d5176..8897cb5 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -117,11 +117,12 @@
void __iomem *base = drv->base;
unsigned long start_addr = drv->start_addr;
- /* Deassert reset to Pronto */
+ /* Deassert reset to subsystem and wait for propagation */
reg = readl_relaxed(drv->reset_base);
reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
writel_relaxed(reg, drv->reset_base);
mb();
+ udelay(2);
/* Configure boot address */
writel_relaxed(start_addr >> 16, base +
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 62685ca..5c9c3c4 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -139,8 +139,10 @@
struct q6v5_data *drv = dev_get_drvdata(pil->dev);
int ret;
+ /* Deassert reset to subsystem and wait for propagation */
writel_relaxed(0, drv->restart_reg);
mb();
+ udelay(2);
/*
* Bring subsystem out of reset and enable required
@@ -235,7 +237,7 @@
if (IS_ERR(drv->vreg))
return PTR_ERR(drv->vreg);
- ret = regulator_set_voltage(drv->vreg, 1150000, 1150000);
+ ret = regulator_set_voltage(drv->vreg, 1050000, 1050000);
if (ret)
dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 4096d9c..55ae2f8 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -94,7 +94,7 @@
{
int ret = 0;
- if (!scm_perf_client || !scm_bus_clk)
+ if (!scm_perf_client)
return -EINVAL;
mutex_lock(&scm_pas_bw_mutex);
@@ -102,7 +102,7 @@
ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
if (ret) {
pr_err("bandwidth request failed (%d)\n", ret);
- } else {
+ } else if (scm_bus_clk) {
ret = clk_prepare_enable(scm_bus_clk);
if (ret)
pr_err("clock enable failed\n");
@@ -121,7 +121,8 @@
mutex_lock(&scm_pas_bw_mutex);
if (scm_pas_bw_count-- == 1) {
msm_bus_scale_client_update_request(scm_perf_client, 0);
- clk_disable_unprepare(scm_bus_clk);
+ if (scm_bus_clk)
+ clk_disable_unprepare(scm_bus_clk);
}
mutex_unlock(&scm_pas_bw_mutex);
}
@@ -190,16 +191,23 @@
static int __init scm_pas_init(void)
{
+ if (cpu_is_msm8974()) {
+ scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
+ scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
+ } else {
+ scm_bus_clk = clk_get_sys("scm", "bus_clk");
+ if (!IS_ERR(scm_bus_clk)) {
+ clk_set_rate(scm_bus_clk, 64000000);
+ } else {
+ scm_bus_clk = NULL;
+ pr_warn("unable to get bus clock\n");
+ }
+ }
+
scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
if (!scm_perf_client)
pr_warn("unable to register bus client\n");
- scm_bus_clk = clk_get_sys("scm", "bus_clk");
- if (!IS_ERR(scm_bus_clk)) {
- clk_set_rate(scm_bus_clk, 64000000);
- } else {
- scm_bus_clk = NULL;
- pr_warn("unable to get bus clock\n");
- }
+
return 0;
}
module_init(scm_pas_init);
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 741d4fa..4fe1f01 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1306,10 +1306,9 @@
return PTR_ERR(dmabuf);
}
fd = dma_buf_fd(dmabuf, O_CLOEXEC);
- if (fd < 0) {
+ if (fd < 0)
dma_buf_put(dmabuf);
- ion_buffer_put(buffer);
- }
+
return fd;
}
EXPORT_SYMBOL(ion_share_dma_buf);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 3047693..3bfec17 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1590,9 +1590,8 @@
cmds[1] = 0;
if (adreno_dev->drawctxt_active)
- adreno_ringbuffer_issuecmds(device,
- adreno_dev->drawctxt_active,
- KGSL_CMD_FLAGS_NONE, &cmds[0], 2);
+ adreno_ringbuffer_issuecmds_intr(device,
+ context, &cmds[0], 2);
else
/* We would never call this function if there
* was no active contexts running */
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 57f4859..78bdc3f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -32,7 +32,7 @@
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
-#define KGSL_CMD_FLAGS_NO_TS_CMP 0x00000002
+#define KGSL_CMD_FLAGS_DUMMY_INTR_CMD 0x00000002
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 5a76c86..86fe3f5 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1982,7 +1982,13 @@
0x18000000);
}
- adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
+ if (adreno_is_a203(adreno_dev))
+ /* For A203 increase number of clocks that RBBM
+ * will wait before de-asserting Register Clock
+ * Active signal */
+ adreno_regwrite(device, REG_RBBM_CNTL, 0x0000FFFF);
+ else
+ adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 098c4f5..6c74dfa 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -147,6 +147,7 @@
{
struct adreno_context *drawctxt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
int ret;
drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
@@ -157,6 +158,7 @@
drawctxt->pagetable = pagetable;
drawctxt->bin_base_offset = 0;
drawctxt->id = context->id;
+ rb->timestamp[context->id] = 0;
if (flags & KGSL_CONTEXT_PREAMBLE)
drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
@@ -174,6 +176,12 @@
kgsl_sharedmem_writel(&device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
KGSL_INIT_REFTIMESTAMP);
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
context->devctxt = drawctxt;
return 0;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 86a349a..49786ba 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -404,11 +404,8 @@
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
{
- if (rb->flags & KGSL_FLAGS_STARTED) {
- /* ME_HALT */
- adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
+ if (rb->flags & KGSL_FLAGS_STARTED)
rb->flags &= ~KGSL_FLAGS_STARTED;
- }
}
int adreno_ringbuffer_init(struct kgsl_device *device)
@@ -494,9 +491,9 @@
* error checking if needed
*/
total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
- total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
/* 2 dwords to store the start of command sequence */
total_sizedwords += 2;
+ total_sizedwords += context ? 7 : 0;
if (adreno_is_a3xx(adreno_dev))
total_sizedwords += 7;
@@ -548,9 +545,10 @@
/* always increment the global timestamp. once. */
rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
- if (context) {
+
+ if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
if (context_id == KGSL_MEMSTORE_GLOBAL)
- rb->timestamp[context_id] =
+ rb->timestamp[context->id] =
rb->timestamp[KGSL_MEMSTORE_GLOBAL];
else
rb->timestamp[context_id]++;
@@ -580,7 +578,7 @@
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(context->id, soptimestamp)));
+ KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
/* end-of-pipeline timestamp */
@@ -588,14 +586,14 @@
cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
+ KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp)));
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu,
rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
} else {
@@ -603,13 +601,11 @@
cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
- rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
}
- if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
+ if (context) {
/* Conditional execution based on memory values */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_COND_EXEC, 4));
@@ -641,6 +637,30 @@
return timestamp;
}
+void
+adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+ struct kgsl_context *k_ctxt,
+ unsigned int *cmds,
+ int sizedwords)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct adreno_context *a_ctxt = NULL;
+
+ if (!k_ctxt)
+ return;
+
+ a_ctxt = k_ctxt->devctxt;
+
+ if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
+ a_ctxt == NULL ||
+ device->state & KGSL_STATE_HUNG)
+ return;
+
+ adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
+ cmds, sizedwords);
+}
+
unsigned int
adreno_ringbuffer_issuecmds(struct kgsl_device *device,
struct adreno_context *drawctxt,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 4cc57c2..6c3d9b1 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -110,6 +110,11 @@
unsigned int *cmdaddr,
int sizedwords);
+void adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+ struct kgsl_context *k_ctxt,
+ unsigned int *cmdaddr,
+ int sizedwords);
+
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb);
void kgsl_cp_intrcallback(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fa204c3..62e1521 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -450,6 +450,7 @@
device->state == KGSL_STATE_ACTIVE &&
device->requested_state == KGSL_STATE_NONE) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+ kgsl_pwrscale_idle(device, 1);
if (kgsl_pwrctrl_sleep(device) != 0)
mod_timer(&device->idle_timer,
jiffies +
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index edccff1..d8472f2 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -686,7 +686,6 @@
static void kgsl_gpummu_stop(struct kgsl_mmu *mmu)
{
- kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
mmu->flags &= ~KGSL_FLAGS_STARTED;
}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 016771b..e858651 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -880,7 +880,6 @@
*/
if (mmu->flags & KGSL_FLAGS_STARTED) {
- kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
/* detach iommu attachment */
kgsl_detach_pagetable_iommu_domain(mmu);
mmu->hwpagetable = NULL;
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index fbf3bb4..bfe6957 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -640,7 +640,7 @@
mutex_lock(&device->mutex);
if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
- kgsl_pwrscale_idle(device);
+ kgsl_pwrscale_idle(device, 0);
if (kgsl_pwrctrl_sleep(device) != 0) {
mod_timer(&device->idle_timer,
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 6fb9326..f6277b3 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -237,21 +237,18 @@
void kgsl_pwrscale_busy(struct kgsl_device *device)
{
if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->busy)
- if ((!device->pwrscale.gpu_busy) &&
- (device->requested_state != KGSL_STATE_SLUMBER))
+ if (device->requested_state != KGSL_STATE_SLUMBER)
device->pwrscale.policy->busy(device,
&device->pwrscale);
- device->pwrscale.gpu_busy = 1;
}
-void kgsl_pwrscale_idle(struct kgsl_device *device)
+void kgsl_pwrscale_idle(struct kgsl_device *device, unsigned int ignore_idle)
{
if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->idle)
if (device->requested_state != KGSL_STATE_SLUMBER &&
device->requested_state != KGSL_STATE_SLEEP)
device->pwrscale.policy->idle(device,
- &device->pwrscale);
- device->pwrscale.gpu_busy = 0;
+ &device->pwrscale, ignore_idle);
}
EXPORT_SYMBOL(kgsl_pwrscale_idle);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index 34698cd..ba9b1af 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -23,7 +23,8 @@
void (*close)(struct kgsl_device *device,
struct kgsl_pwrscale *pwrscale);
void (*idle)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale);
+ struct kgsl_pwrscale *pwrscale,
+ unsigned int ignore_idle);
void (*busy)(struct kgsl_device *device,
struct kgsl_pwrscale *pwrscale);
void (*sleep)(struct kgsl_device *device,
@@ -36,7 +37,6 @@
struct kgsl_pwrscale_policy *policy;
struct kobject kobj;
void *priv;
- int gpu_busy;
int enabled;
};
@@ -64,7 +64,8 @@
struct kgsl_pwrscale_policy *policy);
void kgsl_pwrscale_detach_policy(struct kgsl_device *device);
-void kgsl_pwrscale_idle(struct kgsl_device *device);
+void kgsl_pwrscale_idle(struct kgsl_device *device,
+ unsigned int ignore_idle);
void kgsl_pwrscale_busy(struct kgsl_device *device);
void kgsl_pwrscale_sleep(struct kgsl_device *device);
void kgsl_pwrscale_wake(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
index 4102302..fc58dd1 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
@@ -131,7 +131,7 @@
}
static void idlestats_idle(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
+ struct kgsl_pwrscale *pwrscale, unsigned int ignore_idle)
{
int i, nr_cpu;
struct idlestats_priv *priv = pwrscale->priv;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index 61d4b2d..c6f8b1b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -17,6 +17,7 @@
#include "kgsl_pwrscale.h"
#include "kgsl_device.h"
#include "a2xx_reg.h"
+#include "kgsl_trace.h"
struct msm_priv {
struct kgsl_device *device;
@@ -26,6 +27,7 @@
struct msm_dcvs_idle idle_source;
struct msm_dcvs_freq freq_sink;
struct msm_dcvs_core_info *core_info;
+ int gpu_busy;
};
static int msm_idle_enable(struct msm_dcvs_idle *self,
@@ -89,29 +91,40 @@
struct kgsl_pwrscale *pwrscale)
{
struct msm_priv *priv = pwrscale->priv;
- if (priv->enabled)
+ if (priv->enabled && !priv->gpu_busy) {
msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_EXIT, 0);
+ trace_kgsl_mpdcvs(device, 1);
+ priv->gpu_busy = 1;
+ }
return;
}
static void msm_idle(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
+ struct kgsl_pwrscale *pwrscale, unsigned int ignore_idle)
{
struct msm_priv *priv = pwrscale->priv;
- unsigned int rb_rptr, rb_wptr;
- kgsl_regread(device, REG_CP_RB_RPTR, &rb_rptr);
- kgsl_regread(device, REG_CP_RB_WPTR, &rb_wptr);
- if (priv->enabled && (rb_rptr == rb_wptr))
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
-
+ if (priv->enabled && priv->gpu_busy)
+ if (device->ftbl->isidle(device)) {
+ msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ trace_kgsl_mpdcvs(device, 0);
+ priv->gpu_busy = 0;
+ }
return;
}
static void msm_sleep(struct kgsl_device *device,
struct kgsl_pwrscale *pwrscale)
{
- /* do we need to reset any parameters here? */
+ struct msm_priv *priv = pwrscale->priv;
+
+ if (priv->enabled && priv->gpu_busy) {
+ msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ trace_kgsl_mpdcvs(device, 0);
+ priv->gpu_busy = 0;
+ }
+
+ return;
}
static int msm_init(struct kgsl_device *device,
@@ -159,10 +172,10 @@
ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
if (ret >= 0) {
if (device->ftbl->isidle(device)) {
- device->pwrscale.gpu_busy = 0;
+ priv->gpu_busy = 0;
msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
} else {
- device->pwrscale.gpu_busy = 1;
+ priv->gpu_busy = 1;
}
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index d6c5e66..1b029b1 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -119,16 +119,19 @@
device->pwrctrl.default_pwrlevel);
}
-static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
+static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale,
+ unsigned int ignore_idle)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct tz_priv *priv = pwrscale->priv;
struct kgsl_power_stats stats;
int val, idle;
+ if (ignore_idle)
+ return;
+
/* In "performance" mode the clock speed always stays
the same */
-
if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
return;
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 3eff40f..81ab3fb 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -251,6 +251,29 @@
)
);
+TRACE_EVENT(kgsl_mpdcvs,
+
+ TP_PROTO(struct kgsl_device *device, unsigned int state),
+
+ TP_ARGS(device, state),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, state)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->state = state;
+ ),
+
+ TP_printk(
+ "d_name=%s %s",
+ __get_str(device_name),
+ __entry->state ? "BUSY" : "IDLE"
+ )
+);
+
DECLARE_EVENT_CLASS(kgsl_pwrstate_template,
TP_PROTO(struct kgsl_device *device, unsigned int state),
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index e59ca17..55639e0 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -415,6 +415,7 @@
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_set_abs_params(input_dev, ABS_X, ts->min_x,
ts->max_x, pdata->fuzzx, 0);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 790cc10..df71f76 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -685,6 +685,52 @@
}
}
+void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
+ size_t count)
+{
+ struct dvb_demux_feed *feed;
+ u16 pid = ts_pid(buf);
+ struct timespec pre_time;
+
+ if (dvb_demux_performancecheck)
+ pre_time = current_kernel_time();
+
+ spin_lock(&demux->lock);
+
+ demux->sw_filter_abort = 0;
+
+ while (count--) {
+ if (buf[0] != 0x47) {
+ buf += 188;
+ continue;
+ }
+
+ if (demux->playback_mode == DMX_PB_MODE_PULL)
+ if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0)
+ break;
+
+ list_for_each_entry(feed, &demux->feed_list, list_head) {
+ if (feed->pid != pid)
+ continue;
+
+ if (!feed->feed.sec.is_filtering)
+ continue;
+
+ if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) {
+ feed->feed.sec.seclen = 0;
+ feed->feed.sec.secbufp = 0;
+ }
+ }
+ buf += 188;
+ }
+
+ spin_unlock(&demux->lock);
+
+ if (dvb_demux_performancecheck)
+ demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_section_packets);
+
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
{
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index a663191..5a32363 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -179,6 +179,8 @@
int dvb_dmx_init(struct dvb_demux *dvbdemux);
void dvb_dmx_release(struct dvb_demux *dvbdemux);
+void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
+ size_t count);
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
size_t count);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 116b7f9..af4c2c9 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -122,6 +122,8 @@
int enable_optimized_srch_alg;
unsigned char spur_table_size;
struct fm_spur_data spur_data;
+ atomic_t validate_channel;
+ unsigned char is_station_valid;
};
/**************************************************************************
@@ -152,6 +154,7 @@
static int update_spur_table(struct tavarua_device *radio);
static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
unsigned long offset, unsigned char *buf);
+static int compute_MPX_DCC(struct tavarua_device *radio, int *val);
/* work function */
static void read_int_stat(struct work_struct *work);
@@ -734,7 +737,7 @@
static void tavarua_handle_interrupts(struct tavarua_device *radio)
{
int i;
- int retval;
+ int retval, adj_channel_tune_req = 0;
unsigned char xfr_status;
if (!radio->handle_irq) {
FMDBG("IRQ happend, but I wont handle it\n");
@@ -758,7 +761,25 @@
complete(&radio->sync_req_done);
radio->tune_req = 0;
}
- tavarua_q_event(radio, TAVARUA_EVT_TUNE_SUCC);
+
+ /*
+ * Do not queue the TUNE event while validating if the station
+ * is good or not. As part of channel validation we tune to the
+ * adjacent station, measure its MPX_DCC value, then tune back
+ * to the original station and measure its MPX_DCC value.
+ * Compare the MPX_DCC values of curent and adjacent stations
+ * and decide if the channel is valid or not. During this period
+ * we should not queue the TUNE event to the upper layers.
+ */
+ adj_channel_tune_req = atomic_read(&radio->validate_channel);
+ if (adj_channel_tune_req) {
+ complete(&radio->sync_req_done);
+ FMDBG("Tune event for adjacent channel\n");
+ } else {
+ tavarua_q_event(radio, TAVARUA_EVT_TUNE_SUCC);
+ FMDBG("Queueing Tune event\n");
+ }
+
if (radio->srch_params.get_list) {
tavarua_start_xfr(radio, TAVARUA_XFR_SRCH_LIST,
RX_STATIONS_0);
@@ -2603,40 +2624,57 @@
static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
unsigned long offset, unsigned char *buf) {
- unsigned char xfr_buf[XFR_REG_NUM];
+ unsigned char xfr_buf[XFR_REG_NUM + 1];
int retval = 0, temp = 0;
+ /* zero initialize the buffer */
memset(xfr_buf, 0x0, XFR_REG_NUM);
+
+ /* save the 'size' parameter */
temp = size;
- xfr_buf[XFR_MODE_OFFSET] = (size << 1);
+ /* Populate the XFR bytes */
+ xfr_buf[XFR_MODE_OFFSET] = LSH_DATA(size, 1);
xfr_buf[XFR_ADDR_MSB_OFFSET] = GET_FREQ(offset, 1);
xfr_buf[XFR_ADDR_LSB_OFFSET] = GET_FREQ(offset, 0);
-
if (op == XFR_READ) {
+ if (size > XFR_REG_NUM) {
+ FMDERR("%s: Cant read more than 16 bytes\n", __func__);
+ return -EINVAL;
+ }
xfr_buf[XFR_MODE_OFFSET] |= (XFR_PEEK_MODE);
size = 3;
} else if (op == XFR_WRITE) {
+ if (size > (XFR_REG_NUM - 2)) {
+ FMDERR("%s: Cant write more than 14 bytes\n", __func__);
+ return -EINVAL;
+ }
xfr_buf[XFR_MODE_OFFSET] |= (XFR_POKE_MODE);
memcpy(&xfr_buf[XFR_DATA_OFFSET], buf, size);
size += 3;
}
+ /* Perform the XFR READ/WRITE operation */
+ init_completion(&radio->sync_req_done);
retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, size);
if (retval < 0) {
- FMDERR("%s: Failed to performXFR operation\n", __func__);
+ FMDERR("%s: Failed to perform XFR operation\n", __func__);
return retval;
}
- size = temp;
-
/*Wait for the XFR interrupt */
- init_completion(&radio->sync_req_done);
if (!wait_for_completion_timeout(&radio->sync_req_done,
msecs_to_jiffies(WAIT_TIMEOUT))) {
FMDERR("Timeout: No XFR interrupt");
+ return -ETIMEDOUT;
}
+ /*
+ * For XFR READ operation save the XFR data provided by the SOC.
+ * Firmware reads the data from the address specified and places
+ * them in to the registers XFRDAT0-XFRDAT15 which the host can read.
+ */
+ size = temp;
if (op == XFR_READ) {
retval = tavarua_read_registers(radio, XFRDAT0, size);
if (retval < 0) {
@@ -2645,6 +2683,10 @@
}
if (buf != NULL)
memcpy(buf, &radio->registers[XFRDAT0], size);
+ else {
+ FMDERR("%s: No buffer to copy XFR data\n", __func__);
+ return -EINVAL;
+ }
}
return retval;
@@ -2966,6 +3008,9 @@
case V4L2_CID_PRIVATE_IRIS_GET_SINR:
retval = 0;
break;
+ case V4L2_CID_PRIVATE_VALID_CHANNEL:
+ ctrl->value = radio->is_station_valid;
+ break;
default:
retval = -EINVAL;
}
@@ -3114,12 +3159,15 @@
struct v4l2_control *ctrl)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
- int retval = 0;
- int size = 0, cnt = 0;
+ int retval = 0, size = 0, cnt = 0;
unsigned char value;
unsigned char xfr_buf[XFR_REG_NUM];
unsigned char tx_data[XFR_REG_NUM];
unsigned char dis_buf[XFR_REG_NUM];
+ unsigned int freq = 0, mpx_dcc = 0;
+ unsigned long curr = 0, prev = 0;
+
+ memset(xfr_buf, 0x0, XFR_REG_NUM);
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -3538,6 +3586,104 @@
if (retval < 0)
FMDERR("Tone generator failed\n");
break;
+ case V4L2_CID_PRIVATE_VALID_CHANNEL:
+ /* Do not notify the host of tune event */
+ atomic_set(&radio->validate_channel, 1);
+
+ FMDBG("Going into low power mode\n");
+ retval = tavarua_disable_interrupts(radio);
+
+ /*
+ * Tune to 50KHz adjacent channel. If the requested station
+ * falls in JAPAN band and on the lower band-limit, then the
+ * adjacnet channel to be considered is 50KHz to the right side
+ * of the requested station as firmware does not allows to tune
+ * to frequency outside the range: 76000KHz to 108000KHz.
+ */
+ if (ctrl->value == REGION_JAPAN_STANDARD_BAND_LOW)
+ freq = (ctrl->value + ADJ_CHANNEL_KHZ);
+ else
+ freq = (ctrl->value - ADJ_CHANNEL_KHZ);
+ INIT_COMPLETION(radio->sync_req_done);
+ retval = tavarua_set_freq(radio, (freq * TUNE_MULT));
+ if (retval < 0) {
+ FMDERR("Failed to tune to adjacent station\n");
+ goto error;
+ }
+ if (!wait_for_completion_timeout(&radio->sync_req_done,
+ msecs_to_jiffies(wait_timeout))) {
+ FMDERR("Timeout: No Tune response\n");
+ retval = -ETIMEDOUT;
+ goto error;
+ }
+
+ /*
+ * Wait for a minimum of 100ms for the firmware
+ * to start collecting the MPX_DCC values
+ */
+ msleep(TAVARUA_DELAY * 10);
+
+ /* Compute MPX_DCC of adjacent station */
+ retval = compute_MPX_DCC(radio, &mpx_dcc);
+ if (retval < 0) {
+ FMDERR("Failed to get MPX_DCC of adjacent station\n");
+ goto error;
+ }
+ /* Calculate the absolute value of MPX_DCC */
+ prev = abs(mpx_dcc);
+
+ /* Tune back to original station */
+ INIT_COMPLETION(radio->sync_req_done);
+ retval = tavarua_set_freq(radio, (ctrl->value * TUNE_MULT));
+ if (retval < 0) {
+ FMDERR("Failed to tune to requested station\n");
+ goto error;
+ }
+ if (!wait_for_completion_timeout(&radio->sync_req_done,
+ msecs_to_jiffies(wait_timeout))) {
+ FMDERR("Timeout: No Tune response\n");
+ retval = -ETIMEDOUT;
+ goto error;
+ }
+
+ /*
+ * Wait for a minimum of 100ms for the firmware
+ * to start collecting the MPX_DCC values
+ */
+ msleep(TAVARUA_DELAY * 10);
+
+ /* Compute MPX_DCC of current station */
+ retval = compute_MPX_DCC(radio, &mpx_dcc);
+ if (retval < 0) {
+ FMDERR("Failed to get MPX_DCC of current station\n");
+ goto error;
+ }
+ /* Calculate the absolute value of MPX_DCC */
+ curr = abs(mpx_dcc);
+
+ FMDBG("Going into normal power mode\n");
+ tavarua_setup_interrupts(radio,
+ (radio->registers[RDCTRL] & 0x03));
+
+ FMDBG("Absolute MPX_DCC of current station : %lu\n", curr);
+ FMDBG("Absolute MPX_DCC of adjacent station : %lu\n", prev);
+
+ /*
+ * For valid stations, the absolute MPX_DCC value will be within
+ * the range 0 <= MPX_DCC <= 12566 and the MPX_DCC value of the
+ * adjacent station will be greater than 20,000.
+ */
+ if ((curr <= MPX_DCC_LIMIT) &&
+ (prev > MPX_DCC_UPPER_LIMIT)) {
+ FMDBG("%d KHz is A VALID STATION!\n", ctrl->value);
+ radio->is_station_valid = VALID_CHANNEL;
+ } else {
+ FMDBG("%d KHz is NOT A VALID STATION!\n", ctrl->value);
+ radio->is_station_valid = INVALID_CHANNEL;
+ }
+error:
+ atomic_set(&radio->validate_channel, 0);
+ break;
default:
retval = -EINVAL;
}
@@ -3548,6 +3694,56 @@
return retval;
}
+static int compute_MPX_DCC(struct tavarua_device *radio, int *val)
+{
+
+ int DCC = 0, retval = 0;
+ int MPX_DCC[3];
+ unsigned char value;
+ unsigned char xfr_buf[XFR_REG_NUM];
+
+ /* Freeze the MPX_DCC value from changing */
+ value = CTRL_ON;
+ retval = xfr_rdwr_data(radio, XFR_WRITE, 1, MPX_DCC_BYPASS_REG, &value);
+ if (retval < 0) {
+ FMDERR("%s: Failed to freeze MPX_DCC\n", __func__);
+ return retval;
+ }
+
+ /* Measure the MPX_DCC of current station. */
+ retval = xfr_rdwr_data(radio, XFR_READ, 3, MPX_DCC_DATA_REG, xfr_buf);
+ if (retval < 0) {
+ FMDERR("%s: Failed to read MPX_DCC\n", __func__);
+ return retval;
+ }
+ MPX_DCC[0] = xfr_buf[0];
+ MPX_DCC[1] = xfr_buf[1];
+ MPX_DCC[2] = xfr_buf[2];
+ /*
+ * Form the final MPX_DCC parameter
+ * MPX_DCC[0] will form the LSB part
+ * MPX_DCC[1] will be the middle part and 4 bits of
+ * MPX_DCC[2] will be the MSB part of the 20-bit signed MPX_DCC
+ */
+ DCC = (LSH_DATA(MPX_DCC[2], 16) | LSH_DATA(MPX_DCC[1], 8) | MPX_DCC[0]);
+
+ /* if bit-19 is '1',set remaining bits to '1' & make it -tive */
+ if (DCC & 0x00080000)
+ DCC |= 0xFFF00000;
+
+ *val = DCC;
+
+ /* Un-freeze the MPX_DCC value */
+ value = CTRL_OFF;
+ retval = xfr_rdwr_data(radio, XFR_WRITE, 1, 0x88C0, &value);
+ if (retval < 0) {
+ FMDERR("%s: Failed to un-freeze MPX_DCC\n", __func__);
+ return retval;
+ }
+
+ return retval;
+}
+
/*=============================================================================
FUNCTION: tavarua_vidioc_g_tuner
=============================================================================*/
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
index ecc4fea..c678ea2 100644
--- a/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
@@ -69,9 +69,11 @@
#define RAW_INTF_1_OVERFLOW_IRQ 25
#define RESET_DONE_IRQ 27
-#define ISPIF_IRQ_STATUS_MASK 0xA493000
-#define ISPIF_IRQ_1_STATUS_MASK 0xA493000
-#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_MASK 0xA493249
+#define ISPIF_IRQ_1_STATUS_MASK 0xA493249
+#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249
+#define ISPIF_IRQ_STATUS_SOF_MASK 0x492249
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
#endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
index 820adf4..4b17538 100644
--- a/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
@@ -83,9 +83,12 @@
#define RAW_INTF_1_OVERFLOW_IRQ 25
#define RESET_DONE_IRQ 27
-#define ISPIF_IRQ_STATUS_MASK 0xA493000
-#define ISPIF_IRQ_1_STATUS_MASK 0xA493000
-#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_MASK 0xA493249
+#define ISPIF_IRQ_1_STATUS_MASK 0xA493249
+#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249
+#define ISPIF_IRQ_STATUS_SOF_MASK 0x492249
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
+
#endif
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index b23efb5..092ee90 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -24,6 +24,7 @@
#define V4L2_IDENT_ISPIF 50001
#define CSID_VERSION_V2 0x02000011
#define CSID_VERSION_V3 0x30000000
+
#define MAX_CID 15
static atomic_t ispif_irq_cnt;
@@ -52,6 +53,7 @@
else
data1 |= (0x1 << PIX_0_VFE_RST_STB) |
(0x1 << PIX_0_CSID_RST_STB);
+ ispif->pix_sof_count = 0;
break;
case RDI0:
@@ -127,7 +129,7 @@
(0x1 << PIX_1_CSID_RST_STB) |
(0x1 << RDI_2_VFE_RST_STB) |
(0x1 << RDI_2_CSID_RST_STB);
- return 0;
+ ispif->pix_sof_count = 0;
msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
rc = wait_for_completion_interruptible(&ispif->reset_complete);
if (ispif->csid_version >= CSID_VERSION_V3) {
@@ -568,7 +570,8 @@
DECLARE_TASKLET(ispif_tasklet, ispif_do_tasklet, 0);
-static void ispif_process_irq(struct ispif_irq_status *out)
+static void ispif_process_irq(struct ispif_device *ispif,
+ struct ispif_irq_status *out)
{
unsigned long flags;
struct ispif_isr_queue_cmd *qcmd;
@@ -583,6 +586,13 @@
qcmd->ispifInterruptStatus0 = out->ispifIrqStatus0;
qcmd->ispifInterruptStatus1 = out->ispifIrqStatus1;
+ if (qcmd->ispifInterruptStatus0 & ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
+ CDBG("%s: ispif PIX sof irq\n", __func__);
+ ispif->pix_sof_count++;
+ v4l2_subdev_notify(&ispif->subdev, NOTIFY_VFE_SOF_COUNT,
+ (void *)&ispif->pix_sof_count);
+ }
+
spin_lock_irqsave(&ispif_tasklet_lock, flags);
list_add_tail(&qcmd->list, &ispif_tasklet_q);
@@ -605,7 +615,7 @@
msm_camera_io_w(out->ispifIrqStatus1,
ispif->base + ISPIF_IRQ_CLEAR_1_ADDR);
- CDBG("ispif->irq: Irq_status0 = 0x%x\n",
+ CDBG("%s: irq ispif->irq: Irq_status0 = 0x%x\n", __func__,
out->ispifIrqStatus0);
if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ))
@@ -614,10 +624,10 @@
pr_err("%s: pix intf 0 overflow.\n", __func__);
if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ))
pr_err("%s: rdi intf 0 overflow.\n", __func__);
- if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_RDI_SOF_MASK) ||
+ if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_SOF_MASK) ||
(out->ispifIrqStatus1 &
- ISPIF_IRQ_STATUS_RDI_SOF_MASK)) {
- ispif_process_irq(out);
+ ISPIF_IRQ_STATUS_SOF_MASK)) {
+ ispif_process_irq(ispif, out);
}
}
msm_camera_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
@@ -648,7 +658,6 @@
INIT_LIST_HEAD(&ispif_tasklet_q);
rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
IRQF_TRIGGER_RISING, "ispif", ispif);
-
init_completion(&ispif->reset_complete);
ispif->csid_version = *csid_version;
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index df93a44..f4ad661 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -34,6 +34,7 @@
struct completion reset_complete;
uint32_t csid_version;
struct clk *ispif_clk[5];
+ uint32_t pix_sof_count;
};
struct ispif_isr_queue_cmd {
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 29aba08..b14d4f6 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -718,6 +718,8 @@
SET_VIDEO_INST_IDX(pcam_inst->inst_handle, pcam_inst->my_index);
pcam_inst->pcam->dev_inst_map[pcam_inst->image_mode] = pcam_inst;
pcam_inst->path = msm_vidbuf_get_path(pcam_inst->image_mode);
+ rc = msm_cam_server_config_interface_map(pcam_inst->image_mode,
+ pcam_inst->pcam->mctl_handle);
D("%spath=%d,rc=%d\n", __func__,
pcam_inst->path, rc);
return rc;
@@ -834,7 +836,6 @@
int ion_client_created = 0;
#endif
int server_q_idx = 0;
- /*struct msm_isp_ops *p_isp = 0;*/
/* get the video device */
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
struct msm_cam_v4l2_dev_inst *pcam_inst;
@@ -941,8 +942,7 @@
msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
if (pmctl->mctl_release)
- if (pmctl->mctl_release(pmctl) < 0)
- pr_err("%s: mctl_release failed\n", __func__);
+ pmctl->mctl_release(pmctl);
mctl_open_failed:
if (pcam->use_count == 1) {
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -1066,11 +1066,8 @@
if (pcam_inst->streamon) {
/*something went wrong since instance
is closing without streamoff*/
- if (pmctl->mctl_release) {
- rc = pmctl->mctl_release(pmctl);
- if (rc < 0)
- pr_err("mctl_release fails %d\n", rc);
- }
+ if (pmctl->mctl_release)
+ pmctl->mctl_release(pmctl);
pmctl->mctl_release = NULL;/*so that it isn't closed again*/
}
@@ -1100,11 +1097,8 @@
pr_err("msm_send_close_server failed %d\n", rc);
}
- if (pmctl->mctl_release) {
- rc = pmctl->mctl_release(pmctl);
- if (rc < 0)
- pr_err("mctl_release fails %d\n", rc);
- }
+ if (pmctl->mctl_release)
+ pmctl->mctl_release(pmctl);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
kref_put(&pmctl->refcount, msm_release_ion_client);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 687ed74..a2c21bd 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -148,11 +148,11 @@
NOTIFY_VFE_MSG_COMP_STATS, /* arg = struct msm_stats_buf */
NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
NOTIFY_VFE_CAMIF_ERROR,
+ NOTIFY_VFE_SOF_COUNT, /*arg = int*/
NOTIFY_PCLK_CHANGE, /* arg = pclk */
NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
NOTIFY_CSIC_CFG, /* arg = msm_camera_csic_params */
- NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
NOTIFY_VFE_IRQ,
NOTIFY_AXI_IRQ,
NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
@@ -237,7 +237,7 @@
int (*mctl_cb)(void);
int (*mctl_cmd)(struct msm_cam_media_controller *p_mctl,
unsigned int cmd, unsigned long arg);
- int (*mctl_release)(struct msm_cam_media_controller *p_mctl);
+ void (*mctl_release)(struct msm_cam_media_controller *p_mctl);
int (*mctl_buf_init)(struct msm_cam_v4l2_dev_inst *pcam);
int (*mctl_vbqueue_init)(struct msm_cam_v4l2_dev_inst *pcam,
struct vb2_queue *q, enum v4l2_buf_type type);
@@ -288,15 +288,10 @@
struct msm_isp_ops {
char *config_dev_name;
- /*int (*isp_init)(struct msm_cam_v4l2_device *pcam);*/
- int (*isp_open)(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl);
int (*isp_config)(struct msm_cam_media_controller *pmctl,
unsigned int cmd, unsigned long arg);
int (*isp_notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
- void (*isp_release)(struct msm_cam_media_controller *mctl,
- struct v4l2_subdev *sd);
int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
struct msm_mctl_pp_cmd, void *data);
@@ -398,9 +393,9 @@
struct cdev config_cdev;
struct v4l2_queue_util config_stat_event_queue;
int use_count;
- /*struct msm_isp_ops* isp_subdev;*/
struct msm_cam_media_controller *p_mctl;
struct msm_mem_map_info mem_map;
+ int dev_num;
};
struct msm_cam_subdev_info {
@@ -490,6 +485,15 @@
struct intr_table_entry comp_intr_tbl[CAMERA_SS_IRQ_MAX];
};
+struct interface_map {
+ /* The interafce a particular stream belongs to.
+ * PIX0, RDI0, RDI1, or RDI2
+ */
+ int interface;
+ /* The handle of the mctl intstance interface runs on */
+ uint32_t mctl_handle;
+};
+
/* abstract camera server device for all sensor successfully probed*/
struct msm_cam_server_dev {
@@ -505,7 +509,7 @@
/* info of configs successfully created*/
struct msm_cam_config_dev_info config_info;
/* active working camera device - only one allowed at this time*/
- struct msm_cam_v4l2_device *pcam_active;
+ struct msm_cam_v4l2_device *pcam_active[MAX_NUM_ACTIVE_CAMERA];
/* number of camera devices opened*/
atomic_t number_pcam_active;
struct v4l2_queue_util server_command_queue;
@@ -519,6 +523,8 @@
struct msm_cam_server_mctl_inst mctl[MAX_NUM_ACTIVE_CAMERA];
uint32_t mctl_handle_cnt;
+ struct interface_map interface_map_table[INTF_MAX];
+
int use_count;
/* all the registered ISP subdevice*/
struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 935ce75..3d94afd 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -67,16 +67,16 @@
}
}
-static int msm_isp_notify_VFE_BUF_FREE_EVT(struct v4l2_subdev *sd, void *arg)
+static int msm_isp_notify_VFE_SOF_COUNT_EVT(struct v4l2_subdev *sd, void *arg)
{
struct msm_vfe_cfg_cmd cfgcmd;
struct msm_camvfe_params vfe_params;
int rc;
- cfgcmd.cmd_type = CMD_VFE_BUFFER_RELEASE;
+ cfgcmd.cmd_type = CMD_VFE_SOF_COUNT_UPDATE;
cfgcmd.value = NULL;
vfe_params.vfe_cfg = &cfgcmd;
- vfe_params.data = NULL;
+ vfe_params.data = arg;
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
return 0;
}
@@ -294,8 +294,8 @@
if (notification == NOTIFY_VFE_BUF_EVT)
return msm_isp_notify_VFE_BUF_EVT(sd, arg);
- if (notification == NOTIFY_VFE_BUF_FREE_EVT)
- return msm_isp_notify_VFE_BUF_FREE_EVT(sd, arg);
+ if (notification == NOTIFY_VFE_SOF_COUNT)
+ return msm_isp_notify_VFE_SOF_COUNT_EVT(sd, arg);
isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_ATOMIC);
if (!isp_event) {
@@ -499,35 +499,6 @@
return msm_isp_notify_vfe(sd, notification, arg);
}
-/* This function is called by open() function, so we need to init HW*/
-static int msm_isp_open(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
-{
- /* init vfe and senor, register sync callbacks for init*/
- int rc = 0;
- D("%s\n", __func__);
- if (!mctl) {
- pr_err("%s: param is NULL", __func__);
- return -EINVAL;
- }
-
- rc = v4l2_subdev_call(sd, core, ioctl,
- VIDIOC_MSM_VFE_INIT, NULL);
- if (rc < 0) {
- pr_err("%s: vfe_init failed at %d\n",
- __func__, rc);
- }
- return rc;
-}
-
-static void msm_isp_release(struct msm_cam_media_controller *mctl,
- struct v4l2_subdev *sd)
-{
- D("%s\n", __func__);
- v4l2_subdev_call(sd, core, ioctl,
- VIDIOC_MSM_VFE_RELEASE, NULL);
-}
-
static int msm_config_vfe(struct v4l2_subdev *sd,
struct msm_cam_media_controller *mctl, void __user *arg)
{
@@ -780,9 +751,7 @@
int i = 0;
for (i = 0; i < g_num_config_nodes; i++) {
- isp_subdev[i].isp_open = msm_isp_open;
isp_subdev[i].isp_config = msm_isp_config;
- isp_subdev[i].isp_release = msm_isp_release;
isp_subdev[i].isp_notify = msm_isp_notify;
}
return 0;
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index fd5591c..d4d72b9 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -130,6 +130,14 @@
.pxlcode = V4L2_MBUS_FMT_SGRBG10_1X10, /* Bayer sensor */
.colorspace = V4L2_COLORSPACE_JPEG,
},
+ {
+ .name = "YUYV",
+ .depth = 16,
+ .bitsperpxl = 16,
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .pxlcode = V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
};
@@ -548,9 +556,8 @@
return rc;
}
-static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
+static void msm_mctl_release(struct msm_cam_media_controller *p_mctl)
{
- int rc = 0;
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
struct msm_camera_sensor_info *sinfo =
(struct msm_camera_sensor_info *) s_ctrl->sensordata;
@@ -573,11 +580,6 @@
VIDIOC_MSM_AXI_RELEASE, NULL);
}
- if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release
- && p_mctl->isp_sdev->sd)
- p_mctl->isp_sdev->isp_release(p_mctl,
- p_mctl->isp_sdev->sd);
-
if (p_mctl->csid_sdev) {
v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
VIDIOC_MSM_CSID_RELEASE, NULL);
@@ -601,7 +603,6 @@
pm_qos_remove_request(&p_mctl->pm_qos_req_list);
wake_unlock(&p_mctl->wake_lock);
- return rc;
}
int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam)
@@ -1467,6 +1468,9 @@
pcam_inst->pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] =
pcam_inst;
pcam_inst->path = msm_mctl_vidbuf_get_path(pcam_inst->image_mode);
+
+ rc = msm_cam_server_config_interface_map(pcam_inst->image_mode,
+ pcam_inst->pcam->mctl_handle);
D("%s path=%d, image mode = %d rc=%d\n", __func__,
pcam_inst->path, pcam_inst->image_mode, rc);
return rc;
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 36b9576..2cc61a1 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -108,6 +108,58 @@
v4l2_fh_exit(eventHandle);
}
+int msm_cam_server_config_interface_map(u32 extendedmode, uint32_t mctl_handle)
+{
+ int i = 0;
+ int rc = 0;
+ int old_handle;
+ int interface;
+
+ switch (extendedmode) {
+ case MSM_V4L2_EXT_CAPTURE_MODE_RDI:
+ interface = RDI_0;
+ break;
+ case MSM_V4L2_EXT_CAPTURE_MODE_RDI1:
+ interface = RDI_1;
+ break;
+ case MSM_V4L2_EXT_CAPTURE_MODE_RDI2:
+ interface = RDI_2;
+ break;
+ default:
+ interface = PIX_0;
+ break;
+ }
+ for (i = 0; i < INTF_MAX; i++) {
+ if (g_server_dev.interface_map_table[i].interface ==
+ interface) {
+ old_handle =
+ g_server_dev.interface_map_table[i].mctl_handle;
+ if (old_handle == 0) {
+ g_server_dev.interface_map_table[i].mctl_handle
+ = mctl_handle;
+ } else if (old_handle != mctl_handle) {
+ pr_err("%s: interface_map[%d] was set: %d\n",
+ __func__, i, old_handle);
+ rc = -EINVAL;
+ }
+ break;
+ }
+ }
+
+ if (i == INTF_MAX)
+ rc = -EINVAL;
+ return rc;
+}
+
+void msm_cam_server_clear_interface_map(uint32_t mctl_handle)
+{
+ int i;
+ for (i = 0; i < INTF_MAX; i++)
+ if (g_server_dev.interface_map_table[i].mctl_handle ==
+ mctl_handle)
+ g_server_dev.interface_map_table[i].mctl_handle = 0;
+}
+
uint32_t msm_cam_server_get_mctl_handle(void)
{
uint32_t i;
@@ -146,13 +198,15 @@
return NULL;
}
-static void msm_cam_server_send_error_evt(int evt_type)
+
+static void msm_cam_server_send_error_evt(
+ struct msm_cam_media_controller *pmctl, int evt_type)
{
struct v4l2_event v4l2_ev;
v4l2_ev.id = 0;
v4l2_ev.type = evt_type;
ktime_get_ts(&v4l2_ev.timestamp);
- v4l2_event_queue(g_server_dev.pcam_active->pvdev, &v4l2_ev);
+ v4l2_event_queue(pmctl->pcam_ptr->pvdev, &v4l2_ev);
}
static int msm_ctrl_cmd_done(void *arg)
@@ -370,7 +424,8 @@
ctrlcmd.vnode_id = pcam->vnode_id;
ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
- ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+ ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[
+ pcam->server_queue_idx];
/* send command to config thread in userspace, and get return value */
rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -384,15 +439,17 @@
{
int rc = 0;
struct msm_ctrl_cmd ctrlcmd;
+ int idx = pcam->server_queue_idx;
D("%s qid %d\n", __func__, pcam->server_queue_idx);
ctrlcmd.type = MSM_V4L2_OPEN;
ctrlcmd.timeout_ms = 10000;
- ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
- MAX_DEV_NAME_LEN)+1;
- ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[0];
+ ctrlcmd.length = strnlen(
+ g_server_dev.config_info.config_dev_name[idx],
+ MAX_DEV_NAME_LEN)+1;
+ ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[idx];
ctrlcmd.vnode_id = pcam->vnode_id;
ctrlcmd.queue_idx = pcam->server_queue_idx;
- ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+ ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[idx];
/* send command to config thread in usersspace, and get return value */
rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -407,12 +464,14 @@
D("%s qid %d\n", __func__, pcam->server_queue_idx);
ctrlcmd.type = MSM_V4L2_CLOSE;
ctrlcmd.timeout_ms = 10000;
- ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
- MAX_DEV_NAME_LEN)+1;
- ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[0];
+ ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[
+ pcam->server_queue_idx], MAX_DEV_NAME_LEN)+1;
+ ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[
+ pcam->server_queue_idx];
ctrlcmd.vnode_id = pcam->vnode_id;
ctrlcmd.queue_idx = pcam->server_queue_idx;
- ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+ ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[
+ pcam->server_queue_idx];
/* send command to config thread in usersspace, and get return value */
rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -904,19 +963,20 @@
return rc;
}
- /* The number of camera instance should be controlled by the
- resource manager. Currently supporting one active instance
- until multiple instances are supported */
- if (atomic_read(&ps->number_pcam_active) > 0) {
- pr_err("%s Cannot have more than one active camera %d\n",
+ /*
+ * The number of camera instance should be controlled by the
+ * resource manager. Currently supporting two active instances
+ */
+ if (atomic_read(&ps->number_pcam_active) > 1) {
+ pr_err("%s Cannot have more than two active camera %d\n",
__func__, atomic_read(&ps->number_pcam_active));
return -EINVAL;
}
/* book keeping this camera session*/
- ps->pcam_active = pcam;
+ ps->pcam_active[pcam->server_queue_idx] = pcam;
atomic_inc(&ps->number_pcam_active);
- D("config pcam = 0x%p\n", ps->pcam_active);
+ D("config pcam = 0x%p\n", pcam);
/* initialization the media controller module*/
msm_mctl_init(pcam);
@@ -928,6 +988,7 @@
static int msm_cam_server_close_session(struct msm_cam_server_dev *ps,
struct msm_cam_v4l2_device *pcam)
{
+ int i;
int rc = 0;
D("%s\n", __func__);
@@ -936,10 +997,14 @@
return rc;
}
-
atomic_dec(&ps->number_pcam_active);
- ps->pcam_active = NULL;
+ ps->pcam_active[pcam->server_queue_idx] = NULL;
+ for (i = 0; i < INTF_MAX; i++) {
+ if (ps->interface_map_table[i].mctl_handle ==
+ pcam->mctl_handle)
+ ps->interface_map_table[i].mctl_handle = 0;
+ }
msm_mctl_free(pcam);
return rc;
}
@@ -1228,22 +1293,23 @@
mutex_unlock(&g_server_dev.server_lock);
if (g_server_dev.use_count == 0) {
+ int i;
mutex_lock(&g_server_dev.server_lock);
- if (g_server_dev.pcam_active) {
- struct msm_cam_media_controller *pmctl = NULL;
- int rc;
+ for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
+ if (g_server_dev.pcam_active[i]) {
+ struct msm_cam_media_controller *pmctl = NULL;
- pmctl = msm_cam_server_get_mctl(
- g_server_dev.pcam_active->mctl_handle);
- if (pmctl && pmctl->mctl_release) {
- rc = pmctl->mctl_release(pmctl);
- if (rc < 0)
- pr_err("mctl_release fails %d\n", rc);
- /*so that it isn't closed again*/
- pmctl->mctl_release = NULL;
+ pmctl = msm_cam_server_get_mctl(
+ g_server_dev.pcam_active[i]->mctl_handle);
+ if (pmctl && pmctl->mctl_release) {
+ pmctl->mctl_release(pmctl);
+ /*so that it isn't closed again*/
+ pmctl->mctl_release = NULL;
+ }
+ msm_cam_server_send_error_evt(pmctl,
+ V4L2_EVENT_PRIVATE_START +
+ MSM_CAM_APP_NOTIFY_ERROR_EVENT);
}
- msm_cam_server_send_error_evt(V4L2_EVENT_PRIVATE_START
- + MSM_CAM_APP_NOTIFY_ERROR_EVENT);
}
sub.type = V4L2_EVENT_ALL;
msm_server_v4l2_unsubscribe_event(
@@ -1433,49 +1499,96 @@
.vidioc_default = msm_ioctl_server,
};
+static uint32_t msm_camera_server_find_mctl(
+ unsigned int notification, void *arg)
+{
+ int i;
+ uint32_t interface;
+
+ switch (notification) {
+ case NOTIFY_ISP_MSG_EVT:
+ if (((struct isp_msg_event *)arg)->msg_id ==
+ MSG_ID_RDI0_UPDATE_ACK)
+ interface = RDI_0;
+ else if (((struct isp_msg_event *)arg)->msg_id ==
+ MSG_ID_RDI1_UPDATE_ACK)
+ interface = RDI_1;
+ else
+ interface = PIX_0;
+ break;
+ case NOTIFY_VFE_MSG_OUT:
+ if (((struct isp_msg_output *)arg)->output_id ==
+ MSG_ID_OUTPUT_TERTIARY1)
+ interface = RDI_0;
+ else if (((struct isp_msg_output *)arg)->output_id ==
+ MSG_ID_OUTPUT_TERTIARY2)
+ interface = RDI_1;
+ else
+ interface = PIX_0;
+ break;
+ case NOTIFY_VFE_BUF_EVT: {
+ struct msm_vfe_resp *rp;
+ struct msm_frame_info *frame_info;
+ rp = (struct msm_vfe_resp *)arg;
+ frame_info = rp->evt_msg.data;
+ if (frame_info->path == VFE_MSG_OUTPUT_TERTIARY1)
+ interface = RDI_0;
+ else if (frame_info->path == VFE_MSG_OUTPUT_TERTIARY2)
+ interface = RDI_1;
+ else
+ interface = PIX_0;
+ }
+ break;
+ case NOTIFY_VFE_MSG_STATS:
+ case NOTIFY_VFE_MSG_COMP_STATS:
+ case NOTIFY_VFE_CAMIF_ERROR:
+ case NOTIFY_VFE_IRQ:
+ default:
+ interface = PIX_0;
+ break;
+ }
+
+ for (i = 0; i < INTF_MAX; i++) {
+ if (interface == g_server_dev.interface_map_table[i].interface)
+ break;
+ }
+ if (i == INTF_MAX) {
+ pr_err("%s: Cannot find valid interface map\n", __func__);
+ return -EINVAL;
+ } else
+ return g_server_dev.interface_map_table[i].mctl_handle;
+}
+
static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
unsigned int notification, void *arg)
{
int rc = -EINVAL;
- struct msm_sensor_ctrl_t *s_ctrl;
- struct msm_camera_sensor_info *sinfo;
- struct msm_camera_device_platform_data *camdev;
- uint8_t csid_core = 0;
- struct msm_cam_media_controller *p_mctl;
+ uint32_t mctl_handle = 0;
+ struct msm_cam_media_controller *p_mctl = NULL;
- if (notification == NOTIFY_PCLK_CHANGE ||
- notification == NOTIFY_CSIPHY_CFG ||
- notification == NOTIFY_CSID_CFG ||
- notification == NOTIFY_CSIC_CFG) {
- s_ctrl = get_sctrl(sd);
- sinfo = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
- camdev = sinfo->pdata;
- csid_core = camdev->csid_core;
- }
- if (notification != NOTIFY_GESTURE_CAM_EVT) {
- p_mctl = v4l2_get_subdev_hostdata(sd);
- if (p_mctl == NULL) {
- pr_err("%s: cannot find mctl, %d\n",
- __func__, notification);
- return;
- }
+ mctl_handle = msm_camera_server_find_mctl(notification, arg);
+ if (mctl_handle < 0) {
+ pr_err("%s: Couldn't find mctl instance!\n", __func__);
+ return;
}
switch (notification) {
case NOTIFY_ISP_MSG_EVT:
case NOTIFY_VFE_MSG_OUT:
+ case NOTIFY_VFE_SOF_COUNT:
case NOTIFY_VFE_MSG_STATS:
case NOTIFY_VFE_MSG_COMP_STATS:
case NOTIFY_VFE_BUF_EVT:
- case NOTIFY_VFE_BUF_FREE_EVT:
- if (g_server_dev.isp_subdev[0] &&
- g_server_dev.isp_subdev[0]->isp_notify
+ p_mctl = msm_cam_server_get_mctl(mctl_handle);
+ if (p_mctl->isp_sdev &&
+ p_mctl->isp_sdev->isp_notify
&& p_mctl->isp_sdev->sd)
- rc = g_server_dev.isp_subdev[0]->isp_notify(
+ rc = p_mctl->isp_sdev->isp_notify(
p_mctl->isp_sdev->sd, notification, arg);
break;
case NOTIFY_VFE_IRQ:{
struct msm_vfe_cfg_cmd cfg_cmd;
struct msm_camvfe_params vfe_params;
+ p_mctl = msm_cam_server_get_mctl(mctl_handle);
cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
vfe_params.vfe_cfg = &cfg_cmd;
vfe_params.data = arg;
@@ -1484,10 +1597,10 @@
}
break;
case NOTIFY_AXI_IRQ:
- rc = v4l2_subdev_call(p_mctl->axi_sdev,
- core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
+ rc = v4l2_subdev_call(sd, core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
break;
case NOTIFY_PCLK_CHANGE:
+ p_mctl = v4l2_get_subdev_hostdata(sd);
if (p_mctl->axi_sdev)
rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
s_crystal_freq, *(uint32_t *)arg, 0);
@@ -1496,14 +1609,17 @@
s_crystal_freq, *(uint32_t *)arg, 0);
break;
case NOTIFY_CSIPHY_CFG:
+ p_mctl = v4l2_get_subdev_hostdata(sd);
rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
break;
case NOTIFY_CSID_CFG:
+ p_mctl = v4l2_get_subdev_hostdata(sd);
rc = v4l2_subdev_call(p_mctl->csid_sdev,
core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
break;
case NOTIFY_CSIC_CFG:
+ p_mctl = v4l2_get_subdev_hostdata(sd);
rc = v4l2_subdev_call(p_mctl->csic_sdev,
core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
break;
@@ -1516,7 +1632,8 @@
core, ioctl, VIDIOC_MSM_GESTURE_CAM_EVT, arg);
break;
case NOTIFY_VFE_CAMIF_ERROR: {
- msm_cam_server_send_error_evt(V4L2_EVENT_PRIVATE_START
+ p_mctl = msm_cam_server_get_mctl(mctl_handle);
+ msm_cam_server_send_error_evt(p_mctl, V4L2_EVENT_PRIVATE_START
+ MSM_CAM_APP_NOTIFY_ERROR_EVENT);
break;
}
@@ -2111,7 +2228,6 @@
spin_lock_init(&g_server_dev.intr_table_lock);
memset(&g_server_dev.irq_lkup_table, 0,
sizeof(struct irqmgr_intr_lkup_table));
- g_server_dev.pcam_active = NULL;
g_server_dev.camera_info.num_cameras = 0;
atomic_set(&g_server_dev.number_pcam_active, 0);
g_server_dev.server_evt_id = 0;
@@ -2129,6 +2245,12 @@
queue->queue_active = 0;
msm_queue_init(&queue->ctrl_q, "control");
msm_queue_init(&queue->eventData_q, "eventdata");
+ g_server_dev.pcam_active[i] = NULL;
+ }
+
+ for (i = 0; i < INTF_MAX; i++) {
+ g_server_dev.interface_map_table[i].interface = 0x01 << i;
+ g_server_dev.interface_map_table[i].mctl_handle = 0;
}
return rc;
}
@@ -2162,9 +2284,8 @@
{
int rc = 0;
struct msm_cam_media_controller *pmctl = NULL;
- D("%s: %p", __func__, g_server_dev.pcam_active);
*p_active = 0;
- if (g_server_dev.pcam_active) {
+ if (g_server_dev.pcam_active[pcam->server_queue_idx]) {
D("%s: Active camera present return", __func__);
return 0;
}
@@ -2206,11 +2327,8 @@
return -ENODEV;
}
- if (pmctl->mctl_release) {
- rc = pmctl->mctl_release(pmctl);
- if (rc < 0)
- pr_err("mctl_release fails %d\n", rc);
- }
+ if (pmctl->mctl_release)
+ pmctl->mctl_release(pmctl);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
kref_put(&pmctl->refcount, msm_release_ion_client);
@@ -2452,8 +2570,8 @@
config_cam->use_count++;
/* assume there is only one active camera possible*/
- config_cam->p_mctl =
- msm_cam_server_get_mctl(g_server_dev.pcam_active->mctl_handle);
+ config_cam->p_mctl = msm_cam_server_get_mctl(
+ g_server_dev.pcam_active[config_cam->dev_num]->mctl_handle);
if (!config_cam->p_mctl) {
pr_err("%s: cannot find mctl\n", __func__);
return -ENODEV;
@@ -2858,6 +2976,7 @@
msm_setup_v4l2_event_queue(
&config_cam->config_stat_event_queue.eventHandle,
config_cam->config_stat_event_queue.pvdev);
+ config_cam->dev_num = dev_num;
return rc;
@@ -2870,9 +2989,9 @@
{
int rc = 0, i;
memset(&g_server_dev, 0, sizeof(struct msm_cam_server_dev));
- /*for now just create a config 0 node
+ /*for now just create two config nodes
put logic here later to know how many configs to create*/
- g_server_dev.config_info.num_config_nodes = 1;
+ g_server_dev.config_info.num_config_nodes = 2;
rc = msm_isp_init_module(g_server_dev.config_info.num_config_nodes);
if (rc < 0) {
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
index 8a02d32..229e9c9 100644
--- a/drivers/media/video/msm/server/msm_cam_server.h
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -64,4 +64,6 @@
int msm_cam_server_request_irq(void *arg);
int msm_cam_server_update_irqmap(
struct msm_cam_server_irqmap_entry *entry);
+int msm_cam_server_config_interface_map(u32 extendedmode,
+ uint32_t mctl_handle);
#endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm/vfe/Makefile b/drivers/media/video/msm/vfe/Makefile
index 8068e4f..91f0e7f 100644
--- a/drivers/media/video/msm/vfe/Makefile
+++ b/drivers/media/video/msm/vfe/Makefile
@@ -16,4 +16,5 @@
obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o
obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o
obj-$(CONFIG_ARCH_MSM8960) += msm_vfe32.o
+obj-$(CONFIG_ARCH_MSM8974) += msm_vfe40.o msm_vfe40_axi.o
obj-$(CONFIG_MSM_CAMERA_V4L2) += msm_vfe_stats_buf.o
diff --git a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
index a3037d5..0bd7b94 100644
--- a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
@@ -3830,6 +3830,10 @@
/* No need to decouple AXI/VFE for VFE3.1*/
break;
+ case CMD_AXI_RESET:
+ /* No need to decouple AXI/VFE for VFE3.1*/
+ break;
+
default:
pr_err("%s Unsupported AXI configuration %x ", __func__,
cmd->cmd_type);
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 2f50d7f..3e01437 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -412,36 +412,33 @@
}
}
-static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
+static void axi_disable_irq(struct axi_ctrl_t *axi_ctrl)
{
- unsigned long flags;
-
- atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
-
- /* for reset hw modules, and send msg when reset_irq comes.*/
- spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
- vfe32_ctrl->share_ctrl->stop_ack_pending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
/* disable all interrupts. */
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* clear all pending interrupts*/
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+}
+static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
+{
+
+ atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
/* in either continuous or snapshot mode, stop command can be issued
* at any time. stop camif immediately. */
- msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
+ msm_camera_io_w(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
vfe32_ctrl->share_ctrl->operation_mode &=
~(vfe32_ctrl->share_ctrl->current_mode);
@@ -561,44 +558,50 @@
axi_cfg, 12);
axi_cfg += 3;
}
- /* TODO: Only reload for 1st axi config for concurrent case */
msm_camera_io_w(bus_cmd, axi_ctrl->share_ctrl->vfebase +
V32_AXI_BUS_CMD_OFF);
return 0;
}
+static void axi_reset_internal_variables(
+ struct axi_ctrl_t *axi_ctrl)
+{
+ unsigned long flags;
+ /* state control variables */
+ axi_ctrl->share_ctrl->start_ack_pending = FALSE;
+ atomic_set(&irq_cnt, 0);
+
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+ axi_ctrl->share_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+
+ init_completion(&axi_ctrl->share_ctrl->reset_complete);
+
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->update_ack_lock, flags);
+ axi_ctrl->share_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->update_ack_lock, flags);
+
+ axi_ctrl->share_ctrl->recording_state = VFE_STATE_IDLE;
+ axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+ atomic_set(&axi_ctrl->share_ctrl->vstate, 0);
+ atomic_set(&axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0);
+ atomic_set(&axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0);
+ atomic_set(&axi_ctrl->share_ctrl->rdi2_update_ack_pending, 0);
+
+ /* 0 for continuous mode, 1 for snapshot mode */
+ axi_ctrl->share_ctrl->operation_mode = 0;
+ axi_ctrl->share_ctrl->current_mode = 0;
+ axi_ctrl->share_ctrl->outpath.output_mode = 0;
+ axi_ctrl->share_ctrl->vfe_capture_count = 0;
+
+ /* this is unsigned 32 bit integer. */
+ axi_ctrl->share_ctrl->vfeFrameId = 0;
+}
+
static void vfe32_reset_internal_variables(
struct vfe32_ctrl_type *vfe32_ctrl)
{
- unsigned long flags;
- vfe32_ctrl->vfeImaskCompositePacked = 0;
- /* state control variables */
- vfe32_ctrl->start_ack_pending = FALSE;
- atomic_set(&irq_cnt, 0);
-
- spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
- vfe32_ctrl->share_ctrl->stop_ack_pending = FALSE;
- spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
-
- init_completion(&vfe32_ctrl->reset_complete);
-
- spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
- vfe32_ctrl->update_ack_pending = FALSE;
- spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
-
- vfe32_ctrl->recording_state = VFE_STATE_IDLE;
- vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
-
- atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
-
- /* 0 for continuous mode, 1 for snapshot mode */
- vfe32_ctrl->share_ctrl->operation_mode = 0;
- vfe32_ctrl->share_ctrl->current_mode = 0;
- vfe32_ctrl->share_ctrl->outpath.output_mode = 0;
- vfe32_ctrl->share_ctrl->vfe_capture_count = 0;
-
- /* this is unsigned 32 bit integer. */
- vfe32_ctrl->share_ctrl->vfeFrameId = 0;
/* Stats control variables. */
memset(&(vfe32_ctrl->afbfStatsControl), 0,
sizeof(struct vfe_stats_control));
@@ -682,31 +685,30 @@
vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
}
-static int vfe32_reset(struct vfe32_ctrl_type *vfe32_ctrl)
+static int axi_reset(struct axi_ctrl_t *axi_ctrl)
{
- vfe32_reset_internal_variables(vfe32_ctrl);
+ axi_reset_internal_variables(axi_ctrl);
/* disable all interrupts. vfeImaskLocal is also reset to 0
* to begin with. */
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* clear all pending interrupts*/
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
/* Ensure the write order while writing
to the command register using the barrier */
- msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
- VFE_IRQ_CMD);
+ msm_camera_io_w_mb(1, axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
/* enable reset_ack interrupt. */
msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
* is done, hardware interrupt will be generated. VFE ist processes
@@ -716,13 +718,10 @@
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(VFE_RESET_UPON_RESET_CMD,
- vfe32_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+ axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
- if (vfe32_ctrl->is_reset_blocking)
- return wait_for_completion_interruptible(
- &vfe32_ctrl->reset_complete);
- else
- return 0;
+ return wait_for_completion_interruptible(
+ &axi_ctrl->share_ctrl->reset_complete);
}
static int vfe32_operation_config(uint32_t *cmd,
@@ -1068,7 +1067,7 @@
uint16_t vfe_operation_mode =
vfe32_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
VFE_OUTPUTS_RDI1);
- vfe32_ctrl->start_ack_pending = TRUE;
+ vfe32_ctrl->share_ctrl->start_ack_pending = TRUE;
CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
vfe32_ctrl->share_ctrl->current_mode,
vfe32_ctrl->share_ctrl->outpath.output_mode);
@@ -1095,13 +1094,25 @@
irq_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
msm_camera_io_w(irq_mask1, vfe32_ctrl->share_ctrl->vfebase +
VFE_IRQ_MASK_1);
- msm_camera_io_w_mb(reg_update|0x2, vfe32_ctrl->share_ctrl->
- vfebase + VFE_REG_UPDATE_CMD);
+ if (!atomic_cmpxchg(
+ &vfe32_ctrl->share_ctrl->rdi0_update_ack_pending,
+ 0, 1)) {
+ msm_camera_io_w_mb(reg_update|0x2,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ }
}
if (vfe32_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
irq_mask1 |= VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK;
msm_camera_io_w(irq_mask1, vfe32_ctrl->share_ctrl->vfebase +
VFE_IRQ_MASK_1);
+ if (!atomic_cmpxchg(
+ &vfe32_ctrl->share_ctrl->rdi1_update_ack_pending,
+ 0, 1)) {
+ msm_camera_io_w_mb(reg_update|0x4,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ }
msm_camera_io_w_mb(reg_update|0x4, vfe32_ctrl->share_ctrl->
vfebase + VFE_REG_UPDATE_CMD);
}
@@ -1122,9 +1133,7 @@
struct msm_cam_media_controller *pmctl,
struct vfe32_ctrl_type *vfe32_ctrl)
{
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
- vfe32_ctrl->recording_state = VFE_STATE_START_REQUESTED;
+ vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_START_REQUESTED;
msm_camera_io_w_mb(1,
vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
return 0;
@@ -1134,11 +1143,9 @@
struct msm_cam_media_controller *pmctl,
struct vfe32_ctrl_type *vfe32_ctrl)
{
- vfe32_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+ vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
msm_camera_io_w_mb(1,
vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
return 0;
}
@@ -1151,8 +1158,6 @@
vfe32_ctrl->share_ctrl->vfe_capture_count =
vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt;
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_LIVESHOT);
vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
msm_camera_io_w_mb(1, vfe32_ctrl->
share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
@@ -1165,8 +1170,6 @@
vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_STOP_REQUESTED;
msm_camera_io_w_mb(1,
vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
}
static int vfe32_zsl(
@@ -1174,8 +1177,6 @@
struct vfe32_ctrl_type *vfe32_ctrl)
{
vfe32_start_common(vfe32_ctrl);
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x188);
@@ -1188,8 +1189,6 @@
{
vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt = num_frames_capture;
vfe32_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
vfe32_start_common(vfe32_ctrl);
return 0;
}
@@ -1217,9 +1216,6 @@
vfe32_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
-
vfe32_start_common(vfe32_ctrl);
/* for debug */
msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
@@ -1231,8 +1227,6 @@
struct msm_cam_media_controller *pmctl,
struct vfe32_ctrl_type *vfe32_ctrl)
{
- msm_camio_bus_scale_cfg(
- pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
vfe32_start_common(vfe32_ctrl);
return 0;
}
@@ -1284,9 +1278,9 @@
vfe32_ctrl->update_gamma = false;
}
- spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
- vfe32_ctrl->update_ack_pending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
+ spin_lock_irqsave(&vfe32_ctrl->share_ctrl->update_ack_lock, flags);
+ vfe32_ctrl->share_ctrl->update_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->update_ack_lock, flags);
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(1,
@@ -1467,53 +1461,53 @@
b = &outch->free_buf;
return b;
}
-static int vfe32_configure_pingpong_buffers(
- int id, int path, struct vfe32_ctrl_type *vfe32_ctrl)
+static int configure_pingpong_buffers(
+ int id, int path, struct axi_ctrl_t *axi_ctrl)
{
struct vfe32_output_ch *outch = NULL;
int rc = 0;
uint32_t inst_handle = 0;
if (path == VFE_MSG_OUTPUT_PRIMARY)
- inst_handle = vfe32_ctrl->share_ctrl->outpath.out0.inst_handle;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
- inst_handle = vfe32_ctrl->share_ctrl->outpath.out1.inst_handle;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
else if (path == VFE_MSG_OUTPUT_TERTIARY1)
- inst_handle = vfe32_ctrl->share_ctrl->outpath.out2.inst_handle;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
else if (path == VFE_MSG_OUTPUT_TERTIARY2)
- inst_handle = vfe32_ctrl->share_ctrl->outpath.out3.inst_handle;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
vfe32_subdev_notify(id, path, inst_handle,
- &vfe32_ctrl->subdev, vfe32_ctrl->share_ctrl);
- outch = vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+ &axi_ctrl->subdev, axi_ctrl->share_ctrl);
+ outch = vfe32_get_ch(path, axi_ctrl->share_ctrl);
if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
/* Configure Preview Ping Pong */
pr_info("%s Configure ping/pong address for %d",
__func__, path);
vfe32_put_ch_ping_addr(
- vfe32_ctrl->share_ctrl->vfebase, outch->ch0,
+ axi_ctrl->share_ctrl->vfebase, outch->ch0,
outch->ping.ch_paddr[0]);
vfe32_put_ch_pong_addr(
- vfe32_ctrl->share_ctrl->vfebase, outch->ch0,
+ axi_ctrl->share_ctrl->vfebase, outch->ch0,
outch->pong.ch_paddr[0]);
- if ((vfe32_ctrl->share_ctrl->current_mode !=
+ if ((axi_ctrl->share_ctrl->current_mode !=
VFE_OUTPUTS_RAW) && (path != VFE_MSG_OUTPUT_TERTIARY1)
&& (path != VFE_MSG_OUTPUT_TERTIARY2)) {
vfe32_put_ch_ping_addr(
- vfe32_ctrl->share_ctrl->vfebase, outch->ch1,
+ axi_ctrl->share_ctrl->vfebase, outch->ch1,
outch->ping.ch_paddr[1]);
vfe32_put_ch_pong_addr(
- vfe32_ctrl->share_ctrl->vfebase, outch->ch1,
+ axi_ctrl->share_ctrl->vfebase, outch->ch1,
outch->pong.ch_paddr[1]);
}
if (outch->ping.num_planes > 2)
vfe32_put_ch_ping_addr(
- vfe32_ctrl->share_ctrl->vfebase, outch->ch2,
+ axi_ctrl->share_ctrl->vfebase, outch->ch2,
outch->ping.ch_paddr[2]);
if (outch->pong.num_planes > 2)
vfe32_put_ch_pong_addr(
- vfe32_ctrl->share_ctrl->vfebase, outch->ch2,
+ axi_ctrl->share_ctrl->vfebase, outch->ch2,
outch->pong.ch_paddr[2]);
/* avoid stale info */
@@ -1568,7 +1562,6 @@
uint32_t *cmdp_local = NULL;
uint32_t snapshot_cnt = 0;
uint32_t temp1 = 0, temp2 = 0;
- uint16_t vfe_mode = 0;
struct msm_camera_vfe_params_t vfe_params;
CDBG("vfe32_proc_general: cmdID = %s, length = %d\n",
@@ -1577,8 +1570,7 @@
case VFE_CMD_RESET:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- vfe32_ctrl->is_reset_blocking = false;
- vfe32_reset(vfe32_ctrl);
+ vfe32_reset_internal_variables(vfe32_ctrl);
break;
case VFE_CMD_START:
pr_info("vfe32_proc_general: cmdID = %s\n",
@@ -1592,42 +1584,7 @@
vfe32_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- vfe_mode = vfe32_ctrl->share_ctrl->current_mode
- & ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1);
- if (vfe_mode) {
- if ((vfe32_ctrl->share_ctrl->current_mode &
- VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
- (vfe32_ctrl->share_ctrl->current_mode &
- VFE_OUTPUTS_PREVIEW))
- /* Configure primary channel */
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_START,
- VFE_MSG_OUTPUT_PRIMARY,
- vfe32_ctrl);
- else
- /* Configure secondary channel */
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_START,
- VFE_MSG_OUTPUT_SECONDARY,
- vfe32_ctrl);
- }
- if (vfe32_ctrl->share_ctrl->current_mode &
- VFE_OUTPUTS_RDI0)
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY1,
- vfe32_ctrl);
- if (vfe32_ctrl->share_ctrl->current_mode &
- VFE_OUTPUTS_RDI1)
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY2,
- vfe32_ctrl);
- if (rc < 0) {
- pr_err("%s error configuring pingpong buffers"
- " for preview", __func__);
- rc = -EINVAL;
- goto proc_general_done;
- }
rc = vfe32_start(pmctl, vfe32_ctrl);
break;
case VFE_CMD_UPDATE:
@@ -1645,15 +1602,6 @@
snapshot_cnt = vfe_params.capture_count;
vfe32_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
- vfe32_ctrl);
- if (rc < 0) {
- pr_err("%s error configuring pingpong buffers"
- " for snapshot", __func__);
- rc = -EINVAL;
- goto proc_general_done;
- }
rc = vfe32_capture_raw(pmctl, vfe32_ctrl, snapshot_cnt);
break;
case VFE_CMD_CAPTURE:
@@ -1667,78 +1615,12 @@
snapshot_cnt = vfe_params.capture_count;
vfe32_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- if (vfe32_ctrl->share_ctrl->current_mode ==
- VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe32_ctrl->share_ctrl->current_mode ==
- VFE_OUTPUTS_THUMB_AND_JPEG) {
- if (snapshot_cnt != 1) {
- pr_err("only support 1 inline snapshot\n");
- rc = -EINVAL;
- goto proc_general_done;
- }
- /* Configure primary channel for JPEG */
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_JPEG_CAPTURE,
- VFE_MSG_OUTPUT_PRIMARY,
- vfe32_ctrl);
- } else {
- /* Configure primary channel */
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_CAPTURE,
- VFE_MSG_OUTPUT_PRIMARY,
- vfe32_ctrl);
- }
- if (rc < 0) {
- pr_err("%s error configuring pingpong buffers"
- " for primary output", __func__);
- rc = -EINVAL;
- goto proc_general_done;
- }
- /* Configure secondary channel */
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
- vfe32_ctrl);
- if (rc < 0) {
- pr_err("%s error configuring pingpong buffers"
- " for secondary output", __func__);
- rc = -EINVAL;
- goto proc_general_done;
- }
+
rc = vfe32_capture(pmctl, snapshot_cnt, vfe32_ctrl);
break;
case VFE_CMD_START_RECORDING:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- if (copy_from_user(&temp1, (void __user *)(cmd->value),
- sizeof(uint32_t))) {
- pr_err("%s Error copying inst_handle for recording\n",
- __func__);
- rc = -EFAULT;
- goto proc_general_done;
- }
- if (vfe32_ctrl->share_ctrl->current_mode &
- VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
- vfe32_ctrl->share_ctrl->outpath.out1.inst_handle =
- temp1;
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_START_RECORDING,
- VFE_MSG_OUTPUT_SECONDARY,
- vfe32_ctrl);
- } else if (vfe32_ctrl->share_ctrl->current_mode &
- VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
- vfe32_ctrl->share_ctrl->outpath.out0.inst_handle =
- temp1;
- rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_START_RECORDING,
- VFE_MSG_OUTPUT_PRIMARY,
- vfe32_ctrl);
- }
- if (rc < 0) {
- pr_err("%s error configuring pingpong buffers"
- " for video", __func__);
- rc = -EINVAL;
- goto proc_general_done;
- }
rc = vfe32_start_recording(pmctl, vfe32_ctrl);
break;
case VFE_CMD_STOP_RECORDING:
@@ -2280,23 +2162,7 @@
break;
case VFE_CMD_LIVESHOT:
- if (copy_from_user(&temp1, (void __user *)(cmd->value),
- sizeof(uint32_t))) {
- pr_err("%s Error copying inst_handle for liveshot ",
- __func__);
- rc = -EFAULT;
- goto proc_general_done;
- }
- vfe32_ctrl->share_ctrl->outpath.out0.inst_handle = temp1;
/* Configure primary channel */
- rc = vfe32_configure_pingpong_buffers(VFE_MSG_CAPTURE,
- VFE_MSG_OUTPUT_PRIMARY, vfe32_ctrl);
- if (rc < 0) {
- pr_err("%s error configuring pingpong buffers"
- " for primary output", __func__);
- rc = -EINVAL;
- goto proc_general_done;
- }
vfe32_start_liveshot(pmctl, vfe32_ctrl);
break;
@@ -2838,14 +2704,6 @@
vfe32_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- rc = vfe32_configure_pingpong_buffers(VFE_MSG_START,
- VFE_MSG_OUTPUT_PRIMARY, vfe32_ctrl);
- if (rc < 0)
- goto proc_general_done;
- rc = vfe32_configure_pingpong_buffers(VFE_MSG_START,
- VFE_MSG_OUTPUT_SECONDARY, vfe32_ctrl);
- if (rc < 0)
- goto proc_general_done;
rc = vfe32_zsl(pmctl, vfe32_ctrl);
break;
@@ -3110,12 +2968,6 @@
CDBG("%s Stopping liveshot ", __func__);
vfe32_stop_liveshot(pmctl, vfe32_ctrl);
break;
- case VFE_CMD_RESET_2:
- CDBG("vfe32_proc_general: cmdID = %s\n",
- vfe32_general_cmd[cmd->id]);
- vfe32_ctrl->is_reset_blocking = true;
- vfe32_reset(vfe32_ctrl);
- break;
default:
if (cmd->length != vfe32_cmd[cmd->id].length)
return -EINVAL;
@@ -3179,7 +3031,8 @@
{
unsigned long flags;
- if (vfe32_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+ if (vfe32_ctrl->share_ctrl->recording_state ==
+ VFE_STATE_START_REQUESTED) {
if (vfe32_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
@@ -3197,11 +3050,11 @@
vfe32_AXI_WM_CFG[vfe32_ctrl->
share_ctrl->outpath.out1.ch1]);
}
- vfe32_ctrl->recording_state = VFE_STATE_STARTED;
+ vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_STARTED;
msm_camera_io_w_mb(1,
vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
CDBG("start video triggered .\n");
- } else if (vfe32_ctrl->recording_state ==
+ } else if (vfe32_ctrl->share_ctrl->recording_state ==
VFE_STATE_STOP_REQUESTED) {
if (vfe32_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
@@ -3223,40 +3076,47 @@
CDBG("stop video triggered .\n");
}
- spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
- if (vfe32_ctrl->start_ack_pending == TRUE) {
- vfe32_ctrl->start_ack_pending = FALSE;
- spin_unlock_irqrestore(&vfe32_ctrl->start_ack_lock, flags);
+ spin_lock_irqsave(&vfe32_ctrl->share_ctrl->start_ack_lock, flags);
+ if (vfe32_ctrl->share_ctrl->start_ack_pending == TRUE) {
+ vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &vfe32_ctrl->share_ctrl->start_ack_lock, flags);
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
} else {
- spin_unlock_irqrestore(&vfe32_ctrl->start_ack_lock, flags);
- if (vfe32_ctrl->recording_state ==
+ spin_unlock_irqrestore(
+ &vfe32_ctrl->share_ctrl->start_ack_lock, flags);
+ if (vfe32_ctrl->share_ctrl->recording_state ==
VFE_STATE_STOP_REQUESTED) {
- vfe32_ctrl->recording_state = VFE_STATE_STOPPED;
+ vfe32_ctrl->share_ctrl->recording_state =
+ VFE_STATE_STOPPED;
/* request a reg update and send STOP_REC_ACK
* when we process the next reg update irq.
*/
msm_camera_io_w_mb(1,
vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- } else if (vfe32_ctrl->recording_state ==
+ } else if (vfe32_ctrl->share_ctrl->recording_state ==
VFE_STATE_STOPPED) {
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_STOP_REC_ACK);
- vfe32_ctrl->recording_state = VFE_STATE_IDLE;
+ vfe32_ctrl->share_ctrl->recording_state =
+ VFE_STATE_IDLE;
}
- spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
- if (vfe32_ctrl->update_ack_pending == TRUE) {
- vfe32_ctrl->update_ack_pending = FALSE;
+ spin_lock_irqsave(
+ &vfe32_ctrl->share_ctrl->update_ack_lock, flags);
+ if (vfe32_ctrl->share_ctrl->update_ack_pending == TRUE) {
+ vfe32_ctrl->share_ctrl->update_ack_pending = FALSE;
spin_unlock_irqrestore(
- &vfe32_ctrl->update_ack_lock, flags);
+ &vfe32_ctrl->share_ctrl->update_ack_lock,
+ flags);
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_UPDATE_ACK);
} else {
spin_unlock_irqrestore(
- &vfe32_ctrl->update_ack_lock, flags);
+ &vfe32_ctrl->share_ctrl->update_ack_lock,
+ flags);
}
}
@@ -3376,34 +3236,22 @@
static void vfe32_process_rdi0_reg_update_irq(
struct vfe32_ctrl_type *vfe32_ctrl)
{
- unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
- if (vfe32_ctrl->start_ack_pending == TRUE) {
- vfe32_ctrl->start_ack_pending = FALSE;
- spin_unlock_irqrestore(
- &vfe32_ctrl->start_ack_lock, flags);
+ if (atomic_cmpxchg(
+ &vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0)) {
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
- } else {
- spin_unlock_irqrestore(
- &vfe32_ctrl->start_ack_lock, flags);
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI0_UPDATE_ACK);
}
}
static void vfe32_process_rdi1_reg_update_irq(
struct vfe32_ctrl_type *vfe32_ctrl)
{
- unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
- if (vfe32_ctrl->start_ack_pending == TRUE) {
- vfe32_ctrl->start_ack_pending = FALSE;
- spin_unlock_irqrestore(
- &vfe32_ctrl->start_ack_lock, flags);
+ if (atomic_cmpxchg(
+ &vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0)) {
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
- } else {
- spin_unlock_irqrestore(
- &vfe32_ctrl->start_ack_lock, flags);
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI1_UPDATE_ACK);
}
}
@@ -3509,12 +3357,7 @@
/* reload all write masters. (frame & line)*/
msm_camera_io_w(0x7FFF,
vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
- if (vfe32_ctrl->is_reset_blocking)
- complete(&vfe32_ctrl->reset_complete);
- else
- vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId,
- MSG_ID_RESET_ACK);
+ complete(&vfe32_ctrl->share_ctrl->reset_complete);
}
}
@@ -3523,11 +3366,11 @@
{
if (vfe32_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_RAW) {
- if (vfe32_ctrl->start_ack_pending) {
+ if (vfe32_ctrl->share_ctrl->start_ack_pending) {
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_START_ACK);
- vfe32_ctrl->start_ack_pending = FALSE;
+ vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
}
vfe32_ctrl->share_ctrl->vfe_capture_count--;
/* if last frame to be captured: */
@@ -3543,11 +3386,14 @@
VFE_MODE_OF_OPERATION_VIDEO) &&
(vfe32_ctrl->share_ctrl->vfeFrameId %
vfe32_ctrl->hfr_mode != 0)) {
- vfe32_ctrl->share_ctrl->vfeFrameId++;
+ if (vfe32_ctrl->vfe_sof_count_enable)
+ vfe32_ctrl->share_ctrl->vfeFrameId++;
CDBG("Skip the SOF notification when HFR enabled\n");
return;
}
- vfe32_ctrl->share_ctrl->vfeFrameId++;
+ if (vfe32_ctrl->vfe_sof_count_enable)
+ vfe32_ctrl->share_ctrl->vfeFrameId++;
+
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_SOF_ACK);
CDBG("camif_sof_irq, frameId = %d\n",
@@ -4373,7 +4219,6 @@
struct vfe32_ctrl_type *vfe32_ctrl, uint32_t irqstatus)
{
uint32_t status_bits = VFE_COM_STATUS & irqstatus;
-
if ((vfe32_ctrl->hfr_mode != HFR_MODE_OFF) &&
(vfe32_ctrl->share_ctrl->vfeFrameId %
vfe32_ctrl->hfr_mode != 0)) {
@@ -4544,6 +4389,11 @@
NOTIFY_VFE_IRQ,
(void *)VFE_IMASK_WHILE_STOPPING_1);
+ if (atomic_read(&axi_ctrl->share_ctrl->handle_axi_irq))
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_AXI_IRQ,
+ (void *)qcmd->vfeInterruptStatus0);
+
if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
if (qcmd->vfeInterruptStatus1 &
VFE32_IMASK_ERROR_ONLY_1) {
@@ -4553,9 +4403,6 @@
qcmd->vfeInterruptStatus1 &
VFE32_IMASK_ERROR_ONLY_1);
}
- v4l2_subdev_notify(&axi_ctrl->subdev,
- NOTIFY_AXI_IRQ,
- (void *)qcmd->vfeInterruptStatus0);
/* then process stats irq. */
if (axi_ctrl->share_ctrl->stats_comp) {
@@ -4845,7 +4692,9 @@
cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE) {
+ cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_VFE_SOF_COUNT_UPDATE &&
+ cmd->cmd_type != CMD_VFE_COUNT_SOF_ENABLE) {
if (copy_from_user(&vfecmd,
(void __user *)(cmd->value),
sizeof(vfecmd))) {
@@ -4925,6 +4774,19 @@
case CMD_GENERAL:
rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
break;
+ case CMD_VFE_COUNT_SOF_ENABLE: {
+ int enable = *((int *)cmd->value);
+ if (enable)
+ vfe32_ctrl->vfe_sof_count_enable = TRUE;
+ else
+ vfe32_ctrl->vfe_sof_count_enable = false;
+ }
+ break;
+ case CMD_VFE_SOF_COUNT_UPDATE:
+ if (!vfe32_ctrl->vfe_sof_count_enable)
+ vfe32_ctrl->share_ctrl->vfeFrameId =
+ *((uint32_t *)vfe_params->data);
+ break;
case CMD_CONFIG_PING_ADDR: {
int path = *((int *)cmd->value);
struct vfe32_output_ch *outch =
@@ -5071,16 +4933,17 @@
(struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
spin_lock_init(&vfe32_ctrl->share_ctrl->stop_flag_lock);
+ spin_lock_init(&vfe32_ctrl->share_ctrl->abort_lock);
spin_lock_init(&vfe32_ctrl->state_lock);
- spin_lock_init(&vfe32_ctrl->io_lock);
- spin_lock_init(&vfe32_ctrl->update_ack_lock);
- spin_lock_init(&vfe32_ctrl->start_ack_lock);
+ spin_lock_init(&vfe32_ctrl->share_ctrl->update_ack_lock);
+ spin_lock_init(&vfe32_ctrl->share_ctrl->start_ack_lock);
spin_lock_init(&vfe32_ctrl->stats_bufq_lock);
vfe32_ctrl->update_linear = false;
vfe32_ctrl->update_rolloff = false;
vfe32_ctrl->update_la = false;
vfe32_ctrl->update_gamma = false;
+ vfe32_ctrl->vfe_sof_count_enable = false;
vfe32_ctrl->hfr_mode = HFR_MODE_OFF;
memset(&vfe32_ctrl->stats_ctrl, 0, sizeof(struct msm_stats_bufq_ctrl));
@@ -5125,9 +4988,216 @@
vfe32_ctrl->share_ctrl->vfebase = NULL;
}
-void axi_start(struct axi_ctrl_t *axi_ctrl, uint16_t cmd_type)
+void axi_abort(struct axi_ctrl_t *axi_ctrl)
+{
+ uint8_t axi_busy_flag = true;
+ /* axi halt command. */
+ msm_camera_io_w(AXI_HALT,
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+ wmb();
+ while (axi_busy_flag) {
+ if (msm_camera_io_r(
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+ axi_busy_flag = false;
+ }
+ /* Ensure the write order while writing
+ * to the command register using the barrier */
+ msm_camera_io_w_mb(AXI_HALT_CLEAR,
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+
+ /* after axi halt, then ok to apply global reset.
+ * enable reset_ack and async timer interrupt only while
+ * stopping the pipeline.*/
+ msm_camera_io_w(0xf0000000,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Ensure the write order while writing
+ * to the command register using the barrier */
+ msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+ axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+int axi_config_buffers(struct axi_ctrl_t *axi_ctrl,
+ struct msm_camera_vfe_params_t vfe_params)
+{
+ uint16_t vfe_mode = axi_ctrl->share_ctrl->current_mode
+ & ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1);
+ int rc = 0;
+ switch (vfe_params.cmd_type) {
+ case AXI_CMD_PREVIEW:
+ if (vfe_mode) {
+ if ((axi_ctrl->share_ctrl->current_mode &
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+ (axi_ctrl->share_ctrl->current_mode &
+ VFE_OUTPUTS_PREVIEW))
+ /* Configure primary channel */
+ rc = configure_pingpong_buffers(
+ VFE_MSG_START,
+ VFE_MSG_OUTPUT_PRIMARY,
+ axi_ctrl);
+ else
+ /* Configure secondary channel */
+ rc = configure_pingpong_buffers(
+ VFE_MSG_START,
+ VFE_MSG_OUTPUT_SECONDARY,
+ axi_ctrl);
+ }
+ if (axi_ctrl->share_ctrl->current_mode &
+ VFE_OUTPUTS_RDI0)
+ rc = configure_pingpong_buffers(
+ VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY1,
+ axi_ctrl);
+ if (axi_ctrl->share_ctrl->current_mode &
+ VFE_OUTPUTS_RDI1)
+ rc = configure_pingpong_buffers(
+ VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY2,
+ axi_ctrl);
+
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers for preview",
+ __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ break;
+ case AXI_CMD_RAW_CAPTURE:
+ rc = configure_pingpong_buffers(
+ VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
+ axi_ctrl);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers for snapshot",
+ __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ break;
+ case AXI_CMD_ZSL:
+ rc = configure_pingpong_buffers(VFE_MSG_START,
+ VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+ if (rc < 0)
+ goto config_done;
+ rc = configure_pingpong_buffers(VFE_MSG_START,
+ VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
+ if (rc < 0)
+ goto config_done;
+ break;
+ case AXI_CMD_RECORD:
+ if (axi_ctrl->share_ctrl->current_mode &
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ axi_ctrl->share_ctrl->outpath.out1.inst_handle =
+ vfe_params.inst_handle;
+ rc = configure_pingpong_buffers(
+ VFE_MSG_START_RECORDING,
+ VFE_MSG_OUTPUT_SECONDARY,
+ axi_ctrl);
+ } else if (axi_ctrl->share_ctrl->current_mode &
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ axi_ctrl->share_ctrl->outpath.out0.inst_handle =
+ vfe_params.inst_handle;
+ rc = configure_pingpong_buffers(
+ VFE_MSG_START_RECORDING,
+ VFE_MSG_OUTPUT_PRIMARY,
+ axi_ctrl);
+ }
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers for video",
+ __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ break;
+ case AXI_CMD_LIVESHOT:
+ axi_ctrl->share_ctrl->outpath.out0.inst_handle =
+ vfe_params.inst_handle;
+ rc = configure_pingpong_buffers(VFE_MSG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers for primary output",
+ __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ break;
+ case AXI_CMD_CAPTURE:
+ if (axi_ctrl->share_ctrl->current_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ axi_ctrl->share_ctrl->current_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG) {
+
+ /* Configure primary channel for JPEG */
+ rc = configure_pingpong_buffers(
+ VFE_MSG_JPEG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY,
+ axi_ctrl);
+ } else {
+ /* Configure primary channel */
+ rc = configure_pingpong_buffers(
+ VFE_MSG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY,
+ axi_ctrl);
+ }
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers for primary output",
+ __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ /* Configure secondary channel */
+ rc = configure_pingpong_buffers(
+ VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
+ axi_ctrl);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers for secondary output",
+ __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+
+ }
+config_done:
+ return rc;
+}
+
+void axi_start(struct msm_cam_media_controller *pmctl,
+ struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
{
uint32_t irq_comp_mask = 0, irq_mask = 0;
+ int rc = 0;
+ rc = axi_config_buffers(axi_ctrl, vfe_params);
+ if (rc < 0)
+ return;
+
+ switch (vfe_params.cmd_type) {
+ case AXI_CMD_PREVIEW:
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ break;
+ case AXI_CMD_CAPTURE:
+ case AXI_CMD_RAW_CAPTURE:
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+ break;
+ case AXI_CMD_RECORD:
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+ return;
+ case AXI_CMD_ZSL:
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
+ break;
+ case AXI_CMD_LIVESHOT:
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_LIVESHOT);
+ return;
+ default:
+ return;
+ }
irq_comp_mask =
msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
@@ -5179,7 +5249,7 @@
msm_camera_io_w(irq_comp_mask,
axi_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
- switch (cmd_type) {
+ switch (vfe_params.cmd_type) {
case AXI_CMD_PREVIEW: {
uint16_t operation_mode =
(axi_ctrl->share_ctrl->operation_mode &
@@ -5286,37 +5356,160 @@
msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
outpath.out3.ch0]);
+ atomic_set(&axi_ctrl->share_ctrl->handle_axi_irq, 1);
}
-void axi_stop(struct axi_ctrl_t *axi_ctrl, uint16_t cmd_type)
+void axi_stop(struct msm_cam_media_controller *pmctl,
+ struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
{
- uint8_t axiBusyFlag = true;
- /* axi halt command. */
- msm_camera_io_w(AXI_HALT,
- axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
- wmb();
- while (axiBusyFlag) {
- if (msm_camera_io_r(
- axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
- axiBusyFlag = false;
+ uint32_t reg_update = 0;
+ unsigned long flags;
+ uint32_t operation_mode =
+ axi_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+
+ switch (vfe_params.cmd_type) {
+ case AXI_CMD_PREVIEW:
+ case AXI_CMD_CAPTURE:
+ case AXI_CMD_RAW_CAPTURE:
+ case AXI_CMD_ZSL:
+ break;
+ case AXI_CMD_RECORD:
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ return;
+ case AXI_CMD_LIVESHOT:
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+ return;
+ default:
+ return;
}
- /* Ensure the write order while writing
- to the command register using the barrier */
- msm_camera_io_w_mb(AXI_HALT_CLEAR,
- axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
- /* after axi halt, then ok to apply global reset. */
- /* enable reset_ack and async timer interrupt only while
- stopping the pipeline.*/
- msm_camera_io_w(0xf0000000,
- axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
- msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
- axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ if (!axi_ctrl->share_ctrl->skip_abort) {
+ atomic_set(&axi_ctrl->share_ctrl->handle_axi_irq, 0);
+ axi_disable_irq(axi_ctrl);
+ }
- /* Ensure the write order while writing
- to the command register using the barrier */
- msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
- axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+ axi_ctrl->share_ctrl->stop_ack_pending = TRUE;
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+ switch (vfe_params.cmd_type) {
+ case AXI_CMD_PREVIEW: {
+ switch (operation_mode) {
+ case VFE_OUTPUTS_PREVIEW:
+ case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch2]);
+ }
+ break;
+ default:
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch2]);
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch2]);
+ }
+
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch2]);
+ }
+ break;
+ }
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
+ outpath.out2.ch0]);
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+ msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
+ outpath.out3.ch0]);
+
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+ reg_update |= 0x2;
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+ reg_update |= 0x4;
+
+ if (operation_mode)
+ reg_update |= 0x1;
+ msm_camera_io_w_mb(reg_update,
+ axi_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ if (!axi_ctrl->share_ctrl->skip_abort)
+ axi_abort(axi_ctrl);
+
}
static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
@@ -5324,7 +5517,10 @@
struct msm_vfe_cfg_cmd cfgcmd;
struct msm_isp_cmd vfecmd;
struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ struct msm_cam_media_controller *pmctl =
+ (struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
int rc = 0, vfe_cmd_type = 0, rdi_mode = 0;
+ unsigned long flags;
if (!axi_ctrl->share_ctrl->vfebase) {
pr_err("%s: base address unmapped\n", __func__);
@@ -5520,7 +5716,12 @@
}
axi_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- axi_start(axi_ctrl, vfe_params.cmd_type);
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock, flags);
+ axi_ctrl->share_ctrl->skip_abort =
+ vfe_params.skip_abort;
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->abort_lock,
+ flags);
+ axi_start(pmctl, axi_ctrl, vfe_params);
}
break;
case CMD_AXI_STOP: {
@@ -5532,9 +5733,17 @@
}
axi_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- axi_stop(axi_ctrl, vfe_params.cmd_type);
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock, flags);
+ axi_ctrl->share_ctrl->skip_abort =
+ vfe_params.skip_abort;
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->abort_lock,
+ flags);
+ axi_stop(pmctl, axi_ctrl, vfe_params);
}
break;
+ case CMD_AXI_RESET:
+ axi_reset(axi_ctrl);
+ break;
default:
pr_err("%s Unsupported AXI configuration %x ", __func__,
cfgcmd.cmd_type);
@@ -5547,6 +5756,7 @@
{
struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
uint32_t irqstatus = (uint32_t) arg;
+ unsigned long flags;
if (!axi_ctrl->share_ctrl->vfebase) {
pr_err("%s: base address unmapped\n", __func__);
@@ -5595,6 +5805,17 @@
CAMIF_COMMAND_STOP_IMMEDIATELY,
axi_ctrl->share_ctrl->vfebase +
VFE_CAMIF_COMMAND);
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock,
+ flags);
+ if (axi_ctrl->share_ctrl->skip_abort) {
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->
+ abort_lock, flags);
+ atomic_set(&axi_ctrl->share_ctrl->
+ handle_axi_irq, 0);
+ axi_disable_irq(axi_ctrl);
+ } else
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->
+ abort_lock, flags);
vfe32_send_isp_msg(&axi_ctrl->subdev,
axi_ctrl->share_ctrl->vfeFrameId,
MSG_ID_SNAPSHOT_DONE);
@@ -5673,7 +5894,9 @@
rc = 0;
break;
default:
- pr_err("%s: command not found\n", __func__);
+ pr_err("%s: command %d not found\n", __func__,
+ _IOC_NR(cmd));
+ break;
}
return rc;
}
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.h b/drivers/media/video/msm/vfe/msm_vfe32.h
index 170bfb7..f4b7edb 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.h
+++ b/drivers/media/video/msm/vfe/msm_vfe32.h
@@ -941,9 +941,11 @@
uint32_t register_total;
atomic_t vstate;
+ atomic_t handle_axi_irq;
uint32_t vfeFrameId;
uint32_t stats_comp;
spinlock_t stop_flag_lock;
+ spinlock_t abort_lock;
int8_t stop_ack_pending;
enum vfe_output_state liveshot_state;
uint32_t vfe_capture_count;
@@ -956,8 +958,20 @@
uint32_t skip_abort;
spinlock_t sd_notify_lock;
+ struct completion reset_complete;
+
+ spinlock_t update_ack_lock;
+ spinlock_t start_ack_lock;
+
struct axi_ctrl_t *axi_ctrl;
struct vfe32_ctrl_type *vfe32_ctrl;
+ int8_t start_ack_pending;
+ int8_t update_ack_pending;
+ enum vfe_output_state recording_state;
+
+ atomic_t rdi0_update_ack_pending;
+ atomic_t rdi1_update_ack_pending;
+ atomic_t rdi2_update_ack_pending;
};
struct axi_ctrl_t {
@@ -978,21 +992,12 @@
};
struct vfe32_ctrl_type {
- uint32_t vfeImaskCompositePacked;
-
- spinlock_t update_ack_lock;
- spinlock_t start_ack_lock;
spinlock_t state_lock;
- spinlock_t io_lock;
spinlock_t stats_bufq_lock;
uint32_t extlen;
void *extdata;
- int8_t start_ack_pending;
- int8_t update_ack_pending;
- bool is_reset_blocking;
- struct completion reset_complete;
- enum vfe_output_state recording_state;
+ int8_t vfe_sof_count_enable;
int8_t update_linear;
int8_t update_rolloff;
int8_t update_la;
@@ -1004,12 +1009,6 @@
uint32_t sync_timer_state;
uint32_t sync_timer_number;
- uint32_t output1Pattern;
- uint32_t output1Period;
- uint32_t output2Pattern;
- uint32_t output2Period;
- uint32_t vfeFrameSkipCount;
- uint32_t vfeFrameSkipPeriod;
struct msm_ver_num_info ver_num;
struct vfe_stats_control afbfStatsControl;
struct vfe_stats_control awbStatsControl;
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
new file mode 100644
index 0000000..5a1d488
--- /dev/null
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -0,0 +1,3699 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+
+#include "msm.h"
+#include "msm_vfe40.h"
+
+struct vfe40_isr_queue_cmd {
+ struct list_head list;
+ uint32_t vfeInterruptStatus0;
+ uint32_t vfeInterruptStatus1;
+};
+
+static const char * const vfe40_general_cmd[] = {
+ "DUMMY_0", /* 0 */
+ "SET_CLK",
+ "RESET",
+ "START",
+ "TEST_GEN_START",
+ "OPERATION_CFG", /* 5 */
+ "AXI_OUT_CFG",
+ "CAMIF_CFG",
+ "AXI_INPUT_CFG",
+ "BLACK_LEVEL_CFG",
+ "ROLL_OFF_CFG", /* 10 */
+ "DEMUX_CFG",
+ "FOV_CFG",
+ "MAIN_SCALER_CFG",
+ "WB_CFG",
+ "COLOR_COR_CFG", /* 15 */
+ "RGB_G_CFG",
+ "LA_CFG",
+ "CHROMA_EN_CFG",
+ "CHROMA_SUP_CFG",
+ "MCE_CFG", /* 20 */
+ "SK_ENHAN_CFG",
+ "ASF_CFG",
+ "S2Y_CFG",
+ "S2CbCr_CFG",
+ "CHROMA_SUBS_CFG", /* 25 */
+ "OUT_CLAMP_CFG",
+ "FRAME_SKIP_CFG",
+ "DUMMY_1",
+ "DUMMY_2",
+ "DUMMY_3", /* 30 */
+ "UPDATE",
+ "BL_LVL_UPDATE",
+ "DEMUX_UPDATE",
+ "FOV_UPDATE",
+ "MAIN_SCALER_UPDATE", /* 35 */
+ "WB_UPDATE",
+ "COLOR_COR_UPDATE",
+ "RGB_G_UPDATE",
+ "LA_UPDATE",
+ "CHROMA_EN_UPDATE", /* 40 */
+ "CHROMA_SUP_UPDATE",
+ "MCE_UPDATE",
+ "SK_ENHAN_UPDATE",
+ "S2CbCr_UPDATE",
+ "S2Y_UPDATE", /* 45 */
+ "ASF_UPDATE",
+ "FRAME_SKIP_UPDATE",
+ "CAMIF_FRAME_UPDATE",
+ "STATS_AF_UPDATE",
+ "STATS_AE_UPDATE", /* 50 */
+ "STATS_AWB_UPDATE",
+ "STATS_RS_UPDATE",
+ "STATS_CS_UPDATE",
+ "STATS_SKIN_UPDATE",
+ "STATS_IHIST_UPDATE", /* 55 */
+ "DUMMY_4",
+ "EPOCH1_ACK",
+ "EPOCH2_ACK",
+ "START_RECORDING",
+ "STOP_RECORDING", /* 60 */
+ "DUMMY_5",
+ "DUMMY_6",
+ "CAPTURE",
+ "DUMMY_7",
+ "STOP", /* 65 */
+ "GET_HW_VERSION",
+ "GET_FRAME_SKIP_COUNTS",
+ "OUTPUT1_BUFFER_ENQ",
+ "OUTPUT2_BUFFER_ENQ",
+ "OUTPUT3_BUFFER_ENQ", /* 70 */
+ "JPEG_OUT_BUF_ENQ",
+ "RAW_OUT_BUF_ENQ",
+ "RAW_IN_BUF_ENQ",
+ "STATS_AF_ENQ",
+ "STATS_AE_ENQ", /* 75 */
+ "STATS_AWB_ENQ",
+ "STATS_RS_ENQ",
+ "STATS_CS_ENQ",
+ "STATS_SKIN_ENQ",
+ "STATS_IHIST_ENQ", /* 80 */
+ "DUMMY_8",
+ "JPEG_ENC_CFG",
+ "DUMMY_9",
+ "STATS_AF_START",
+ "STATS_AF_STOP", /* 85 */
+ "STATS_AE_START",
+ "STATS_AE_STOP",
+ "STATS_AWB_START",
+ "STATS_AWB_STOP",
+ "STATS_RS_START", /* 90 */
+ "STATS_RS_STOP",
+ "STATS_CS_START",
+ "STATS_CS_STOP",
+ "STATS_SKIN_START",
+ "STATS_SKIN_STOP", /* 95 */
+ "STATS_IHIST_START",
+ "STATS_IHIST_STOP",
+ "DUMMY_10",
+ "SYNC_TIMER_SETTING",
+ "ASYNC_TIMER_SETTING", /* 100 */
+ "LIVESHOT",
+ "LA_SETUP",
+ "LINEARIZATION_CFG",
+ "DEMOSAICV3",
+ "DEMOSAICV3_ABCC_CFG", /* 105 */
+ "DEMOSAICV3_DBCC_CFG",
+ "DEMOSAICV3_DBPC_CFG",
+ "DEMOSAICV3_ABF_CFG",
+ "DEMOSAICV3_ABCC_UPDATE",
+ "DEMOSAICV3_DBCC_UPDATE", /* 110 */
+ "DEMOSAICV3_DBPC_UPDATE",
+ "XBAR_CFG",
+ "EZTUNE_CFG",
+ "V40_ZSL",
+ "LINEARIZATION_UPDATE", /*115*/
+ "DEMOSAICV3_ABF_UPDATE",
+ "CLF_CFG",
+ "CLF_LUMA_UPDATE",
+ "CLF_CHROMA_UPDATE",
+ "PCA_ROLL_OFF_CFG", /*120*/
+ "PCA_ROLL_OFF_UPDATE",
+ "GET_REG_DUMP",
+ "GET_LINEARIZATON_TABLE",
+ "GET_MESH_ROLLOFF_TABLE",
+ "GET_PCA_ROLLOFF_TABLE", /*125*/
+ "GET_RGB_G_TABLE",
+ "GET_LA_TABLE",
+ "DEMOSAICV3_UPDATE",
+ "ACTIVE_REGION_CONFIG",
+ "COLOR_PROCESSING_CONFIG", /*130*/
+ "STATS_WB_AEC_CONFIG",
+ "STATS_WB_AEC_UPDATE",
+ "Y_GAMMA_CONFIG",
+ "SCALE_OUTPUT1_CONFIG",
+ "SCALE_OUTPUT2_CONFIG", /*135*/
+ "CAPTURE_RAW",
+ "STOP_LIVESHOT",
+ "RECONFIG_VFE",
+ "STATS_REQBUF_CFG",
+ "STATS_ENQUEUEBUF_CFG",/*140*/
+ "STATS_FLUSH_BUFQ_CFG",
+ "FOV_ENC_CFG",
+ "FOV_VIEW_CFG",
+ "FOV_ENC_UPDATE",
+ "FOV_VIEW_UPDATE",/*145*/
+ "SCALER_ENC_CFG",
+ "SCALER_VIEW_CFG",
+ "SCALER_ENC_UPDATE",
+ "SCALER_VIEW_UPDATE",
+ "COLORXFORM_ENC_CFG",/*150*/
+ "COLORXFORM_VIEW_CFG",
+ "COLORXFORM_ENC_UPDATE",
+ "COLORXFORM_VIEW_UPDATE",
+};
+
+static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+
+ atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+
+ /* for reset hw modules, and send msg when reset_irq comes.*/
+ spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+ vfe40_ctrl->share_ctrl->stop_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+
+ /* disable all interrupts. */
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQ0,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQ1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+
+ /* in either continuous or snapshot mode, stop command can be issued
+ * at any time. stop camif immediately. */
+ msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+}
+
+void vfe40_subdev_notify(int id, int path, int image_mode,
+ struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl)
+{
+ struct msm_vfe_resp rp;
+ struct msm_frame_info frame_info;
+ unsigned long flags = 0;
+ spin_lock_irqsave(&share_ctrl->sd_notify_lock, flags);
+ CDBG("%s: msgId = %d\n", __func__, id);
+ memset(&rp, 0, sizeof(struct msm_vfe_resp));
+ rp.evt_msg.type = MSM_CAMERA_MSG;
+ frame_info.image_mode = image_mode;
+ frame_info.path = path;
+ rp.evt_msg.data = &frame_info;
+ rp.type = id;
+ v4l2_subdev_notify(sd, NOTIFY_VFE_BUF_EVT, &rp);
+ spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags);
+}
+
+static void vfe40_reset_internal_variables(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ vfe40_ctrl->vfeImaskCompositePacked = 0;
+ /* state control variables */
+ vfe40_ctrl->start_ack_pending = FALSE;
+ atomic_set(&vfe40_ctrl->share_ctrl->irq_cnt, 0);
+
+ spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+ vfe40_ctrl->share_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+
+ vfe40_ctrl->reset_ack_pending = FALSE;
+
+ spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
+ vfe40_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags);
+
+ vfe40_ctrl->recording_state = VFE_STATE_IDLE;
+ vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+ atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+
+ /* 0 for continuous mode, 1 for snapshot mode */
+ vfe40_ctrl->share_ctrl->operation_mode = 0;
+ vfe40_ctrl->share_ctrl->outpath.output_mode = 0;
+ vfe40_ctrl->share_ctrl->vfe_capture_count = 0;
+
+ /* this is unsigned 32 bit integer. */
+ vfe40_ctrl->share_ctrl->vfeFrameId = 0;
+ /* Stats control variables. */
+ memset(&(vfe40_ctrl->afStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->awbStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->aecStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->ihistStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->rsStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->csStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ vfe40_ctrl->frame_skip_cnt = 31;
+ vfe40_ctrl->frame_skip_pattern = 0xffffffff;
+ vfe40_ctrl->snapshot_frame_cnt = 0;
+}
+
+static void vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ vfe40_reset_internal_variables(vfe40_ctrl);
+ /* disable all interrupts. vfeImaskLocal is also reset to 0
+ * to begin with. */
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+
+ /* enable reset_ack interrupt. */
+ msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
+ * is done, hardware interrupt will be generated. VFE ist processes
+ * the interrupt to complete the function call. Note that the reset
+ * function is synchronous. */
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(VFE_RESET_UPON_RESET_CMD,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+ msm_camera_io_w(0xAAAAAAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_0);
+ msm_camera_io_w(0xAAAAAAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_1);
+ msm_camera_io_w(0xAAAAAAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_2);
+ msm_camera_io_w(0xAAAAAAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_3);
+ msm_camera_io_w(0xAAAAAAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_4);
+ msm_camera_io_w(0xAAAAAAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_5);
+ msm_camera_io_w(0xAAAAAAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_6);
+ msm_camera_io_w(0x0002AAAA,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_7);
+}
+
+static int vfe40_operation_config(uint32_t *cmd,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t *p = cmd;
+
+ vfe40_ctrl->share_ctrl->operation_mode = *p;
+ vfe40_ctrl->share_ctrl->stats_comp = *(++p);
+ vfe40_ctrl->hfr_mode = *(++p);
+
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CFG);
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+ if (msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ V40_GET_HW_VERSION_OFF) ==
+ VFE40_HW_NUMBER) {
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
+ } else {
+ ++p;
+ ++p;
+ }
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REALIGN_BUF);
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CHROMA_UP);
+ msm_camera_io_w(*(++p),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+ return 0;
+}
+
+static unsigned long vfe40_stats_dqbuf(struct vfe40_ctrl_type *vfe40_ctrl,
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+ rc = vfe40_ctrl->stats_ops.dqbuf(
+ vfe40_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ return buf->paddr;
+}
+
+static unsigned long vfe40_stats_flush_enqueue(
+ struct vfe40_ctrl_type *vfe40_ctrl,
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ int rc = 0;
+ int i;
+
+ /*
+ * Passing NULL for ion client as the buffers are already
+ * mapped at this stage, client is not required, flush all
+ * the buffers, and buffers move to PREPARE state
+ */
+
+ rc = vfe40_ctrl->stats_ops.bufq_flush(
+ vfe40_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ /* Queue all the buffers back to QUEUED state */
+ bufq = vfe40_ctrl->stats_ctrl.bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ rc = vfe40_ctrl->stats_ops.enqueue_buf(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ &(stats_buf->info), NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return rc;
+ }
+ }
+ return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl,
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_aec_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_af_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ return -EINVAL;
+ }
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AF_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+ return 0;
+}
+
+static int vfe_stats_ihist_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+
+ return 0;
+}
+
+static int vfe_stats_rs_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_RS_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_RS_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_cs_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_CS_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_CS_WR_PONG_ADDR);
+ return 0;
+}
+
+static void vfe40_start_common(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t irq_mask = 0x1E000011;
+ vfe40_ctrl->start_ack_pending = TRUE;
+ CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
+ vfe40_ctrl->share_ctrl->operation_mode,
+ vfe40_ctrl->share_ctrl->outpath.output_mode);
+
+ msm_camera_io_w(irq_mask,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+ msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase,
+ vfe40_ctrl->share_ctrl->register_total*4);
+
+ atomic_set(&vfe40_ctrl->share_ctrl->vstate, 1);
+}
+
+static int vfe40_start_recording(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+ vfe40_ctrl->recording_state = VFE_STATE_START_REQUESTED;
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ return 0;
+}
+
+static int vfe40_stop_recording(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ vfe40_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ return 0;
+}
+
+static void vfe40_start_liveshot(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ /* Hardcode 1 live snapshot for now. */
+ vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = 1;
+ vfe40_ctrl->share_ctrl->vfe_capture_count =
+ vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt;
+
+ vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
+ msm_camera_io_w_mb(1, vfe40_ctrl->
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static int vfe40_zsl(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t irq_comp_mask = 0;
+ /* capture command is valid for both idle and active state. */
+ irq_comp_mask =
+ msm_camera_io_r(vfe40_ctrl->
+ share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ CDBG("%s:op mode %d O/P Mode %d\n", __func__,
+ vfe40_ctrl->share_ctrl->operation_mode,
+ vfe40_ctrl->share_ctrl->outpath.output_mode);
+
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (
+ (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1)));
+ } else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ irq_comp_mask |= (
+ (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1)) |
+ (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch2)));
+ }
+
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= ((0x1 << (vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1 + 8)));
+ } else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ irq_comp_mask |= (
+ (0x1 << (vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1 + 8)) |
+ (0x1 << (vfe40_ctrl->
+ share_ctrl->outpath.out1.ch2 + 8)));
+ }
+
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch2]);
+ }
+
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ } else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch2]);
+ }
+
+ msm_camera_io_w(irq_comp_mask,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ vfe40_start_common(vfe40_ctrl);
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
+
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188);
+ return 0;
+}
+static int vfe40_capture_raw(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe40_ctrl_type *vfe40_ctrl,
+ uint32_t num_frames_capture)
+{
+ uint32_t irq_comp_mask = 0;
+
+ vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = num_frames_capture;
+ vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
+
+ irq_comp_mask =
+ msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |=
+ (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0));
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ }
+
+ msm_camera_io_w(irq_comp_mask,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+ vfe40_start_common(vfe40_ctrl);
+ return 0;
+}
+
+static int vfe40_capture(
+ struct msm_cam_media_controller *pmctl,
+ uint32_t num_frames_capture,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t irq_comp_mask = 0;
+
+ /* capture command is valid for both idle and active state. */
+ vfe40_ctrl->share_ctrl->outpath.out1.capture_cnt = num_frames_capture;
+ if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG) {
+ vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt =
+ num_frames_capture;
+ }
+
+ vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
+ irq_comp_mask = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN) {
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (0x1 << vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1);
+ }
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |=
+ (0x1 << (vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1 + 8));
+ }
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ }
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ }
+ }
+
+ vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
+
+ msm_camera_io_w(irq_comp_mask,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+
+ vfe40_start_common(vfe40_ctrl);
+ /* for debug */
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188);
+ return 0;
+}
+
+static int vfe40_start(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t irq_comp_mask = 0;
+ irq_comp_mask =
+ msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_COMP_MASK);
+
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (
+ 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1);
+ } else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ irq_comp_mask |= (
+ 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1 |
+ 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch2);
+ }
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= (
+ 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8));
+ } else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ irq_comp_mask |= (
+ 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
+ 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch2 + 8));
+ }
+ msm_camera_io_w(irq_comp_mask,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ /*
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);*/
+ vfe40_start_common(vfe40_ctrl);
+ return 0;
+}
+
+static void vfe40_update(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t value = 0;
+ if (vfe40_ctrl->update_linear) {
+ if (!msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_LINEARIZATION_OFF1))
+ msm_camera_io_w(1,
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_LINEARIZATION_OFF1);
+ else
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_LINEARIZATION_OFF1);
+ vfe40_ctrl->update_linear = false;
+ }
+
+ if (vfe40_ctrl->update_la) {
+ if (!msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF))
+ msm_camera_io_w(1,
+ vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF);
+ else
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF);
+ vfe40_ctrl->update_la = false;
+ }
+
+ if (vfe40_ctrl->update_gamma) {
+ value = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+ value ^= V40_GAMMA_LUT_BANK_SEL_MASK;
+ msm_camera_io_w(value,
+ vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+ vfe40_ctrl->update_gamma = false;
+ }
+
+ spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
+ vfe40_ctrl->update_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags);
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ return;
+}
+
+static void vfe40_sync_timer_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t value = 0;
+ vfe40_ctrl->sync_timer_state = 0;
+ if (vfe40_ctrl->sync_timer_number == 0)
+ value = 0x10000;
+ else if (vfe40_ctrl->sync_timer_number == 1)
+ value = 0x20000;
+ else if (vfe40_ctrl->sync_timer_number == 2)
+ value = 0x40000;
+
+ /* Timer Stop */
+ msm_camera_io_w(value,
+ vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF);
+}
+
+static void vfe40_sync_timer_start(
+ const uint32_t *tbl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ /* set bit 8 for auto increment. */
+ uint32_t value = 1;
+ uint32_t val;
+
+ vfe40_ctrl->sync_timer_state = *tbl++;
+ vfe40_ctrl->sync_timer_repeat_count = *tbl++;
+ vfe40_ctrl->sync_timer_number = *tbl++;
+ CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n",
+ __func__, vfe40_ctrl->sync_timer_state,
+ vfe40_ctrl->sync_timer_repeat_count,
+ vfe40_ctrl->sync_timer_number);
+
+ if (vfe40_ctrl->sync_timer_state) { /* Start Timer */
+ value = value << vfe40_ctrl->sync_timer_number;
+ } else { /* Stop Timer */
+ CDBG("Failed to Start timer\n");
+ return;
+ }
+
+ /* Timer Start */
+ msm_camera_io_w(value,
+ vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF);
+ /* Sync Timer Line Start */
+ value = *tbl++;
+ msm_camera_io_w(value,
+ vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF +
+ 4 + ((vfe40_ctrl->sync_timer_number) * 12));
+ /* Sync Timer Pixel Start */
+ value = *tbl++;
+ msm_camera_io_w(value,
+ vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF +
+ 8 + ((vfe40_ctrl->sync_timer_number) * 12));
+ /* Sync Timer Pixel Duration */
+ value = *tbl++;
+ val = vfe40_ctrl->share_ctrl->vfe_clk_rate / 10000;
+ val = 10000000 / val;
+ val = value * 10000 / val;
+ CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
+ msm_camera_io_w(val,
+ vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF +
+ 12 + ((vfe40_ctrl->sync_timer_number) * 12));
+ /* Timer0 Active High/LOW */
+ value = *tbl++;
+ msm_camera_io_w(value,
+ vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_POLARITY_OFF);
+ /* Selects sync timer 0 output to drive onto timer1 port */
+ value = 0;
+ msm_camera_io_w(value,
+ vfe40_ctrl->share_ctrl->vfebase + V40_TIMER_SELECT_OFF);
+}
+
+static void vfe40_program_dmi_cfg(
+ enum VFE40_DMI_RAM_SEL bankSel,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ /* set bit 8 for auto increment. */
+ uint32_t value = VFE_DMI_CFG_DEFAULT;
+ value += (uint32_t)bankSel;
+ CDBG("%s: banksel = %d\n", __func__, bankSel);
+
+ msm_camera_io_w(value, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_CFG);
+ /* by default, always starts with offset 0.*/
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
+}
+static void vfe40_write_gamma_cfg(
+ enum VFE40_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ int i;
+ uint32_t value, value1, value2;
+ vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+ for (i = 0 ; i < (VFE40_GAMMA_NUM_ENTRIES/2) ; i++) {
+ value = *tbl++;
+ value1 = value & 0x0000FFFF;
+ value2 = (value & 0xFFFF0000)>>16;
+ msm_camera_io_w((value1),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+ msm_camera_io_w((value2),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+static void vfe40_read_gamma_cfg(
+ enum VFE40_DMI_RAM_SEL channel_sel,
+ uint32_t *tbl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ int i;
+ vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+ CDBG("%s: Gamma table channel: %d\n", __func__, channel_sel);
+ for (i = 0 ; i < VFE40_GAMMA_NUM_ENTRIES ; i++) {
+ *tbl = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *tbl);
+ tbl++;
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+static void vfe40_write_la_cfg(
+ enum VFE40_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t i;
+ uint32_t value, value1, value2;
+
+ vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+ for (i = 0 ; i < (VFE40_LA_TABLE_LENGTH/2) ; i++) {
+ value = *tbl++;
+ value1 = value & 0x0000FFFF;
+ value2 = (value & 0xFFFF0000)>>16;
+ msm_camera_io_w((value1),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+ msm_camera_io_w((value2),
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+struct vfe40_output_ch *vfe40_get_ch(
+ int path, struct vfe_share_ctrl_t *share_ctrl)
+{
+ struct vfe40_output_ch *ch = NULL;
+
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ ch = &share_ctrl->outpath.out0;
+ else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ ch = &share_ctrl->outpath.out1;
+ else
+ pr_err("%s: Invalid path %d\n", __func__,
+ path);
+
+ BUG_ON(ch == NULL);
+ return ch;
+}
+
+static int vfe40_configure_pingpong_buffers(
+ int id, int path, struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ struct vfe40_output_ch *outch = NULL;
+ int rc = 0;
+ uint32_t image_mode = 0;
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ image_mode = vfe40_ctrl->share_ctrl->outpath.out0.image_mode;
+ else
+ image_mode = vfe40_ctrl->share_ctrl->outpath.out1.image_mode;
+
+ vfe40_subdev_notify(id, path, image_mode,
+ &vfe40_ctrl->subdev, vfe40_ctrl->share_ctrl);
+ outch = vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+ if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
+ /* Configure Preview Ping Pong */
+ CDBG("%s Configure ping/pong address for %d",
+ __func__, path);
+ vfe40_put_ch_ping_addr(
+ vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+ outch->ping.ch_paddr[0]);
+ vfe40_put_ch_pong_addr(
+ vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+ outch->pong.ch_paddr[0]);
+
+ if (vfe40_ctrl->share_ctrl->operation_mode !=
+ VFE_OUTPUTS_RAW) {
+ vfe40_put_ch_ping_addr(
+ vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+ outch->ping.ch_paddr[1]);
+ vfe40_put_ch_pong_addr(
+ vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+ outch->pong.ch_paddr[1]);
+ }
+
+ if (outch->ping.num_planes > 2)
+ vfe40_put_ch_ping_addr(
+ vfe40_ctrl->share_ctrl->vfebase, outch->ch2,
+ outch->ping.ch_paddr[2]);
+ if (outch->pong.num_planes > 2)
+ vfe40_put_ch_pong_addr(
+ vfe40_ctrl->share_ctrl->vfebase, outch->ch2,
+ outch->pong.ch_paddr[2]);
+
+ /* avoid stale info */
+ memset(&outch->ping, 0, sizeof(struct msm_free_buf));
+ memset(&outch->pong, 0, sizeof(struct msm_free_buf));
+ } else {
+ pr_err("%s ping/pong addr is null!!", __func__);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static void vfe40_write_linear_cfg(
+ enum VFE40_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl, struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t i;
+
+ vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+ /* for loop for configuring LUT. */
+ for (i = 0 ; i < VFE40_LINEARIZATON_TABLE_LENGTH ; i++) {
+ msm_camera_io_w(*tbl,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+ tbl++;
+ }
+ CDBG("done writing to linearization table\n");
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+void vfe40_send_isp_msg(
+ struct v4l2_subdev *sd,
+ uint32_t vfeFrameId,
+ uint32_t isp_msg_id)
+{
+ struct isp_msg_event isp_msg_evt;
+
+ isp_msg_evt.msg_id = isp_msg_id;
+ isp_msg_evt.sof_count = vfeFrameId;
+ v4l2_subdev_notify(sd,
+ NOTIFY_ISP_MSG_EVT,
+ (void *)&isp_msg_evt);
+}
+
+static int vfe40_proc_general(
+ struct msm_cam_media_controller *pmctl,
+ struct msm_isp_cmd *cmd,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ int i , rc = 0;
+ uint32_t old_val = 0 , new_val = 0;
+ uint32_t *cmdp = NULL;
+ uint32_t *cmdp_local = NULL;
+ uint32_t snapshot_cnt = 0;
+ uint32_t temp1 = 0, temp2 = 0;
+
+ CDBG("vfe40_proc_general: cmdID = %s, length = %d\n",
+ vfe40_general_cmd[cmd->id], cmd->length);
+ switch (cmd->id) {
+ case VFE_CMD_RESET:
+ CDBG("vfe40_proc_general: cmdID = %s\n",
+ vfe40_general_cmd[cmd->id]);
+ vfe40_reset(vfe40_ctrl);
+ break;
+ case VFE_CMD_START:
+ CDBG("vfe40_proc_general: cmdID = %s\n",
+ vfe40_general_cmd[cmd->id]);
+ if ((vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+ (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW))
+ /* Configure primary channel */
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_START, VFE_MSG_OUTPUT_PRIMARY,
+ vfe40_ctrl);
+ else
+ /* Configure secondary channel */
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_START, VFE_MSG_OUTPUT_SECONDARY,
+ vfe40_ctrl);
+ if (rc < 0) {
+ pr_err(
+ "%s error configuring pingpong buffers for preview",
+ __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+
+ rc = vfe40_start(pmctl, vfe40_ctrl);
+ break;
+ case VFE_CMD_UPDATE:
+ vfe40_update(vfe40_ctrl);
+ break;
+ case VFE_CMD_CAPTURE_RAW:
+ CDBG("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
+ if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
+ vfe40_ctrl);
+ if (rc < 0) {
+ pr_err(
+ "%s error configuring pingpong buffers for snapshot",
+ __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe40_capture_raw(pmctl, vfe40_ctrl, snapshot_cnt);
+ break;
+ case VFE_CMD_CAPTURE:
+ if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG) {
+ if (snapshot_cnt != 1) {
+ pr_err("only support 1 inline snapshot\n");
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ /* Configure primary channel for JPEG */
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_JPEG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY,
+ vfe40_ctrl);
+ } else {
+ /* Configure primary channel */
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY,
+ vfe40_ctrl);
+ }
+ if (rc < 0) {
+ pr_err(
+ "%s error configuring pingpong buffers for primary output",
+ __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ /* Configure secondary channel */
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
+ vfe40_ctrl);
+ if (rc < 0) {
+ pr_err(
+ "%s error configuring pingpong buffers for secondary output",
+ __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe40_capture(pmctl, snapshot_cnt, vfe40_ctrl);
+ break;
+ case VFE_CMD_START_RECORDING:
+ CDBG("vfe40_proc_general: cmdID = %s\n",
+ vfe40_general_cmd[cmd->id]);
+ if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO)
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_START_RECORDING,
+ VFE_MSG_OUTPUT_SECONDARY,
+ vfe40_ctrl);
+ else if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW)
+ rc = vfe40_configure_pingpong_buffers(
+ VFE_MSG_START_RECORDING,
+ VFE_MSG_OUTPUT_PRIMARY,
+ vfe40_ctrl);
+ if (rc < 0) {
+ pr_err(
+ "%s error configuring pingpong buffers for video\n",
+ __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe40_start_recording(pmctl, vfe40_ctrl);
+ break;
+ case VFE_CMD_STOP_RECORDING:
+ CDBG("vfe40_proc_general: cmdID = %s\n",
+ vfe40_general_cmd[cmd->id]);
+ rc = vfe40_stop_recording(pmctl, vfe40_ctrl);
+ break;
+ case VFE_CMD_OPERATION_CFG: {
+ if (cmd->length != V40_OPERATION_CFG_LEN) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(V40_OPERATION_CFG_LEN, GFP_ATOMIC);
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ V40_OPERATION_CFG_LEN)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe40_operation_config(cmdp, vfe40_ctrl);
+ }
+ break;
+
+ case VFE_CMD_STATS_AE_START: {
+ rc = vfe_stats_aec_buf_init(vfe40_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AEC",
+ __func__);
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= BG_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+ case VFE_CMD_STATS_AF_START: {
+ rc = vfe_stats_af_buf_init(vfe40_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AF",
+ __func__);
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ VFE_MODULE_CFG);
+ old_val |= BF_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+
+ case VFE_CMD_STATS_AWB_START: {
+ rc = vfe_stats_awb_buf_init(vfe40_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= AWB_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+
+ case VFE_CMD_STATS_IHIST_START: {
+ rc = vfe_stats_ihist_buf_init(vfe40_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of IHIST",
+ __func__);
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= IHIST_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+
+
+ case VFE_CMD_STATS_RS_START: {
+ rc = vfe_stats_rs_buf_init(vfe40_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of RS",
+ __func__);
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+
+ case VFE_CMD_STATS_CS_START: {
+ rc = vfe_stats_cs_buf_init(vfe40_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+
+ case VFE_CMD_MCE_UPDATE:
+ case VFE_CMD_MCE_CFG:{
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ /* Incrementing with 4 so as to point to the 2nd Register as
+ the 2nd register has the mce_enable bit */
+ old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 4);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+ old_val &= MCE_EN_MASK;
+ new_val = new_val | old_val;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 4, &new_val, 4);
+ cmdp_local += 1;
+
+ old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 8);
+ new_val = *cmdp_local;
+ old_val &= MCE_Q_K_MASK;
+ new_val = new_val | old_val;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 8, &new_val, 4);
+ cmdp_local += 1;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp_local, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+ case VFE_CMD_CHROMA_SUP_UPDATE:
+ case VFE_CMD_CHROMA_SUP_CFG:{
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF, cmdp_local, 4);
+
+ cmdp_local += 1;
+ new_val = *cmdp_local;
+ /* Incrementing with 4 so as to point to the 2nd Register as
+ * the 2nd register has the mce_enable bit
+ */
+ old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 4);
+ old_val &= ~MCE_EN_MASK;
+ new_val = new_val | old_val;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 4, &new_val, 4);
+ cmdp_local += 1;
+
+ old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 8);
+ new_val = *cmdp_local;
+ old_val &= ~MCE_Q_K_MASK;
+ new_val = new_val | old_val;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_CHROMA_SUP_OFF + 8, &new_val, 4);
+ }
+ break;
+ case VFE_CMD_BLACK_LEVEL_CFG:
+ rc = -EFAULT;
+ goto proc_general_done;
+
+ case VFE_CMD_LA_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp_local, (vfe40_cmd[cmd->id].length));
+
+ cmdp_local += 1;
+ vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+ cmdp_local, vfe40_ctrl);
+ break;
+
+ case VFE_CMD_LA_UPDATE: {
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ cmdp_local = cmdp + 1;
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF);
+ if (old_val != 0x0)
+ vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+ cmdp_local, vfe40_ctrl);
+ else
+ vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+ cmdp_local, vfe40_ctrl);
+ }
+ vfe40_ctrl->update_la = true;
+ break;
+
+ case VFE_CMD_GET_LA_TABLE:
+ temp1 = sizeof(uint32_t) * VFE40_LA_TABLE_LENGTH / 2;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ if (msm_camera_io_r(vfe40_ctrl->
+ share_ctrl->vfebase + V40_LA_OFF))
+ vfe40_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+ vfe40_ctrl);
+ else
+ vfe40_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+ vfe40_ctrl);
+ for (i = 0 ; i < (VFE40_LA_TABLE_LENGTH / 2) ; i++) {
+ *cmdp_local =
+ msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
+ *cmdp_local |= (msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO)) << 16;
+ cmdp_local++;
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_SK_ENHAN_CFG:
+ case VFE_CMD_SK_ENHAN_UPDATE:{
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_SCE_OFF,
+ cmdp, V40_SCE_LEN);
+ }
+ break;
+
+ case VFE_CMD_LIVESHOT:
+ /* Configure primary channel */
+ rc = vfe40_configure_pingpong_buffers(VFE_MSG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl);
+ if (rc < 0) {
+ pr_err(
+ "%s error configuring pingpong buffers for primary output\n",
+ __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ vfe40_start_liveshot(pmctl, vfe40_ctrl);
+ break;
+
+ case VFE_CMD_LINEARIZATION_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_LINEARIZATION_OFF1,
+ cmdp_local, V40_LINEARIZATION_LEN1);
+
+ cmdp_local = cmdp + 17;
+ vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK0,
+ cmdp_local, vfe40_ctrl);
+ break;
+
+ case VFE_CMD_LINEARIZATION_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ cmdp_local++;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_LINEARIZATION_OFF1 + 4,
+ cmdp_local, (V40_LINEARIZATION_LEN1 - 4));
+ cmdp_local = cmdp + 17;
+ /*extracting the bank select*/
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_LINEARIZATION_OFF1);
+
+ if (old_val != 0x0)
+ vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK0,
+ cmdp_local, vfe40_ctrl);
+ else
+ vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK1,
+ cmdp_local, vfe40_ctrl);
+ vfe40_ctrl->update_linear = true;
+ break;
+
+ case VFE_CMD_GET_LINEARIZATON_TABLE:
+ temp1 = sizeof(uint32_t) * VFE40_LINEARIZATON_TABLE_LENGTH;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ if (msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_LINEARIZATION_OFF1))
+ vfe40_program_dmi_cfg(BLACK_LUT_RAM_BANK1, vfe40_ctrl);
+ else
+ vfe40_program_dmi_cfg(BLACK_LUT_RAM_BANK0, vfe40_ctrl);
+ CDBG("%s: Linearization Table\n", __func__);
+ for (i = 0 ; i < VFE40_LINEARIZATON_TABLE_LENGTH ; i++) {
+ *cmdp_local = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *cmdp_local);
+ cmdp_local++;
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_DEMOSAICV3:
+ if (cmd->length !=
+ V40_DEMOSAICV3_0_LEN+V40_DEMOSAICV3_1_LEN) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+ old_val &= DEMOSAIC_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+ cmdp_local, V40_DEMOSAICV3_0_LEN);
+ cmdp_local += 1;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_1_OFF,
+ cmdp_local, V40_DEMOSAICV3_1_LEN);
+ break;
+
+ case VFE_CMD_DEMOSAICV3_UPDATE:
+ if (cmd->length !=
+ V40_DEMOSAICV3_0_LEN * V40_DEMOSAICV3_UP_REG_CNT) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+ old_val &= DEMOSAIC_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+ cmdp_local, V40_DEMOSAICV3_0_LEN);
+ /* As the address space is not contiguous increment by 2
+ * before copying to next address space */
+ cmdp_local += 1;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_1_OFF,
+ cmdp_local, 2 * V40_DEMOSAICV3_0_LEN);
+ /* As the address space is not contiguous increment by 2
+ * before copying to next address space */
+ cmdp_local += 2;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_2_OFF,
+ cmdp_local, 2 * V40_DEMOSAICV3_0_LEN);
+ break;
+
+ case VFE_CMD_DEMOSAICV3_ABCC_CFG:
+ rc = -EFAULT;
+ break;
+
+ case VFE_CMD_DEMOSAICV3_ABF_UPDATE:/* 116 ABF update */
+ case VFE_CMD_DEMOSAICV3_ABF_CFG: { /* 108 ABF config */
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+ old_val &= ABF_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+ cmdp_local, 4);
+
+ cmdp_local += 1;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp_local, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+
+ case VFE_CMD_DEMOSAICV3_DBCC_CFG:
+ case VFE_CMD_DEMOSAICV3_DBCC_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+ old_val &= DBCC_MASK;
+
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+ cmdp_local, 4);
+ cmdp_local += 1;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp_local, (vfe40_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_DEMOSAICV3_DBPC_CFG:
+ case VFE_CMD_DEMOSAICV3_DBPC_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+ old_val &= DBPC_MASK;
+
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+ msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+ V40_DEMOSAICV3_0_OFF,
+ cmdp_local, V40_DEMOSAICV3_0_LEN);
+ cmdp_local += 1;
+ msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+ V40_DEMOSAICV3_DBPC_CFG_OFF,
+ cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+ cmdp_local += 1;
+ msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+ V40_DEMOSAICV3_DBPC_CFG_OFF0,
+ cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+ cmdp_local += 1;
+ msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+ V40_DEMOSAICV3_DBPC_CFG_OFF1,
+ cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+ cmdp_local += 1;
+ msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+ V40_DEMOSAICV3_DBPC_CFG_OFF2,
+ cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+ break;
+
+ case VFE_CMD_RGB_G_CFG: {
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF,
+ cmdp, 4);
+ cmdp += 1;
+
+ vfe40_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp, vfe40_ctrl);
+ vfe40_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp, vfe40_ctrl);
+ vfe40_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp, vfe40_ctrl);
+ }
+ cmdp -= 1;
+ break;
+
+ case VFE_CMD_RGB_G_UPDATE: {
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+ cmdp += 1;
+ if (old_val != 0x0) {
+ vfe40_write_gamma_cfg(
+ RGBLUT_RAM_CH0_BANK0, cmdp, vfe40_ctrl);
+ vfe40_write_gamma_cfg(
+ RGBLUT_RAM_CH1_BANK0, cmdp, vfe40_ctrl);
+ vfe40_write_gamma_cfg(
+ RGBLUT_RAM_CH2_BANK0, cmdp, vfe40_ctrl);
+ } else {
+ vfe40_write_gamma_cfg(
+ RGBLUT_RAM_CH0_BANK1, cmdp, vfe40_ctrl);
+ vfe40_write_gamma_cfg(
+ RGBLUT_RAM_CH1_BANK1, cmdp, vfe40_ctrl);
+ vfe40_write_gamma_cfg(
+ RGBLUT_RAM_CH2_BANK1, cmdp, vfe40_ctrl);
+ }
+ }
+ vfe40_ctrl->update_gamma = TRUE;
+ cmdp -= 1;
+ break;
+
+ case VFE_CMD_GET_RGB_G_TABLE:
+ temp1 = sizeof(uint32_t) * VFE40_GAMMA_NUM_ENTRIES * 3;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+ temp2 = old_val ? RGBLUT_RAM_CH0_BANK1 :
+ RGBLUT_RAM_CH0_BANK0;
+ for (i = 0; i < 3; i++) {
+ vfe40_read_gamma_cfg(temp2,
+ cmdp_local + (VFE40_GAMMA_NUM_ENTRIES * i),
+ vfe40_ctrl);
+ temp2 += 2;
+ }
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+
+ case VFE_CMD_STATS_AWB_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~AWB_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ }
+ break;
+
+ case VFE_CMD_STATS_AE_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~BG_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ }
+ break;
+ case VFE_CMD_STATS_AF_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~BF_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case VFE_CMD_STATS_IHIST_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~IHIST_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ }
+ break;
+
+ case VFE_CMD_STATS_RS_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~RS_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ }
+ break;
+
+ case VFE_CMD_STATS_CS_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~CS_ENABLE_MASK;
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ }
+ break;
+ case VFE_CMD_STOP:
+ CDBG("vfe40_proc_general: cmdID = %s\n",
+ vfe40_general_cmd[cmd->id]);
+ vfe40_stop(vfe40_ctrl);
+ break;
+
+ case VFE_CMD_SYNC_TIMER_SETTING:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ vfe40_sync_timer_start(cmdp, vfe40_ctrl);
+ break;
+
+ case VFE_CMD_MODULE_CFG: {
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ *cmdp &= ~STATS_ENABLE_MASK;
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= STATS_ENABLE_MASK;
+ *cmdp |= old_val;
+
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ }
+ break;
+
+ case VFE_CMD_ZSL:
+ rc = vfe40_configure_pingpong_buffers(VFE_MSG_START,
+ VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl);
+ if (rc < 0)
+ goto proc_general_done;
+ rc = vfe40_configure_pingpong_buffers(VFE_MSG_START,
+ VFE_MSG_OUTPUT_SECONDARY, vfe40_ctrl);
+ if (rc < 0)
+ goto proc_general_done;
+
+ rc = vfe40_zsl(pmctl, vfe40_ctrl);
+ break;
+
+ case VFE_CMD_ASF_CFG:
+ case VFE_CMD_ASF_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ cmdp_local = cmdp + V40_ASF_LEN/4;
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_ASF_SPECIAL_EFX_CFG_OFF,
+ cmdp_local, V40_ASF_SPECIAL_EFX_CFG_LEN);
+ break;
+
+ case VFE_CMD_GET_HW_VERSION:
+ if (cmd->length != V40_GET_HW_VERSION_LEN) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(V40_GET_HW_VERSION_LEN, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ *cmdp = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase+V40_GET_HW_VERSION_OFF);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ V40_GET_HW_VERSION_LEN)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_GET_REG_DUMP:
+ temp1 = sizeof(uint32_t) *
+ vfe40_ctrl->share_ctrl->register_total;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(temp1, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase,
+ vfe40_ctrl->share_ctrl->register_total*4);
+ CDBG("%s: %p %p %d\n", __func__, (void *)cmdp,
+ vfe40_ctrl->share_ctrl->vfebase, temp1);
+ memcpy_fromio((void *)cmdp,
+ vfe40_ctrl->share_ctrl->vfebase, temp1);
+ if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_FRAME_SKIP_CFG:
+ if (cmd->length != vfe40_cmd[cmd->id].length)
+ return -EINVAL;
+
+ cmdp = kmalloc(vfe40_cmd[cmd->id].length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+
+ if (copy_from_user((cmdp), (void __user *)cmd->value,
+ cmd->length)) {
+ rc = -EFAULT;
+ pr_err("%s copy from user failed for cmd %d",
+ __func__, cmd->id);
+ break;
+ }
+
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ vfe40_ctrl->frame_skip_cnt = ((uint32_t)
+ *cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
+ vfe40_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2));
+ break;
+ default:
+ if (cmd->length != vfe40_cmd[cmd->id].length)
+ return -EINVAL;
+
+ cmdp = kmalloc(vfe40_cmd[cmd->id].length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+
+ if (copy_from_user((cmdp), (void __user *)cmd->value,
+ cmd->length)) {
+ rc = -EFAULT;
+ pr_err("%s copy from user failed for cmd %d",
+ __func__, cmd->id);
+ goto proc_general_done;
+ }
+ msm_camera_io_memcpy(
+ vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[cmd->id].offset,
+ cmdp, (vfe40_cmd[cmd->id].length));
+ break;
+
+ }
+
+proc_general_done:
+ kfree(cmdp);
+
+ return rc;
+}
+
+static inline void vfe40_read_irq_status(
+ struct axi_ctrl_t *axi_ctrl, struct vfe40_irq_status *out)
+{
+ uint32_t *temp;
+ memset(out, 0, sizeof(struct vfe40_irq_status));
+ temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_0);
+ out->vfeIrqStatus0 = msm_camera_io_r(temp);
+
+ temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_1);
+ out->vfeIrqStatus1 = msm_camera_io_r(temp);
+
+ temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
+ out->camifStatus = msm_camera_io_r(temp);
+ CDBG("camifStatus = 0x%x\n", out->camifStatus);
+
+ /* clear the pending interrupt of the same kind.*/
+ msm_camera_io_w(out->vfeIrqStatus0,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_camera_io_w(out->vfeIrqStatus1,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(1, axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+
+}
+
+static void vfe40_process_reg_update_irq(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+
+ if (vfe40_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+ if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ }
+ vfe40_ctrl->recording_state = VFE_STATE_STARTED;
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ CDBG("start video triggered .\n");
+ } else if (vfe40_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ }
+ CDBG("stop video triggered .\n");
+ }
+
+ if (vfe40_ctrl->start_ack_pending == TRUE) {
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
+ vfe40_ctrl->start_ack_pending = FALSE;
+ } else {
+ if (vfe40_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ vfe40_ctrl->recording_state = VFE_STATE_STOPPED;
+ /* request a reg update and send STOP_REC_ACK
+ * when we process the next reg update irq.
+ */
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } else if (vfe40_ctrl->recording_state ==
+ VFE_STATE_STOPPED) {
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_STOP_REC_ACK);
+ vfe40_ctrl->recording_state = VFE_STATE_IDLE;
+ }
+ spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
+ if (vfe40_ctrl->update_ack_pending == TRUE) {
+ vfe40_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &vfe40_ctrl->update_ack_lock, flags);
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_UPDATE_ACK);
+ } else {
+ spin_unlock_irqrestore(
+ &vfe40_ctrl->update_ack_lock, flags);
+ }
+ }
+
+ if (vfe40_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_START_REQUESTED) {
+ CDBG("%s enabling liveshot output\n", __func__);
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ vfe40_ctrl->share_ctrl->liveshot_state =
+ VFE_STATE_STARTED;
+ }
+ }
+
+ if (vfe40_ctrl->share_ctrl->liveshot_state == VFE_STATE_STARTED) {
+ vfe40_ctrl->share_ctrl->vfe_capture_count--;
+ if (!vfe40_ctrl->share_ctrl->vfe_capture_count)
+ vfe40_ctrl->share_ctrl->liveshot_state =
+ VFE_STATE_STOP_REQUESTED;
+ msm_camera_io_w_mb(1, vfe40_ctrl->
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } else if (vfe40_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ CDBG("%s: disabling liveshot output\n", __func__);
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ vfe40_ctrl->share_ctrl->liveshot_state =
+ VFE_STATE_STOPPED;
+ msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ }
+ } else if (vfe40_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOPPED) {
+ vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+ }
+
+ if ((vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN) ||
+ (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB) ||
+ (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG) ||
+ (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB)) {
+ /* in snapshot mode */
+ /* later we need to add check for live snapshot mode. */
+ if (vfe40_ctrl->frame_skip_pattern & (0x1 <<
+ (vfe40_ctrl->snapshot_frame_cnt %
+ vfe40_ctrl->frame_skip_cnt))) {
+ vfe40_ctrl->share_ctrl->vfe_capture_count--;
+ /* if last frame to be captured: */
+ if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) {
+ /* stop the bus output:write master enable = 0*/
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode
+ & VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ }
+ if (vfe40_ctrl->share_ctrl->outpath.output_mode&
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[vfe40_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ }
+ msm_camera_io_w_mb
+ (CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
+ vfe40_ctrl->snapshot_frame_cnt = -1;
+ vfe40_ctrl->frame_skip_cnt = 31;
+ vfe40_ctrl->frame_skip_pattern = 0xffffffff;
+ } /*if snapshot count is 0*/
+ } /*if frame is not being dropped*/
+ vfe40_ctrl->snapshot_frame_cnt++;
+ /* then do reg_update. */
+ msm_camera_io_w(1,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } /* if snapshot mode. */
+}
+
+static void vfe40_set_default_reg_values(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ msm_camera_io_w(0x800080,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+ msm_camera_io_w(0x800080,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+ /* What value should we program CGC_OVERRIDE to? */
+ msm_camera_io_w(0xFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+ /* default frame drop period and pattern */
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MIN);
+ msm_camera_io_w(0xFFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MAX);
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MIN);
+ msm_camera_io_w(0xFFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MAX);
+
+ /* stats UB config */
+ msm_camera_io_w(0x3980007,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
+ msm_camera_io_w(0x3A00007,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
+ msm_camera_io_w(0x3A8000F,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
+ msm_camera_io_w(0x3B80007,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
+ msm_camera_io_w(0x3C0001F,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
+ msm_camera_io_w(0x3E0001F,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+}
+
+static void vfe40_process_reset_irq(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+
+ atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+
+ spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+ if (vfe40_ctrl->share_ctrl->stop_ack_pending) {
+ vfe40_ctrl->share_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
+ } else {
+ spin_unlock_irqrestore(
+ &vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+ /* this is from reset command. */
+ vfe40_set_default_reg_values(vfe40_ctrl);
+
+ /* reload all write masters. (frame & line)*/
+ msm_camera_io_w(0x7FFF,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_RESET_ACK);
+ }
+}
+
+static void vfe40_process_camif_sof_irq(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ if (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW) {
+ if (vfe40_ctrl->start_ack_pending) {
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_START_ACK);
+ vfe40_ctrl->start_ack_pending = FALSE;
+ }
+ vfe40_ctrl->share_ctrl->vfe_capture_count--;
+ /* if last frame to be captured: */
+ if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) {
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ }
+ } /* if raw snapshot mode. */
+ if ((vfe40_ctrl->hfr_mode != HFR_MODE_OFF) &&
+ (vfe40_ctrl->share_ctrl->operation_mode ==
+ VFE_MODE_OF_OPERATION_VIDEO) &&
+ (vfe40_ctrl->share_ctrl->vfeFrameId %
+ vfe40_ctrl->hfr_mode != 0)) {
+ vfe40_ctrl->share_ctrl->vfeFrameId++;
+ CDBG("Skip the SOF notification when HFR enabled\n");
+ return;
+ }
+ vfe40_ctrl->share_ctrl->vfeFrameId++;
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_SOF_ACK);
+ CDBG("camif_sof_irq, frameId = %d\n",
+ vfe40_ctrl->share_ctrl->vfeFrameId);
+
+ if (vfe40_ctrl->sync_timer_state) {
+ if (vfe40_ctrl->sync_timer_repeat_count == 0)
+ vfe40_sync_timer_stop(vfe40_ctrl);
+ else
+ vfe40_ctrl->sync_timer_repeat_count--;
+ }
+}
+
+static void vfe40_process_error_irq(
+ struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
+{
+ uint32_t reg_value;
+
+ if (errStatus & VFE40_IMASK_CAMIF_ERROR) {
+ pr_err("vfe40_irq: camif errors\n");
+ reg_value = msm_camera_io_r(
+ axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
+ pr_err("camifStatus = 0x%x\n", reg_value);
+ vfe40_send_isp_msg(&axi_ctrl->subdev,
+ axi_ctrl->share_ctrl->vfeFrameId, MSG_ID_CAMIF_ERROR);
+ }
+
+ if (errStatus & VFE40_IMASK_BHIST_OVWR)
+ pr_err("vfe40_irq: stats bhist overwrite\n");
+
+ if (errStatus & VFE40_IMASK_STATS_CS_OVWR)
+ pr_err("vfe40_irq: stats cs overwrite\n");
+
+ if (errStatus & VFE40_IMASK_STATS_IHIST_OVWR)
+ pr_err("vfe40_irq: stats ihist overwrite\n");
+
+ if (errStatus & VFE40_IMASK_REALIGN_BUF_Y_OVFL)
+ pr_err("vfe40_irq: realign bug Y overflow\n");
+
+ if (errStatus & VFE40_IMASK_REALIGN_BUF_CB_OVFL)
+ pr_err("vfe40_irq: realign bug CB overflow\n");
+
+ if (errStatus & VFE40_IMASK_REALIGN_BUF_CR_OVFL)
+ pr_err("vfe40_irq: realign bug CR overflow\n");
+
+ if (errStatus & VFE40_IMASK_VIOLATION) {
+ pr_err("vfe40_irq: violation interrupt\n");
+ reg_value = msm_camera_io_r(
+ axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS);
+ pr_err("%s: violationStatus = 0x%x\n", __func__, reg_value);
+ }
+
+ if (errStatus & VFE40_IMASK_IMG_MAST_0_BUS_OVFL)
+ pr_err("vfe40_irq: image master 0 bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_IMG_MAST_1_BUS_OVFL)
+ pr_err("vfe40_irq: image master 1 bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_IMG_MAST_2_BUS_OVFL)
+ pr_err("vfe40_irq: image master 2 bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_IMG_MAST_3_BUS_OVFL)
+ pr_err("vfe40_irq: image master 3 bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_IMG_MAST_4_BUS_OVFL)
+ pr_err("vfe40_irq: image master 4 bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_IMG_MAST_5_BUS_OVFL)
+ pr_err("vfe40_irq: image master 5 bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_IMG_MAST_6_BUS_OVFL)
+ pr_err("vfe40_irq: image master 6 bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_AE_BG_BUS_OVFL)
+ pr_err("vfe40_irq: ae/bg stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_AF_BF_BUS_OVFL)
+ pr_err("vfe40_irq: af/bf stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_AWB_BUS_OVFL)
+ pr_err("vfe40_irq: awb stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_RS_BUS_OVFL)
+ pr_err("vfe40_irq: rs stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_CS_BUS_OVFL)
+ pr_err("vfe40_irq: cs stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_IHIST_BUS_OVFL)
+ pr_err("vfe40_irq: ihist stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+ pr_err("vfe40_irq: skin/bhist stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_AXI_ERROR)
+ pr_err("vfe40_irq: axi error\n");
+}
+
+static uint32_t vfe40_process_stats_irq_common(
+ struct vfe40_ctrl_type *vfe40_ctrl,
+ uint32_t statsNum, uint32_t newAddr)
+{
+ uint32_t pingpongStatus;
+ uint32_t returnAddr;
+ uint32_t pingpongAddr;
+
+ /* must be 0=ping, 1=pong */
+ pingpongStatus =
+ ((msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS))
+ & ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
+ /* stats bits starts at 7 */
+ CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
+ pingpongAddr =
+ ((uint32_t)(vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_PING_PONG_BASE)) +
+ (3*statsNum)*4 + (1-pingpongStatus)*4;
+ returnAddr = msm_camera_io_r((uint32_t *)pingpongAddr);
+ msm_camera_io_w(newAddr, (uint32_t *)pingpongAddr);
+ return returnAddr;
+}
+
+static void
+vfe_send_stats_msg(struct vfe40_ctrl_type *vfe40_ctrl,
+ uint32_t bufAddress, uint32_t statsNum)
+{
+ int rc = 0;
+ void *vaddr = NULL;
+ /* fill message with right content. */
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ struct isp_msg_stats msgStats;
+ msgStats.frameCounter = vfe40_ctrl->share_ctrl->vfeFrameId;
+ msgStats.buffer = bufAddress;
+
+ switch (statsNum) {
+ case statsAeNum:{
+ msgStats.id = MSG_ID_STATS_AEC;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AEC, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
+ case statsAfNum:{
+ msgStats.id = MSG_ID_STATS_AF;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AF, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
+ case statsAwbNum: {
+ msgStats.id = MSG_ID_STATS_AWB;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AWB, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
+
+ case statsIhistNum: {
+ msgStats.id = MSG_ID_STATS_IHIST;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_IHIST, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
+ case statsRsNum: {
+ msgStats.id = MSG_ID_STATS_RS;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_RS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
+ case statsCsNum: {
+ msgStats.id = MSG_ID_STATS_CS;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_CS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
+
+ default:
+ goto stats_done;
+ }
+ if (rc == 0) {
+ msgStats.buffer = (uint32_t)vaddr;
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS,
+ &msgStats);
+ } else {
+ pr_err("%s: paddr to idx mapping error, stats_id = %d, paddr = 0x%d",
+ __func__, msgStats.id, msgStats.buffer);
+ }
+stats_done:
+ spin_unlock_irqrestore(&ctrl->state_lock, flags);
+ return;
+}
+
+static void vfe_send_comp_stats_msg(
+ struct vfe40_ctrl_type *vfe40_ctrl, uint32_t status_bits)
+{
+ struct msm_stats_buf msgStats;
+ uint32_t temp;
+
+ msgStats.frame_id = vfe40_ctrl->share_ctrl->vfeFrameId;
+ msgStats.status_bits = status_bits;
+
+ msgStats.aec.buff = vfe40_ctrl->aecStatsControl.bufToRender;
+ msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
+ msgStats.af.buff = vfe40_ctrl->afStatsControl.bufToRender;
+
+ msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
+ msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
+ msgStats.cs.buff = vfe40_ctrl->csStatsControl.bufToRender;
+
+ temp = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG);
+ msgStats.awb_ymin = (0xFF00 & temp) >> 8;
+
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_MSG_COMP_STATS,
+ &msgStats);
+}
+
+static void vfe40_process_stats_awb_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->awbStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl, statsAwbNum,
+ addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->awbStatsControl.bufToRender, statsAwbNum);
+ } else{
+ vfe40_ctrl->awbStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->awbStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe40_process_stats_ihist_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->ihistStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsIhistNum, addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->ihistStatsControl.bufToRender,
+ statsIhistNum);
+ } else {
+ vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe40_process_stats_rs_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->rsStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl, statsRsNum,
+ addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->rsStatsControl.bufToRender, statsRsNum);
+ } else {
+ vfe40_ctrl->rsStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->rsStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe40_process_stats_cs_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->csStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl, statsCsNum,
+ addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->csStatsControl.bufToRender, statsCsNum);
+ } else {
+ vfe40_ctrl->csStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->csStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe40_process_stats(struct vfe40_ctrl_type *vfe40_ctrl,
+ uint32_t status_bits)
+{
+ unsigned long flags;
+ int32_t process_stats = false;
+ uint32_t addr;
+
+ CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ MSM_STATS_TYPE_AWB);
+ if (addr) {
+ vfe40_ctrl->awbStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsAwbNum,
+ addr);
+ process_stats = true;
+ } else{
+ vfe40_ctrl->awbStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->awbStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe40_ctrl->awbStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ MSM_STATS_TYPE_IHIST);
+ if (addr) {
+ vfe40_ctrl->ihistStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsIhistNum,
+ addr);
+ process_stats = true;
+ } else {
+ vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->ihistStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe40_ctrl->ihistStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ MSM_STATS_TYPE_RS);
+ if (addr) {
+ vfe40_ctrl->rsStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsRsNum,
+ addr);
+ process_stats = true;
+ } else {
+ vfe40_ctrl->rsStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->rsStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe40_ctrl->rsStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ MSM_STATS_TYPE_CS);
+ if (addr) {
+ vfe40_ctrl->csStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsCsNum,
+ addr);
+ process_stats = true;
+ } else {
+ vfe40_ctrl->csStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->csStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe40_ctrl->csStatsControl.bufToRender = 0;
+ }
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (process_stats)
+ vfe_send_comp_stats_msg(vfe40_ctrl, status_bits);
+
+ return;
+}
+
+static void vfe40_process_stats_irq(
+ struct vfe40_ctrl_type *vfe40_ctrl, uint32_t irqstatus)
+{
+ uint32_t status_bits = VFE_COM_STATUS & irqstatus;
+
+ if ((vfe40_ctrl->hfr_mode != HFR_MODE_OFF) &&
+ (vfe40_ctrl->share_ctrl->vfeFrameId %
+ vfe40_ctrl->hfr_mode != 0)) {
+ CDBG("Skip the stats when HFR enabled\n");
+ return;
+ }
+
+ vfe40_process_stats(vfe40_ctrl, status_bits);
+ return;
+}
+
+static void vfe40_process_irq(
+ struct vfe40_ctrl_type *vfe40_ctrl, uint32_t irqstatus)
+{
+ if (irqstatus &
+ VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) {
+ vfe40_process_stats_irq(vfe40_ctrl, irqstatus);
+ return;
+ }
+
+ switch (irqstatus) {
+ case VFE_IRQ_STATUS0_CAMIF_SOF_MASK:
+ CDBG("irq camifSofIrq\n");
+ vfe40_process_camif_sof_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS0_REG_UPDATE_MASK:
+ CDBG("irq regUpdateIrq\n");
+ vfe40_process_reg_update_irq(vfe40_ctrl);
+ break;
+ case VFE_IMASK_WHILE_STOPPING_0:
+ CDBG("irq resetAckIrq\n");
+ vfe40_process_reset_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS0_STATS_AWB:
+ CDBG("Stats AWB irq occured.\n");
+ vfe40_process_stats_awb_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS0_STATS_IHIST:
+ CDBG("Stats IHIST irq occured.\n");
+ vfe40_process_stats_ihist_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS0_STATS_RS:
+ CDBG("Stats RS irq occured.\n");
+ vfe40_process_stats_rs_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS0_STATS_CS:
+ CDBG("Stats CS irq occured.\n");
+ vfe40_process_stats_cs_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS1_SYNC_TIMER0:
+ CDBG("SYNC_TIMER 0 irq occured.\n");
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_SYNC_TIMER0_DONE);
+ break;
+ case VFE_IRQ_STATUS1_SYNC_TIMER1:
+ CDBG("SYNC_TIMER 1 irq occured.\n");
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_SYNC_TIMER1_DONE);
+ break;
+ case VFE_IRQ_STATUS1_SYNC_TIMER2:
+ CDBG("SYNC_TIMER 2 irq occured.\n");
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_SYNC_TIMER2_DONE);
+ break;
+ default:
+ pr_err("Invalid IRQ status\n");
+ }
+}
+
+static void axi40_do_tasklet(unsigned long data)
+{
+ unsigned long flags;
+ struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data;
+ struct vfe40_isr_queue_cmd *qcmd = NULL;
+
+ CDBG("=== axi40_do_tasklet start ===\n");
+
+ while (atomic_read(&axi_ctrl->share_ctrl->irq_cnt)) {
+ spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
+ qcmd = list_first_entry(&axi_ctrl->tasklet_q,
+ struct vfe40_isr_queue_cmd, list);
+ atomic_sub(1, &axi_ctrl->share_ctrl->irq_cnt);
+
+ if (!qcmd) {
+ spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
+ flags);
+ return;
+ }
+
+ list_del(&qcmd->list);
+ spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
+ flags);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_CAMIF_SOF_MASK)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
+
+ /* interrupt to be processed, *qcmd has the payload. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
+ }
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IMASK_WHILE_STOPPING_0)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IMASK_WHILE_STOPPING_0);
+
+ if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
+ if (qcmd->vfeInterruptStatus1 &
+ VFE40_IMASK_ERROR_ONLY_1) {
+ pr_err("irq errorIrq\n");
+ vfe40_process_error_irq(
+ axi_ctrl,
+ qcmd->vfeInterruptStatus1 &
+ VFE40_IMASK_ERROR_ONLY_1);
+ }
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_AXI_IRQ,
+ (void *)qcmd->vfeInterruptStatus0);
+
+ /* then process stats irq. */
+ if (axi_ctrl->share_ctrl->stats_comp) {
+ /* process stats comb interrupt. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) {
+ CDBG("Stats composite irq occured.\n");
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)qcmd->vfeInterruptStatus0);
+ }
+ } else {
+ /* process individual stats interrupt. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AWB)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_AWB);
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_IHIST)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_IHIST);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_RS)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_RS);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_CS)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_CS);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS1_SYNC_TIMER0)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS1_SYNC_TIMER0);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS1_SYNC_TIMER1)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS1_SYNC_TIMER1);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS1_SYNC_TIMER2)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS1_SYNC_TIMER2);
+ }
+ }
+ kfree(qcmd);
+ }
+ CDBG("=== axi40_do_tasklet end ===\n");
+}
+
+static irqreturn_t vfe40_parse_irq(int irq_num, void *data)
+{
+ unsigned long flags;
+ struct vfe40_irq_status irq;
+ struct vfe40_isr_queue_cmd *qcmd;
+ struct axi_ctrl_t *axi_ctrl = data;
+
+ CDBG("vfe_parse_irq\n");
+
+ vfe40_read_irq_status(axi_ctrl, &irq);
+
+ if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
+ CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
+ return IRQ_HANDLED;
+ }
+
+ qcmd = kzalloc(sizeof(struct vfe40_isr_queue_cmd),
+ GFP_ATOMIC);
+ if (!qcmd) {
+ pr_err("vfe_parse_irq: qcmd malloc failed!\n");
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+ if (axi_ctrl->share_ctrl->stop_ack_pending) {
+ irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
+ irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1;
+ }
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+
+ CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
+ irq.vfeIrqStatus0, irq.vfeIrqStatus1);
+
+ qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
+ qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
+
+ spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
+ list_add_tail(&qcmd->list, &axi_ctrl->tasklet_q);
+
+ atomic_add(1, &axi_ctrl->share_ctrl->irq_cnt);
+ spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, flags);
+ tasklet_schedule(&axi_ctrl->vfe40_tasklet);
+ return IRQ_HANDLED;
+}
+
+
+static long vfe_stats_bufq_sub_ioctl(
+ struct vfe40_ctrl_type *vfe_ctrl,
+ struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+{
+ long rc = 0;
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ if (!vfe_ctrl->stats_ops.stats_ctrl) {
+ /* stats_ctrl has not been init yet */
+ rc = msm_stats_buf_ops_init(&vfe_ctrl->stats_ctrl,
+ (struct ion_client *)ion_client,
+ &vfe_ctrl->stats_ops);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats ops", __func__);
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.stats_ctrl_init(&vfe_ctrl->stats_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats_ctrl ops", __func__);
+ memset(&vfe_ctrl->stats_ops, 0,
+ sizeof(vfe_ctrl->stats_ops));
+ goto end;
+ }
+ if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats reqbuf input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_reqbuf));
+ rc = -EINVAL ;
+ goto end;
+ }
+ }
+ rc = vfe_ctrl->stats_ops.reqbuf(
+ &vfe_ctrl->stats_ctrl,
+ (struct msm_stats_reqbuf *)cmd->value,
+ vfe_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.enqueue_buf(
+ &vfe_ctrl->stats_ctrl,
+ (struct msm_stats_buf_info *)cmd->value,
+ vfe_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ {
+ struct msm_stats_flush_bufq *flush_req = NULL;
+ flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+ if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats flush queue input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_flush_bufq));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.bufq_flush(
+ &vfe_ctrl->stats_ctrl,
+ (enum msm_stats_enum_type)flush_req->stats_type,
+ vfe_ctrl->stats_ops.client);
+ }
+ break;
+ default:
+ rc = -1;
+ pr_err("%s: cmd_type %d not supported", __func__,
+ cmd->cmd_type);
+ break;
+ }
+end:
+ return rc;
+}
+
+static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int subdev_cmd, void *arg)
+{
+ struct msm_cam_media_controller *pmctl =
+ (struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+ struct vfe40_ctrl_type *vfe40_ctrl =
+ (struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
+ struct msm_isp_cmd vfecmd;
+ struct msm_camvfe_params *vfe_params =
+ (struct msm_camvfe_params *)arg;
+ struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+ void *data = vfe_params->data;
+
+ long rc = 0;
+ struct vfe_cmd_stats_buf *scfg = NULL;
+ struct vfe_cmd_stats_ack *sack = NULL;
+
+ if (!vfe40_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return -EFAULT;
+ }
+
+ switch (cmd->cmd_type) {
+ case CMD_VFE_PROCESS_IRQ:
+ vfe40_process_irq(vfe40_ctrl, (uint32_t) data);
+ return rc;
+ case VFE_CMD_STATS_REQBUF:
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ /* for easy porting put in one envelope */
+ rc = vfe_stats_bufq_sub_ioctl(vfe40_ctrl,
+ cmd, vfe_params->data);
+ return rc;
+ default:
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+ cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ /* here eith stats release or frame release. */
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+ /* then must be stats release. */
+ if (!data) {
+ pr_err("%s: data = NULL, cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
+ return -EFAULT;
+ }
+ sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+ GFP_ATOMIC);
+ if (!sack) {
+ pr_err("%s: no mem for cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
+ return -ENOMEM;
+ }
+ sack->nextStatsBuf = *(uint32_t *)data;
+ }
+ }
+ CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+ if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+ scfg = NULL;
+ /* individual */
+ goto vfe40_config_done;
+ }
+ switch (cmd->cmd_type) {
+ case CMD_GENERAL:
+ rc = vfe40_proc_general(pmctl, &vfecmd, vfe40_ctrl);
+ break;
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe40_output_ch *outch =
+ vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe40_output_ch *outch =
+ vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe40_output_ch *outch =
+ vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
+ break;
+ case CMD_SNAP_BUF_RELEASE:
+ break;
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cmd->cmd_type);
+ break;
+ }
+ }
+vfe40_config_done:
+ kfree(scfg);
+ kfree(sack);
+ CDBG("%s done: rc = %d\n", __func__, (int) rc);
+ return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
+ .ioctl = msm_vfe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
+ .core = &msm_vfe_subdev_core_ops,
+};
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd,
+ struct msm_cam_media_controller *mctl)
+{
+ int rc = 0;
+ struct vfe40_ctrl_type *vfe40_ctrl =
+ (struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
+ v4l2_set_subdev_hostdata(sd, mctl);
+
+ spin_lock_init(&vfe40_ctrl->share_ctrl->stop_flag_lock);
+ spin_lock_init(&vfe40_ctrl->state_lock);
+ spin_lock_init(&vfe40_ctrl->io_lock);
+ spin_lock_init(&vfe40_ctrl->update_ack_lock);
+ spin_lock_init(&vfe40_ctrl->stats_bufq_lock);
+
+
+ vfe40_ctrl->update_linear = false;
+ vfe40_ctrl->update_rolloff = false;
+ vfe40_ctrl->update_la = false;
+ vfe40_ctrl->update_gamma = false;
+ vfe40_ctrl->hfr_mode = HFR_MODE_OFF;
+
+ return rc;
+}
+
+void msm_vfe_subdev_release(struct v4l2_subdev *sd)
+{
+ struct vfe40_ctrl_type *vfe40_ctrl =
+ (struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
+ if (!vfe40_ctrl->share_ctrl->vfebase)
+ vfe40_ctrl->share_ctrl->vfebase = NULL;
+}
+
+static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
+
+static int __devinit vfe40_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct axi_ctrl_t *axi_ctrl;
+ struct vfe40_ctrl_type *vfe40_ctrl;
+ struct vfe_share_ctrl_t *share_ctrl;
+ struct msm_cam_subdev_info sd_info;
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
+
+ share_ctrl = kzalloc(sizeof(struct vfe_share_ctrl_t), GFP_KERNEL);
+ if (!share_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ axi_ctrl = kzalloc(sizeof(struct axi_ctrl_t), GFP_KERNEL);
+ if (!axi_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ kfree(share_ctrl);
+ return -ENOMEM;
+ }
+
+ vfe40_ctrl = kzalloc(sizeof(struct vfe40_ctrl_type), GFP_KERNEL);
+ if (!vfe40_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ kfree(share_ctrl);
+ kfree(axi_ctrl);
+ return -ENOMEM;
+ }
+
+ if (pdev->dev.of_node)
+ of_property_read_u32((&pdev->dev)->of_node,
+ "cell-index", &pdev->id);
+
+ share_ctrl->axi_ctrl = axi_ctrl;
+ share_ctrl->vfe40_ctrl = vfe40_ctrl;
+ axi_ctrl->share_ctrl = share_ctrl;
+ vfe40_ctrl->share_ctrl = share_ctrl;
+ axi_ctrl->pdev = pdev;
+ vfe40_axi_probe(axi_ctrl);
+
+ v4l2_subdev_init(&vfe40_ctrl->subdev, &msm_vfe_subdev_ops);
+ vfe40_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
+ vfe40_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(vfe40_ctrl->subdev.name,
+ sizeof(vfe40_ctrl->subdev.name), "vfe4.0");
+ v4l2_set_subdevdata(&vfe40_ctrl->subdev, vfe40_ctrl);
+ platform_set_drvdata(pdev, &vfe40_ctrl->subdev);
+
+ axi_ctrl->vfemem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "vfe");
+ if (!axi_ctrl->vfemem) {
+ pr_err("%s: no mem resource?\n", __func__);
+ rc = -ENODEV;
+ goto vfe40_no_resource;
+ }
+ axi_ctrl->vfeirq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "vfe");
+ if (!axi_ctrl->vfeirq) {
+ pr_err("%s: no irq resource?\n", __func__);
+ rc = -ENODEV;
+ goto vfe40_no_resource;
+ }
+
+ axi_ctrl->vfeio = request_mem_region(axi_ctrl->vfemem->start,
+ resource_size(axi_ctrl->vfemem), pdev->name);
+ if (!axi_ctrl->vfeio) {
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto vfe40_no_resource;
+ }
+
+ rc = request_irq(axi_ctrl->vfeirq->start, vfe40_parse_irq,
+ IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
+ if (rc < 0) {
+ release_mem_region(axi_ctrl->vfemem->start,
+ resource_size(axi_ctrl->vfemem));
+ pr_err("%s: irq request fail\n", __func__);
+ rc = -EBUSY;
+ goto vfe40_no_resource;
+ }
+
+ disable_irq(axi_ctrl->vfeirq->start);
+
+ tasklet_init(&axi_ctrl->vfe40_tasklet,
+ axi40_do_tasklet, (unsigned long)axi_ctrl);
+
+ vfe40_ctrl->pdev = pdev;
+ sd_info.sdev_type = VFE_DEV;
+ sd_info.sd_index = pdev->id;
+ sd_info.irq_num = axi_ctrl->vfeirq->start;
+ msm_cam_register_subdev_node(&vfe40_ctrl->subdev, &sd_info);
+ return 0;
+
+vfe40_no_resource:
+ kfree(vfe40_ctrl);
+ kfree(axi_ctrl);
+ return 0;
+}
+
+static const struct of_device_id msm_vfe_dt_match[] = {
+ {.compatible = "qcom,vfe40"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe_dt_match);
+
+static struct platform_driver vfe40_driver = {
+ .probe = vfe40_probe,
+ .driver = {
+ .name = MSM_VFE_DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_vfe_dt_match,
+ },
+};
+
+static int __init msm_vfe40_init_module(void)
+{
+ return platform_driver_register(&vfe40_driver);
+}
+
+static void __exit msm_vfe40_exit_module(void)
+{
+ platform_driver_unregister(&vfe40_driver);
+}
+
+module_init(msm_vfe40_init_module);
+module_exit(msm_vfe40_exit_module);
+MODULE_DESCRIPTION("VFE 4.0 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
new file mode 100644
index 0000000..c8b0cb8
--- /dev/null
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -0,0 +1,1202 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#ifndef __MSM_VFE40_H__
+#define __MSM_VFE40_H__
+
+#include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define VFE40_HW_NUMBER 0x10000015
+
+/* This defines total number registers in VFE.
+ * Each register is 4 bytes so to get the range,
+ * multiply this number with 4. */
+#define VFE40_REGISTER_TOTAL 0x00000320
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT 0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR 0x00000000
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-32 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD 0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD 0x000001ff
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */
+#define VFE_CLEAR_ALL_IRQ0 0xffff7fff
+#define VFE_CLEAR_ALL_IRQ1 0xffffffff
+
+#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK (0x00000001<<0)
+#define VFE_IRQ_STATUS0_REG_UPDATE_MASK (0x00000001<<4)
+#define VFE_IRQ_STATUS0_STATS_BE (0x00000001<<16)
+#define VFE_IRQ_STATUS0_STATS_BG (0x00000001<<17)
+#define VFE_IRQ_STATUS0_STATS_BF (0x00000001<<18)
+#define VFE_IRQ_STATUS0_STATS_AWB (0x00000001<<19)
+#define VFE_IRQ_STATUS0_STATS_RS (0x00000001<<20)
+#define VFE_IRQ_STATUS0_STATS_CS (0x00000001<<21)
+#define VFE_IRQ_STATUS0_STATS_IHIST (0x00000001<<22)
+#define VFE_IRQ_STATUS0_STATS_SKIN_BHIST (0x00000001<<23)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK (0x00000001<<25)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK (0x00000001<<26)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK (0x00000001<<27)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE3_MASK (0x00000001<<28)
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0 (0x00000001<<29)
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_1 (0x00000001<<30)
+#define VFE_IRQ_STATUS0_RESET_AXI_HALT_ACK_MASK (0x00000001<<31)
+
+#define VFE_IRQ_STATUS1_SYNC_TIMER0 (0x00000001<<25)
+#define VFE_IRQ_STATUS1_SYNC_TIMER1 (0x00000001<<26)
+#define VFE_IRQ_STATUS1_SYNC_TIMER2 (0x00000001<<27)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER0 (0x00000001<<28)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER1 (0x00000001<<29)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER2 (0x00000001<<30)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER3 (0x00000001<<31)
+
+/* imask for while waiting for stop ack, driver has already
+ * requested stop, waiting for reset irq, and async timer irq.
+ * For irq_status_0, bit 28-32 are for async timer. For
+ * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+ irq */
+#define VFE_IMASK_WHILE_STOPPING_0 0x80000000
+#define VFE_IMASK_WHILE_STOPPING_1 0x00000100
+
+/* For ABF bit 4 is set to zero and other's 1 */
+#define ABF_MASK 0xFFFFFFF7
+
+/* For DBPC bit 0 is set to zero and other's 1 */
+#define DBPC_MASK 0xFFFFFFFE
+
+/* For DBPC bit 1 is set to zero and other's 1 */
+#define DBCC_MASK 0xFFFFFFFD
+
+/* For DBPC/ABF/DBCC/ABCC bits are set to 1 all others 0 */
+#define DEMOSAIC_MASK 0xF
+
+/* For MCE enable bit 28 set to zero and other's 1 */
+#define MCE_EN_MASK 0xEFFFFFFF
+
+/* For MCE Q_K bit 28 to 32 set to zero and other's 1 */
+#define MCE_Q_K_MASK 0x0FFFFFFF
+
+#define BE_ENABLE_MASK (0x00000001<<5)
+#define BG_ENABLE_MASK (0x00000001<<6)
+#define BF_ENABLE_MASK (0x00000001<<7)
+#define AWB_ENABLE_MASK (0x00000001<<8)
+#define RS_ENABLE_MASK (0x00000001<<9)
+#define CS_ENABLE_MASK (0x00000001<<10)
+#define CLF_ENABLE_MASK (0x00000001<<12)
+#define IHIST_ENABLE_MASK (0x00000001<<15)
+#define RS_CS_ENABLE_MASK (RS_ENABLE_MASK|CS_ENABLE_MASK)
+#define STATS_ENABLE_MASK 0x000487E0 /* bit 18,15,10,9,8,7,6,5*/
+
+#define VFE_DMI_CFG_DEFAULT 0x00000100
+
+#define HFR_MODE_OFF 1
+#define VFE_FRAME_SKIP_PERIOD_MASK 0x0000001F /*bits 0 -4*/
+
+enum VFE40_DMI_RAM_SEL {
+ NO_MEM_SELECTED = 0,
+ BLACK_LUT_RAM_BANK0 = 0x1,
+ BLACK_LUT_RAM_BANK1 = 0x2,
+ ROLLOFF_RAM0_BANK0 = 0x3,
+ ROLLOFF_RAM0_BANK1 = 0x4,
+ DEMOSAIC_LUT_RAM_BANK0 = 0x5,
+ DEMOSAIC_LUT_RAM_BANK1 = 0x6,
+ STATS_BHIST_RAM0 = 0x7,
+ STATS_BHIST_RAM1 = 0x8,
+ RGBLUT_RAM_CH0_BANK0 = 0x9,
+ RGBLUT_RAM_CH0_BANK1 = 0xa,
+ RGBLUT_RAM_CH1_BANK0 = 0xb,
+ RGBLUT_RAM_CH1_BANK1 = 0xc,
+ RGBLUT_RAM_CH2_BANK0 = 0xd,
+ RGBLUT_RAM_CH2_BANK1 = 0xe,
+ RGBLUT_CHX_BANK0 = 0xf,
+ RGBLUT_CHX_BANK1 = 0x10,
+ STATS_IHIST_RAM = 0x11,
+ LUMA_ADAPT_LUT_RAM_BANK0 = 0x12,
+ LUMA_ADAPT_LUT_RAM_BANK1 = 0x13,
+};
+
+enum vfe_output_state {
+ VFE_STATE_IDLE,
+ VFE_STATE_START_REQUESTED,
+ VFE_STATE_STARTED,
+ VFE_STATE_STOP_REQUESTED,
+ VFE_STATE_STOPPED,
+};
+
+#define V40_CAMIF_OFF 0x000002F8
+#define V40_CAMIF_LEN 36
+
+#define V40_DEMUX_OFF 0x00000424
+#define V40_DEMUX_LEN 28
+
+#define V40_DEMOSAICV3_0_OFF 0x00000440
+#define V40_DEMOSAICV3_0_LEN 4
+#define V40_DEMOSAICV3_1_OFF 0x00000518
+#define V40_DEMOSAICV3_1_LEN 88
+#define V40_DEMOSAICV3_2_OFF 0x00000568
+#define V40_DEMOSAICV3_UP_REG_CNT 5
+
+#define V40_OUT_CLAMP_OFF 0x00000874
+#define V40_OUT_CLAMP_LEN 16
+
+#define V40_OPERATION_CFG_LEN 44
+
+#define V40_AXI_OUT_OFF 0x0000004C
+#define V40_AXI_OUT_LEN 412
+#define V40_AXI_CH_INF_LEN 32
+#define V40_AXI_CFG_LEN 71
+
+#define V40_FOV_ENC_OFF 0x00000854
+#define V40_FOV_ENC_LEN 16
+#define V40_FOV_VIEW_OFF 0x00000864
+#define V40_FOV_VIEW_LEN 16
+
+#define V40_SCALER_ENC_OFF 0x0000075C
+#define V40_SCALER_ENC_LEN 72
+
+#define V40_SCALER_VIEW_OFF 0x000007A4
+#define V40_SCALER_VIEW_LEN 72
+
+#define V40_COLORXFORM_ENC_CFG_OFF 0x0000071C
+#define V40_COLORXFORM_ENC_CFG_LEN 32
+
+#define V40_COLORXFORM_VIEW_CFG_OFF 0x0000073C
+#define V40_COLORXFORM_VIEW_CFG_LEN 32
+
+#define V40_CHROMA_EN_OFF 0x00000640
+#define V40_CHROMA_EN_LEN 36
+
+#define V40_SYNC_TIMER_OFF 0x00000324
+#define V40_SYNC_TIMER_POLARITY_OFF 0x0000034C
+#define V40_TIMER_SELECT_OFF 0x00000374
+#define V40_SYNC_TIMER_LEN 28
+
+#define V40_ASYNC_TIMER_OFF 0x00000350
+#define V40_ASYNC_TIMER_LEN 28
+
+/* use 10x13 mesh table in vfe40*/
+#define V40_MESH_ROLL_OFF_CFG_OFF 0x00000400
+#define V40_MESH_ROLL_OFF_CFG_LEN 36
+#define V40_MESH_ROLL_OFF_TABLE_SIZE 130
+
+
+#define V40_COLOR_COR_OFF 0x000005D0
+#define V40_COLOR_COR_LEN 52
+
+#define V40_WB_OFF 0x00000580
+#define V40_WB_LEN 4
+
+#define V40_RGB_G_OFF 0x00000638
+#define V40_RGB_G_LEN 4
+#define V40_GAMMA_LUT_BANK_SEL_MASK 0x00000007
+
+#define V40_LA_OFF 0x0000063C
+#define V40_LA_LEN 4
+
+#define V40_SCE_OFF 0x00000694
+#define V40_SCE_LEN 136
+
+#define V40_CHROMA_SUP_OFF 0x00000664
+#define V40_CHROMA_SUP_LEN 12
+
+#define V40_MCE_OFF 0x00000670
+#define V40_MCE_LEN 36
+
+#define V40_STATS_BE_OFF 0x0000088C
+#define V40_STATS_BE_LEN 12
+
+#define V40_STATS_BG_OFF 0x00000898
+#define V40_STATS_BG_LEN 12
+
+#define V40_STATS_BF_OFF 0x000008A4
+#define V40_STATS_BF_LEN 24
+
+#define V40_STATS_BHIST_OFF 0x000008BC
+#define V40_STATS_BHIST_LEN 8
+
+#define V40_STATS_AWB_OFF 0x000008C4
+#define V40_STATS_AWB_LEN 32
+
+#define V40_STATS_RS_OFF 0x000008E4
+#define V40_STATS_RS_LEN 8
+
+#define V40_STATS_CS_OFF 0x000008EC
+#define V40_STATS_CS_LEN 8
+
+#define V40_STATS_IHIST_OFF 0x000008F4
+#define V40_STATS_IHIST_LEN 8
+
+#define V40_STATS_SKIN_OFF 0x000008FC
+#define V40_STATS_SKIN_LEN 20
+
+#define V40_ASF_OFF 0x000007EC
+#define V40_ASF_LEN 48
+#define V40_ASF_UPDATE_LEN 36
+
+#define V40_CAPTURE_LEN 4
+
+#define V40_GET_HW_VERSION_OFF 0
+#define V40_GET_HW_VERSION_LEN 4
+
+#define V40_LINEARIZATION_OFF1 0x0000037C
+#define V40_LINEARIZATION_LEN1 68
+
+#define V40_DEMOSAICV3_DBPC_CFG_OFF 0x00000444
+#define V40_DEMOSAICV3_DBPC_LEN 4
+
+#define V40_DEMOSAICV3_DBPC_CFG_OFF0 0x00000448
+#define V40_DEMOSAICV3_DBPC_CFG_OFF1 0x0000044C
+#define V40_DEMOSAICV3_DBPC_CFG_OFF2 0x00000450
+
+#define V40_DEMOSAICV3_DBCC_OFF 0x00000454
+#define V40_DEMOSAICV3_DBCC_LEN 16
+
+#define V40_DEMOSAICV3_ABF_OFF 0x00000464
+#define V40_DEMOSAICV3_ABF_LEN 180
+
+#define V40_MODULE_CFG_OFF 0x00000018
+#define V40_MODULE_CFG_LEN 4
+
+#define V40_ASF_SPECIAL_EFX_CFG_OFF 0x0000081C
+#define V40_ASF_SPECIAL_EFX_CFG_LEN 4
+
+#define V40_CLF_CFG_OFF 0x00000588
+#define V40_CLF_CFG_LEN 72
+
+#define V40_CLF_LUMA_UPDATE_OFF 0x0000058C
+#define V40_CLF_LUMA_UPDATE_LEN 60
+
+#define V40_CLF_CHROMA_UPDATE_OFF 0x000005C8
+#define V40_CLF_CHROMA_UPDATE_LEN 8
+
+#define VFE40_GAMMA_NUM_ENTRIES 64
+
+#define VFE40_LA_TABLE_LENGTH 64
+
+#define VFE40_LINEARIZATON_TABLE_LENGTH 36
+
+#define VFE_WM_CFG_BASE 0x0070
+#define VFE_WM_CFG_LEN 0x0024
+
+#define vfe40_get_ch_ping_addr(base, chn) \
+ (msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
+#define vfe40_get_ch_pong_addr(base, chn) \
+ (msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
+#define vfe40_get_ch_addr(ping_pong, base, chn) \
+ ((((ping_pong) & (1 << (chn))) == 0) ? \
+ (vfe40_get_ch_pong_addr((base), chn)) : \
+ (vfe40_get_ch_ping_addr((base), chn)))
+
+#define vfe40_put_ch_ping_addr(base, chn, addr) \
+ (msm_camera_io_w((addr), \
+ (base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
+#define vfe40_put_ch_pong_addr(base, chn, addr) \
+ (msm_camera_io_w((addr), \
+ (base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
+#define vfe40_put_ch_addr(ping_pong, base, chn, addr) \
+ (((ping_pong) & (1 << (chn))) == 0 ? \
+ vfe40_put_ch_pong_addr((base), (chn), (addr)) : \
+ vfe40_put_ch_ping_addr((base), (chn), (addr)))
+
+struct vfe_cmd_hw_version {
+ uint32_t minorVersion;
+ uint32_t majorVersion;
+ uint32_t coreVersion;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+ VFE_AXI_OUTPUT_MODE_Output1,
+ VFE_AXI_OUTPUT_MODE_Output2,
+ VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+ VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+ VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+ VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+ VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+ VFE_RAW_OUTPUT_DISABLED,
+ VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+ VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+ VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH 4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3
+
+struct vfe_cmds_per_write_master {
+ uint16_t imageWidth;
+ uint16_t imageHeight;
+ uint16_t outRowCount;
+ uint16_t outRowIncrement;
+ uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+ [VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+ uint8_t fragmentCount;
+ struct vfe_cmds_per_write_master firstWM;
+ struct vfe_cmds_per_write_master secondWM;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+ VFE_AXI_BURST_LENGTH_IS_2 = 2,
+ VFE_AXI_BURST_LENGTH_IS_4 = 4,
+ VFE_AXI_BURST_LENGTH_IS_8 = 8,
+ VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+
+struct vfe_cmd_fov_crop_config {
+ uint8_t enable;
+ uint16_t firstPixel;
+ uint16_t lastPixel;
+ uint16_t firstLine;
+ uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+ uint16_t MNCounterInit;
+ uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+ uint8_t enable;
+ uint16_t inputSize;
+ uint16_t outputSize;
+ uint32_t phaseMultiplicationFactor;
+ uint8_t interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+ uint8_t enable;
+ struct vfe_cmds_scaler_one_dimension hconfig;
+ struct vfe_cmds_scaler_one_dimension vconfig;
+ struct vfe_cmds_main_scaler_stripe_init MNInitH;
+ struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+ uint8_t enable;
+ struct vfe_cmds_scaler_one_dimension hconfig;
+ struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+
+struct vfe_cmd_frame_skip_update {
+ uint32_t output1Pattern;
+ uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+ uint8_t minCh0;
+ uint8_t minCh1;
+ uint8_t minCh2;
+ uint8_t maxCh0;
+ uint8_t maxCh1;
+ uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+ uint8_t enable;
+ uint8_t cropEnable;
+ uint8_t vsubSampleEnable;
+ uint8_t hsubSampleEnable;
+ uint8_t vCosited;
+ uint8_t hCosited;
+ uint8_t vCositedPhase;
+ uint8_t hCositedPhase;
+ uint16_t cropWidthFirstPixel;
+ uint16_t cropWidthLastPixel;
+ uint16_t cropHeightFirstLine;
+ uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_PIXEL_PATTERN {
+ VFE_BAYER_RGRGRG,
+ VFE_BAYER_GRGRGR,
+ VFE_BAYER_BGBGBG,
+ VFE_BAYER_GBGBGB,
+ VFE_YUV_YCbYCr,
+ VFE_YUV_YCrYCb,
+ VFE_YUV_CbYCrY,
+ VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+ VFE_BAYER_RAW,
+ VFE_YUV_INTERLEAVED,
+ VFE_YUV_PSEUDO_PLANAR_Y,
+ VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+ VFE_YUV_COSITED,
+ VFE_YUV_INTERPOLATED
+};
+
+struct vfe_cmds_demosaic_abf {
+ uint8_t enable;
+ uint8_t forceOn;
+ uint8_t shift;
+ uint16_t lpThreshold;
+ uint16_t max;
+ uint16_t min;
+ uint8_t ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+ uint8_t enable;
+ uint16_t fmaxThreshold;
+ uint16_t fminThreshold;
+ uint16_t redDiffThreshold;
+ uint16_t blueDiffThreshold;
+ uint16_t greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+ uint8_t enable;
+ uint8_t slopeShift;
+ struct vfe_cmds_demosaic_abf abfConfig;
+ struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+ struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+ struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+ uint8_t enable;
+ uint16_t ch2Gain;
+ uint16_t ch1Gain;
+ uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+ COEF_IS_Q7_SIGNED,
+ COEF_IS_Q8_SIGNED,
+ COEF_IS_Q9_SIGNED,
+ COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+ uint8_t enable;
+ enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+ int16_t C0;
+ int16_t C1;
+ int16_t C2;
+ int16_t C3;
+ int16_t C4;
+ int16_t C5;
+ int16_t C6;
+ int16_t C7;
+ int16_t C8;
+ int16_t K0;
+ int16_t K1;
+ int16_t K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 64
+
+struct vfe_cmd_la_config {
+ uint8_t enable;
+ int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+ RGB_GAMMA_CH0_SELECTED,
+ RGB_GAMMA_CH1_SELECTED,
+ RGB_GAMMA_CH2_SELECTED,
+ RGB_GAMMA_CH0_CH1_SELECTED,
+ RGB_GAMMA_CH0_CH2_SELECTED,
+ RGB_GAMMA_CH1_CH2_SELECTED,
+ RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+ uint8_t enable;
+ enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+ int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+ uint8_t enable;
+ int16_t am;
+ int16_t ap;
+ int16_t bm;
+ int16_t bp;
+ int16_t cm;
+ int16_t cp;
+ int16_t dm;
+ int16_t dp;
+ int16_t kcr;
+ int16_t kcb;
+ int16_t RGBtoYConversionV0;
+ int16_t RGBtoYConversionV1;
+ int16_t RGBtoYConversionV2;
+ uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+ uint8_t enable;
+ uint8_t m1;
+ uint8_t m3;
+ uint8_t n1;
+ uint8_t n3;
+ uint8_t nn1;
+ uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+ uint8_t enable;
+ uint8_t smoothFilterEnabled;
+ uint8_t sharpMode;
+ uint8_t smoothCoefCenter;
+ uint8_t smoothCoefSurr;
+ uint8_t normalizeFactor;
+ uint8_t sharpK1;
+ uint8_t sharpK2;
+ uint8_t sharpThreshE1;
+ int8_t sharpThreshE2;
+ int8_t sharpThreshE3;
+ int8_t sharpThreshE4;
+ int8_t sharpThreshE5;
+ int8_t filter1Coefficients[9];
+ int8_t filter2Coefficients[9];
+ uint8_t cropEnable;
+ uint16_t cropFirstPixel;
+ uint16_t cropLastPixel;
+ uint16_t cropFirstLine;
+ uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+ uint8_t enable;
+ uint8_t smoothFilterEnabled;
+ uint8_t sharpMode;
+ uint8_t smoothCoefCenter;
+ uint8_t smoothCoefSurr;
+ uint8_t normalizeFactor;
+ uint8_t sharpK1;
+ uint8_t sharpK2;
+ uint8_t sharpThreshE1;
+ int8_t sharpThreshE2;
+ int8_t sharpThreshE3;
+ int8_t sharpThreshE4;
+ int8_t sharpThreshE5;
+ int8_t filter1Coefficients[9];
+ int8_t filter2Coefficients[9];
+ uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+ VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+ VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+
+struct vfe_cmd_bus_pm_start {
+ uint8_t output2YWrPmEnable;
+ uint8_t output2CbcrWrPmEnable;
+ uint8_t output1YWrPmEnable;
+ uint8_t output1CbcrWrPmEnable;
+};
+
+struct vfe_frame_skip_counts {
+ uint32_t totalFrameCount;
+ uint32_t output1Count;
+ uint32_t output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+ VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+struct vfe_frame_bpc_info {
+ uint32_t greenDefectPixelCount;
+ uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+ uint32_t asfMaxEdge;
+ uint32_t asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+ uint8_t camifState;
+ uint32_t pixelCount;
+ uint32_t lineCount;
+};
+
+struct vfe40_irq_status {
+ uint32_t vfeIrqStatus0;
+ uint32_t vfeIrqStatus1;
+ uint32_t camifStatus;
+ uint32_t demosaicStatus;
+ uint32_t asfMaxEdge;
+};
+
+#define V40_PREVIEW_AXI_FLAG 0x00000001
+#define V40_SNAPSHOT_AXI_FLAG (0x00000001<<1)
+
+struct vfe40_cmd_type {
+ uint16_t id;
+ uint32_t length;
+ uint32_t offset;
+ uint32_t flag;
+};
+
+struct vfe40_free_buf {
+ struct list_head node;
+ uint32_t paddr;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+};
+
+struct vfe40_output_ch {
+ struct list_head free_buf_queue;
+ spinlock_t free_buf_lock;
+ uint16_t image_mode;
+ int8_t ch0;
+ int8_t ch1;
+ int8_t ch2;
+ uint32_t capture_cnt;
+ uint32_t frame_drop_cnt;
+ struct msm_free_buf ping;
+ struct msm_free_buf pong;
+ struct msm_free_buf free_buf;
+};
+
+/* no error irq in mask 0 */
+#define VFE40_IMASK_ERROR_ONLY_0 0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE40_IMASK_ERROR_ONLY_1 0x005FFFFF
+#define VFE40_IMASK_CAMIF_ERROR (0x00000001<<0)
+#define VFE40_IMASK_BHIST_OVWR (0x00000001<<1)
+#define VFE40_IMASK_STATS_CS_OVWR (0x00000001<<2)
+#define VFE40_IMASK_STATS_IHIST_OVWR (0x00000001<<3)
+#define VFE40_IMASK_REALIGN_BUF_Y_OVFL (0x00000001<<4)
+#define VFE40_IMASK_REALIGN_BUF_CB_OVFL (0x00000001<<5)
+#define VFE40_IMASK_REALIGN_BUF_CR_OVFL (0x00000001<<6)
+#define VFE40_IMASK_VIOLATION (0x00000001<<7)
+#define VFE40_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<8)
+#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<9)
+#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<10)
+#define VFE40_IMASK_IMG_MAST_3_BUS_OVFL (0x00000001<<11)
+#define VFE40_IMASK_IMG_MAST_4_BUS_OVFL (0x00000001<<12)
+#define VFE40_IMASK_IMG_MAST_5_BUS_OVFL (0x00000001<<13)
+#define VFE40_IMASK_IMG_MAST_6_BUS_OVFL (0x00000001<<14)
+#define VFE40_IMASK_STATS_AE_BG_BUS_OVFL (0x00000001<<15)
+#define VFE40_IMASK_STATS_AF_BF_BUS_OVFL (0x00000001<<16)
+#define VFE40_IMASK_STATS_AWB_BUS_OVFL (0x00000001<<17)
+#define VFE40_IMASK_STATS_RS_BUS_OVFL (0x00000001<<18)
+#define VFE40_IMASK_STATS_CS_BUS_OVFL (0x00000001<<19)
+#define VFE40_IMASK_STATS_IHIST_BUS_OVFL (0x00000001<<20)
+#define VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<21)
+#define VFE40_IMASK_AXI_ERROR (0x00000001<<22)
+
+#define VFE_COM_STATUS 0x000FE000
+
+struct vfe40_output_path {
+ uint16_t output_mode; /* bitmask */
+
+ struct vfe40_output_ch out0; /* preview and thumbnail */
+ struct vfe40_output_ch out1; /* snapshot */
+ struct vfe40_output_ch out2; /* video */
+};
+
+struct vfe40_frame_extra {
+ uint32_t greenDefectPixelCount;
+ uint32_t redBlueDefectPixelCount;
+
+ uint32_t asfMaxEdge;
+ uint32_t asfHbiCount;
+
+ uint32_t yWrPmStats0;
+ uint32_t yWrPmStats1;
+ uint32_t cbcrWrPmStats0;
+ uint32_t cbcrWrPmStats1;
+
+ uint32_t frameCounter;
+};
+
+#define VFE_CLEAR_ALL_IRQS 0xffffffff
+
+#define VFE_HW_VERSION 0x00000000
+#define VFE_GLOBAL_RESET 0x0000000C
+#define VFE_MODULE_RESET 0x00000010
+#define VFE_CGC_OVERRIDE 0x00000014
+#define VFE_MODULE_CFG 0x00000018
+#define VFE_CFG 0x0000001C
+#define VFE_IRQ_CMD 0x00000024
+#define VFE_IRQ_MASK_0 0x00000028
+#define VFE_IRQ_MASK_1 0x0000002C
+#define VFE_IRQ_CLEAR_0 0x00000030
+#define VFE_IRQ_CLEAR_1 0x00000034
+#define VFE_IRQ_STATUS_0 0x00000038
+#define VFE_IRQ_STATUS_1 0x0000003C
+#define VFE_IRQ_COMP_MASK 0x00000040
+#define VFE_BUS_CMD 0x0000004C
+#define VFE_BUS_PING_PONG_STATUS 0x00000180
+#define VFE_AXI_CMD 0x000001D8
+#define VFE_AXI_STATUS 0x000002C0
+#define VFE_BUS_STATS_PING_PONG_BASE 0x000000F4
+
+#define VFE_BUS_STATS_AEC_WR_PING_ADDR 0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PONG_ADDR 0x000000F8
+#define VFE_BUS_STATS_AEC_UB_CFG 0x000000FC
+#define VFE_BUS_STATS_AF_WR_PING_ADDR 0x00000100
+#define VFE_BUS_STATS_AF_WR_PONG_ADDR 0x00000104
+#define VFE_BUS_STATS_AF_UB_CFG 0x00000108
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR 0x0000010C
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR 0x00000110
+#define VFE_BUS_STATS_AWB_UB_CFG 0x00000114
+#define VFE_BUS_STATS_RS_WR_PING_ADDR 0x00000118
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR 0x0000011C
+#define VFE_BUS_STATS_RS_UB_CFG 0x00000120
+#define VFE_BUS_STATS_CS_WR_PING_ADDR 0x00000124
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR 0x00000128
+#define VFE_BUS_STATS_CS_UB_CFG 0x0000012C
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR 0x00000130
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR 0x00000134
+#define VFE_BUS_STATS_HIST_UB_CFG 0x00000138
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR 0x0000013C
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR 0x00000140
+#define VFE_BUS_STATS_SKIN_UB_CFG 0x00000144
+
+#define VFE_0_BUS_BDG_QOS_CFG_0 0x000002C4
+#define VFE_0_BUS_BDG_QOS_CFG_1 0x000002C8
+#define VFE_0_BUS_BDG_QOS_CFG_2 0x000002CC
+#define VFE_0_BUS_BDG_QOS_CFG_3 0x000002D0
+#define VFE_0_BUS_BDG_QOS_CFG_4 0x000002D4
+#define VFE_0_BUS_BDG_QOS_CFG_5 0x000002D8
+#define VFE_0_BUS_BDG_QOS_CFG_6 0x000002DC
+#define VFE_0_BUS_BDG_QOS_CFG_7 0x000002E0
+
+#define VFE_CAMIF_COMMAND 0x000002F4
+#define VFE_CAMIF_STATUS 0x0000031C
+#define VFE_REG_UPDATE_CMD 0x00000378
+#define VFE_DEMUX_GAIN_0 0x00000428
+#define VFE_DEMUX_GAIN_1 0x0000042C
+#define VFE_CHROMA_UP 0x0000057C
+
+#define VFE_CLAMP_ENC_MAX 0x00000874
+#define VFE_CLAMP_ENC_MIN 0x00000878
+#define VFE_CLAMP_VIEW_MAX 0x0000087C
+#define VFE_CLAMP_VIEW_MIN 0x00000880
+
+#define VFE_REALIGN_BUF 0x00000884
+#define VFE_STATS_CFG 0x00000888
+#define VFE_STATS_AWB_SGW_CFG 0x000008CC
+#define VFE_DMI_CFG 0x00000910
+#define VFE_DMI_ADDR 0x00000914
+#define VFE_DMI_DATA_LO 0x0000091C
+#define VFE_BUS_IO_FORMAT_CFG 0x00000054
+#define VFE_RDI0_CFG 0x000002E8
+#define VFE_RDI1_CFG 0x000002EC
+#define VFE_RDI2_CFG 0x000002F0
+
+#define VFE_VIOLATION_STATUS 0x000007B4
+
+#define VFE40_DMI_DATA_HI 0x00000918
+#define VFE40_DMI_DATA_LO 0x0000091C
+
+#define VFE40_OUTPUT_MODE_PT BIT(0)
+#define VFE40_OUTPUT_MODE_S BIT(1)
+#define VFE40_OUTPUT_MODE_V BIT(2)
+#define VFE40_OUTPUT_MODE_P BIT(3)
+#define VFE40_OUTPUT_MODE_T BIT(4)
+#define VFE40_OUTPUT_MODE_P_ALL_CHNLS BIT(5)
+#define VFE40_OUTPUT_MODE_PRIMARY BIT(6)
+#define VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS BIT(7)
+#define VFE40_OUTPUT_MODE_SECONDARY BIT(8)
+#define VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS BIT(9)
+
+struct vfe_stats_control {
+ uint32_t droppedStatsFrameCount;
+ uint32_t bufToRender;
+};
+struct axi_ctrl_t;
+struct vfe40_ctrl_type;
+
+struct vfe_share_ctrl_t {
+ void __iomem *vfebase;
+ uint32_t register_total;
+
+ atomic_t vstate;
+ uint32_t vfeFrameId;
+ uint32_t stats_comp;
+ spinlock_t stop_flag_lock;
+ int8_t stop_ack_pending;
+ enum vfe_output_state liveshot_state;
+ uint32_t vfe_capture_count;
+
+ uint16_t operation_mode; /* streaming or snapshot */
+ struct vfe40_output_path outpath;
+
+ uint32_t ref_count;
+ spinlock_t sd_notify_lock;
+ uint32_t vfe_clk_rate;
+
+ atomic_t irq_cnt;
+ struct axi_ctrl_t *axi_ctrl;
+ struct vfe40_ctrl_type *vfe40_ctrl;
+};
+
+struct axi_ctrl_t {
+ struct v4l2_subdev subdev;
+ struct platform_device *pdev;
+ struct resource *vfeirq;
+ spinlock_t tasklet_lock;
+ struct list_head tasklet_q;
+
+ void *syncdata;
+
+ struct resource *vfemem;
+ struct resource *vfeio;
+ struct regulator *fs_vfe;
+ struct clk *vfe_clk[3];
+ struct tasklet_struct vfe40_tasklet;
+ struct vfe_share_ctrl_t *share_ctrl;
+};
+
+struct vfe40_ctrl_type {
+ uint32_t vfeImaskCompositePacked;
+
+ spinlock_t update_ack_lock;
+ spinlock_t state_lock;
+ spinlock_t io_lock;
+ spinlock_t stats_bufq_lock;
+ uint32_t extlen;
+ void *extdata;
+
+ int8_t start_ack_pending;
+ int8_t reset_ack_pending;
+ int8_t update_ack_pending;
+ enum vfe_output_state recording_state;
+ int8_t update_linear;
+ int8_t update_rolloff;
+ int8_t update_la;
+ int8_t update_gamma;
+
+ struct vfe_share_ctrl_t *share_ctrl;
+
+ uint32_t sync_timer_repeat_count;
+ uint32_t sync_timer_state;
+ uint32_t sync_timer_number;
+
+ uint32_t output1Pattern;
+ uint32_t output1Period;
+ uint32_t output2Pattern;
+ uint32_t output2Period;
+ uint32_t vfeFrameSkipCount;
+ uint32_t vfeFrameSkipPeriod;
+ struct vfe_stats_control afStatsControl;
+ struct vfe_stats_control awbStatsControl;
+ struct vfe_stats_control aecStatsControl;
+ struct vfe_stats_control ihistStatsControl;
+ struct vfe_stats_control rsStatsControl;
+ struct vfe_stats_control csStatsControl;
+
+ /* v4l2 subdev */
+ struct v4l2_subdev subdev;
+ struct platform_device *pdev;
+ uint32_t hfr_mode;
+ uint32_t frame_skip_cnt;
+ uint32_t frame_skip_pattern;
+ uint32_t snapshot_frame_cnt;
+ struct msm_stats_bufq_ctrl stats_ctrl;
+ struct msm_stats_ops stats_ops;
+};
+
+#define statsAeNum 0
+#define statsAfNum 1
+#define statsAwbNum 2
+#define statsRsNum 3
+#define statsCsNum 4
+#define statsIhistNum 5
+#define statsSkinNum 6
+
+struct vfe_cmd_stats_ack {
+ uint32_t nextStatsBuf;
+};
+
+#define VFE_STATS_BUFFER_COUNT 3
+
+struct vfe_cmd_stats_buf {
+ uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
+};
+
+void vfe40_subdev_notify(int id, int path, int image_mode,
+ struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl);
+struct vfe40_output_ch *vfe40_get_ch(
+ int path, struct vfe_share_ctrl_t *share_ctrl);
+void vfe40_send_isp_msg(struct v4l2_subdev *sd,
+ uint32_t vfeFrameId, uint32_t isp_msg_id);
+void vfe40_axi_probe(struct axi_ctrl_t *axi_ctrl);
+
+static const uint32_t vfe40_AXI_WM_CFG[] = {
+ 0x0000006C,
+ 0x00000090,
+ 0x000000B4,
+ 0x000000D8,
+ 0x000000FC,
+ 0x00000120,
+ 0x00000144,
+};
+
+static struct vfe40_cmd_type vfe40_cmd[] = {
+/*0*/
+ {VFE_CMD_DUMMY_0},
+ {VFE_CMD_SET_CLK},
+ {VFE_CMD_RESET},
+ {VFE_CMD_START},
+ {VFE_CMD_TEST_GEN_START},
+/*5*/
+ {VFE_CMD_OPERATION_CFG, V40_OPERATION_CFG_LEN},
+ {VFE_CMD_AXI_OUT_CFG, V40_AXI_OUT_LEN, V40_AXI_OUT_OFF, 0xFF},
+ {VFE_CMD_CAMIF_CFG, V40_CAMIF_LEN, V40_CAMIF_OFF, 0xFF},
+ {VFE_CMD_AXI_INPUT_CFG},
+ {VFE_CMD_BLACK_LEVEL_CFG},
+/*10*/
+ {VFE_CMD_MESH_ROLL_OFF_CFG},
+ {VFE_CMD_DEMUX_CFG, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+ {VFE_CMD_FOV_CFG},
+ {VFE_CMD_MAIN_SCALER_CFG},
+ {VFE_CMD_WB_CFG, V40_WB_LEN, V40_WB_OFF, 0xFF},
+/*15*/
+ {VFE_CMD_COLOR_COR_CFG, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF},
+ {VFE_CMD_RGB_G_CFG, V40_RGB_G_LEN, V40_RGB_G_OFF, 0xFF},
+ {VFE_CMD_LA_CFG, V40_LA_LEN, V40_LA_OFF, 0xFF },
+ {VFE_CMD_CHROMA_EN_CFG, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF},
+ {VFE_CMD_CHROMA_SUP_CFG, V40_CHROMA_SUP_LEN, V40_CHROMA_SUP_OFF, 0xFF},
+/*20*/
+ {VFE_CMD_MCE_CFG, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+ {VFE_CMD_SK_ENHAN_CFG, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+ {VFE_CMD_ASF_CFG, V40_ASF_LEN, V40_ASF_OFF, 0xFF},
+ {VFE_CMD_S2Y_CFG},
+ {VFE_CMD_S2CbCr_CFG},
+/*25*/
+ {VFE_CMD_CHROMA_SUBS_CFG},
+ {VFE_CMD_OUT_CLAMP_CFG, V40_OUT_CLAMP_LEN, V40_OUT_CLAMP_OFF, 0xFF},
+ {VFE_CMD_FRAME_SKIP_CFG},
+ {VFE_CMD_DUMMY_1},
+ {VFE_CMD_DUMMY_2},
+/*30*/
+ {VFE_CMD_DUMMY_3},
+ {VFE_CMD_UPDATE},
+ {VFE_CMD_BL_LVL_UPDATE},
+ {VFE_CMD_DEMUX_UPDATE, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+ {VFE_CMD_FOV_UPDATE},
+/*35*/
+ {VFE_CMD_MAIN_SCALER_UPDATE},
+ {VFE_CMD_WB_UPDATE, V40_WB_LEN, V40_WB_OFF, 0xFF},
+ {VFE_CMD_COLOR_COR_UPDATE, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF},
+ {VFE_CMD_RGB_G_UPDATE, V40_RGB_G_LEN, V40_CHROMA_EN_OFF, 0xFF},
+ {VFE_CMD_LA_UPDATE, V40_LA_LEN, V40_LA_OFF, 0xFF },
+/*40*/
+ {VFE_CMD_CHROMA_EN_UPDATE, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF},
+ {VFE_CMD_CHROMA_SUP_UPDATE, V40_CHROMA_SUP_LEN,
+ V40_CHROMA_SUP_OFF, 0xFF},
+ {VFE_CMD_MCE_UPDATE, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+ {VFE_CMD_SK_ENHAN_UPDATE, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+ {VFE_CMD_S2CbCr_UPDATE},
+/*45*/
+ {VFE_CMD_S2Y_UPDATE},
+ {VFE_CMD_ASF_UPDATE, V40_ASF_UPDATE_LEN, V40_ASF_OFF, 0xFF},
+ {VFE_CMD_FRAME_SKIP_UPDATE},
+ {VFE_CMD_CAMIF_FRAME_UPDATE},
+ {VFE_CMD_STATS_AF_UPDATE},
+/*50*/
+ {VFE_CMD_STATS_AE_UPDATE},
+ {VFE_CMD_STATS_AWB_UPDATE, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
+ {VFE_CMD_STATS_RS_UPDATE, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+ {VFE_CMD_STATS_CS_UPDATE, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+ {VFE_CMD_STATS_SKIN_UPDATE},
+/*55*/
+ {VFE_CMD_STATS_IHIST_UPDATE, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
+ {VFE_CMD_DUMMY_4},
+ {VFE_CMD_EPOCH1_ACK},
+ {VFE_CMD_EPOCH2_ACK},
+ {VFE_CMD_START_RECORDING},
+/*60*/
+ {VFE_CMD_STOP_RECORDING},
+ {VFE_CMD_DUMMY_5},
+ {VFE_CMD_DUMMY_6},
+ {VFE_CMD_CAPTURE, V40_CAPTURE_LEN, 0xFF},
+ {VFE_CMD_DUMMY_7},
+/*65*/
+ {VFE_CMD_STOP},
+ {VFE_CMD_GET_HW_VERSION, V40_GET_HW_VERSION_LEN,
+ V40_GET_HW_VERSION_OFF},
+ {VFE_CMD_GET_FRAME_SKIP_COUNTS},
+ {VFE_CMD_OUTPUT1_BUFFER_ENQ},
+ {VFE_CMD_OUTPUT2_BUFFER_ENQ},
+/*70*/
+ {VFE_CMD_OUTPUT3_BUFFER_ENQ},
+ {VFE_CMD_JPEG_OUT_BUF_ENQ},
+ {VFE_CMD_RAW_OUT_BUF_ENQ},
+ {VFE_CMD_RAW_IN_BUF_ENQ},
+ {VFE_CMD_STATS_AF_ENQ},
+/*75*/
+ {VFE_CMD_STATS_AE_ENQ},
+ {VFE_CMD_STATS_AWB_ENQ},
+ {VFE_CMD_STATS_RS_ENQ},
+ {VFE_CMD_STATS_CS_ENQ},
+ {VFE_CMD_STATS_SKIN_ENQ},
+/*80*/
+ {VFE_CMD_STATS_IHIST_ENQ},
+ {VFE_CMD_DUMMY_8},
+ {VFE_CMD_JPEG_ENC_CFG},
+ {VFE_CMD_DUMMY_9},
+ {VFE_CMD_STATS_AF_START},
+/*85*/
+ {VFE_CMD_STATS_AF_STOP},
+ {VFE_CMD_STATS_AE_START},
+ {VFE_CMD_STATS_AE_STOP},
+ {VFE_CMD_STATS_AWB_START, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
+ {VFE_CMD_STATS_AWB_STOP},
+/*90*/
+ {VFE_CMD_STATS_RS_START, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+ {VFE_CMD_STATS_RS_STOP},
+ {VFE_CMD_STATS_CS_START, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+ {VFE_CMD_STATS_CS_STOP},
+ {VFE_CMD_STATS_SKIN_START},
+/*95*/
+ {VFE_CMD_STATS_SKIN_STOP},
+ {VFE_CMD_STATS_IHIST_START, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
+ {VFE_CMD_STATS_IHIST_STOP},
+ {VFE_CMD_DUMMY_10},
+ {VFE_CMD_SYNC_TIMER_SETTING, V40_SYNC_TIMER_LEN, V40_SYNC_TIMER_OFF},
+/*100*/
+ {VFE_CMD_ASYNC_TIMER_SETTING, V40_ASYNC_TIMER_LEN, V40_ASYNC_TIMER_OFF},
+ {VFE_CMD_LIVESHOT},
+ {VFE_CMD_LA_SETUP},
+ {VFE_CMD_LINEARIZATION_CFG, V40_LINEARIZATION_LEN1,
+ V40_LINEARIZATION_OFF1},
+ {VFE_CMD_DEMOSAICV3},
+/*105*/
+ {VFE_CMD_DEMOSAICV3_ABCC_CFG},
+ {VFE_CMD_DEMOSAICV3_DBCC_CFG, V40_DEMOSAICV3_DBCC_LEN,
+ V40_DEMOSAICV3_DBCC_OFF},
+ {VFE_CMD_DEMOSAICV3_DBPC_CFG},
+ {VFE_CMD_DEMOSAICV3_ABF_CFG, V40_DEMOSAICV3_ABF_LEN,
+ V40_DEMOSAICV3_ABF_OFF},
+ {VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
+/*110*/
+ {VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V40_DEMOSAICV3_DBCC_LEN,
+ V40_DEMOSAICV3_DBCC_OFF},
+ {VFE_CMD_DEMOSAICV3_DBPC_UPDATE},
+ {VFE_CMD_XBAR_CFG},
+ {VFE_CMD_MODULE_CFG, V40_MODULE_CFG_LEN, V40_MODULE_CFG_OFF},
+ {VFE_CMD_ZSL},
+/*115*/
+ {VFE_CMD_LINEARIZATION_UPDATE, V40_LINEARIZATION_LEN1,
+ V40_LINEARIZATION_OFF1},
+ {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V40_DEMOSAICV3_ABF_LEN,
+ V40_DEMOSAICV3_ABF_OFF},
+ {VFE_CMD_CLF_CFG, V40_CLF_CFG_LEN, V40_CLF_CFG_OFF},
+ {VFE_CMD_CLF_LUMA_UPDATE, V40_CLF_LUMA_UPDATE_LEN,
+ V40_CLF_LUMA_UPDATE_OFF},
+ {VFE_CMD_CLF_CHROMA_UPDATE, V40_CLF_CHROMA_UPDATE_LEN,
+ V40_CLF_CHROMA_UPDATE_OFF},
+/*120*/
+ {VFE_CMD_PCA_ROLL_OFF_CFG},
+ {VFE_CMD_PCA_ROLL_OFF_UPDATE},
+ {VFE_CMD_GET_REG_DUMP},
+ {VFE_CMD_GET_LINEARIZATON_TABLE},
+ {VFE_CMD_GET_MESH_ROLLOFF_TABLE},
+/*125*/
+ {VFE_CMD_GET_PCA_ROLLOFF_TABLE},
+ {VFE_CMD_GET_RGB_G_TABLE},
+ {VFE_CMD_GET_LA_TABLE},
+ {VFE_CMD_DEMOSAICV3_UPDATE},
+ {VFE_CMD_ACTIVE_REGION_CFG},
+/*130*/
+ {VFE_CMD_COLOR_PROCESSING_CONFIG},
+ {VFE_CMD_STATS_WB_AEC_CONFIG},
+ {VFE_CMD_STATS_WB_AEC_UPDATE},
+ {VFE_CMD_Y_GAMMA_CONFIG},
+ {VFE_CMD_SCALE_OUTPUT1_CONFIG},
+/*135*/
+ {VFE_CMD_SCALE_OUTPUT2_CONFIG},
+ {VFE_CMD_CAPTURE_RAW},
+ {VFE_CMD_STOP_LIVESHOT},
+ {VFE_CMD_RECONFIG_VFE},
+ {VFE_CMD_STATS_REQBUF},
+/*140*/
+ {VFE_CMD_STATS_ENQUEUEBUF},
+ {VFE_CMD_STATS_FLUSH_BUFQ},
+ {VFE_CMD_FOV_ENC_CFG, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF},
+ {VFE_CMD_FOV_VIEW_CFG, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF},
+ {VFE_CMD_FOV_ENC_UPDATE, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF},
+/*145*/
+ {VFE_CMD_FOV_VIEW_UPDATE, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF},
+ {VFE_CMD_SCALER_ENC_CFG, V40_SCALER_ENC_LEN, V40_SCALER_ENC_OFF, 0xFF},
+ {VFE_CMD_SCALER_VIEW_CFG, V40_SCALER_VIEW_LEN,
+ V40_SCALER_VIEW_OFF, 0xFF},
+ {VFE_CMD_SCALER_ENC_UPDATE, V40_SCALER_ENC_LEN,
+ V40_SCALER_ENC_OFF, 0xFF},
+ {VFE_CMD_SCALER_VIEW_UPDATE, V40_SCALER_VIEW_LEN,
+ V40_SCALER_VIEW_OFF, 0xFF},
+/*150*/
+ {VFE_CMD_COLORXFORM_ENC_CFG, V40_COLORXFORM_ENC_CFG_LEN,
+ V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+ {VFE_CMD_COLORXFORM_VIEW_CFG, V40_COLORXFORM_VIEW_CFG_LEN,
+ V40_COLORXFORM_VIEW_CFG_OFF},
+ {VFE_CMD_COLORXFORM_ENC_UPDATE, V40_COLORXFORM_ENC_CFG_LEN,
+ V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+ {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
+ V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
+};
+
+#endif /* __MSM_VFE40_H__ */
diff --git a/drivers/media/video/msm/vfe/msm_vfe40_axi.c b/drivers/media/video/msm/vfe/msm_vfe40_axi.c
new file mode 100644
index 0000000..35d5207
--- /dev/null
+++ b/drivers/media/video/msm/vfe/msm_vfe40_axi.c
@@ -0,0 +1,812 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+
+#include "msm.h"
+#include "msm_vfe40.h"
+
+static int msm_axi_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+ u32 freq, u32 flags)
+{
+ int rc = 0;
+ int round_rate;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+
+ round_rate = clk_round_rate(axi_ctrl->vfe_clk[0], freq);
+ if (rc < 0) {
+ pr_err("%s: clk_round_rate failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ axi_ctrl->share_ctrl->vfe_clk_rate = round_rate;
+ rc = clk_set_rate(axi_ctrl->vfe_clk[0], round_rate);
+ if (rc < 0)
+ pr_err("%s: clk_set_rate failed %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+void axi_start(struct axi_ctrl_t *axi_ctrl)
+{
+ switch (axi_ctrl->share_ctrl->operation_mode) {
+ case VFE_OUTPUTS_PREVIEW:
+ case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch2]);
+ }
+ break;
+ default:
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch2]);
+ }
+ break;
+ }
+}
+
+void axi_stop(struct axi_ctrl_t *axi_ctrl)
+{
+ uint8_t axiBusyFlag = true;
+ /* axi halt command. */
+ msm_camera_io_w(AXI_HALT,
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+ wmb();
+ while (axiBusyFlag) {
+ if (msm_camera_io_r(
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+ axiBusyFlag = false;
+ }
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(AXI_HALT_CLEAR,
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+
+ /* after axi halt, then ok to apply global reset. */
+ /* enable reset_ack and async timer interrupt only while
+ stopping the pipeline.*/
+ msm_camera_io_w(0xf0000000,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+ axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static int vfe40_config_axi(
+ struct axi_ctrl_t *axi_ctrl, int mode, uint32_t *ao)
+{
+ uint32_t *ch_info;
+ uint32_t *axi_cfg = ao;
+
+ /* Update the corresponding write masters for each output*/
+ ch_info = axi_cfg + V40_AXI_CFG_LEN;
+ axi_ctrl->share_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out0.ch1 =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out0.image_mode =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out1.ch1 =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out1.image_mode =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out2.ch1 =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+
+ switch (mode) {
+ case OUTPUT_PRIM:
+ axi_ctrl->share_ctrl->outpath.output_mode =
+ VFE40_OUTPUT_MODE_PRIMARY;
+ break;
+ case OUTPUT_PRIM_ALL_CHNLS:
+ axi_ctrl->share_ctrl->outpath.output_mode =
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ break;
+ case OUTPUT_PRIM|OUTPUT_SEC:
+ axi_ctrl->share_ctrl->outpath.output_mode =
+ VFE40_OUTPUT_MODE_PRIMARY;
+ axi_ctrl->share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_SECONDARY;
+ break;
+ case OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS:
+ axi_ctrl->share_ctrl->outpath.output_mode =
+ VFE40_OUTPUT_MODE_PRIMARY;
+ axi_ctrl->share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+ break;
+ case OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC:
+ axi_ctrl->share_ctrl->outpath.output_mode =
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ axi_ctrl->share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_SECONDARY;
+ break;
+ default:
+ pr_err("%s Invalid AXI mode %d ", __func__, mode);
+ return -EINVAL;
+ }
+ msm_camera_io_w(*ao, axi_ctrl->share_ctrl->vfebase +
+ VFE_BUS_IO_FORMAT_CFG);
+ msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length - V40_AXI_CH_INF_LEN);
+ return 0;
+}
+
+static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
+{
+ struct msm_vfe_cfg_cmd cfgcmd;
+ struct msm_isp_cmd vfecmd;
+ int rc = 0;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return -EFAULT;
+ }
+ if (NULL != arg) {
+ if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ }
+ if (NULL != cfgcmd.value) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cfgcmd.value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n", __func__,
+ __LINE__);
+ return -EFAULT;
+ }
+ }
+
+ switch (cfgcmd.cmd_type) {
+ case CMD_AXI_CFG_PRIM: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe40_config_axi(axi_ctrl, OUTPUT_PRIM, axio);
+ kfree(axio);
+ }
+ break;
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe40_config_axi(axi_ctrl, OUTPUT_PRIM_ALL_CHNLS, axio);
+ kfree(axio);
+ }
+ break;
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe40_config_axi(axi_ctrl, OUTPUT_PRIM|OUTPUT_SEC, axio);
+ kfree(axio);
+ }
+ break;
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe40_config_axi(axi_ctrl,
+ OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
+ kfree(axio);
+ }
+ break;
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe40_config_axi(axi_ctrl,
+ OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
+ kfree(axio);
+ }
+ break;
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS:
+ pr_err("%s Invalid/Unsupported AXI configuration %x",
+ __func__, cfgcmd.cmd_type);
+ break;
+ case CMD_AXI_START:
+ axi_start(axi_ctrl);
+ break;
+ case CMD_AXI_STOP:
+ axi_stop(axi_ctrl);
+ break;
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cfgcmd.cmd_type);
+ break;
+ }
+ return rc;
+}
+
+static struct msm_free_buf *vfe40_check_free_buffer(
+ int id, int path, struct axi_ctrl_t *axi_ctrl)
+{
+ struct vfe40_output_ch *outch = NULL;
+ struct msm_free_buf *b = NULL;
+ uint32_t image_mode = 0;
+
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ image_mode = axi_ctrl->share_ctrl->outpath.out0.image_mode;
+ else
+ image_mode = axi_ctrl->share_ctrl->outpath.out1.image_mode;
+
+ vfe40_subdev_notify(id, path, image_mode,
+ &axi_ctrl->subdev, axi_ctrl->share_ctrl);
+ outch = vfe40_get_ch(path, axi_ctrl->share_ctrl);
+ if (outch->free_buf.ch_paddr[0])
+ b = &outch->free_buf;
+ return b;
+}
+
+static void vfe_send_outmsg(
+ struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
+ uint32_t ch0_paddr, uint32_t ch1_paddr,
+ uint32_t ch2_paddr, uint32_t image_mode)
+{
+ struct isp_msg_output msg;
+
+ msg.output_id = msgid;
+ msg.buf.image_mode = image_mode;
+ msg.buf.ch_paddr[0] = ch0_paddr;
+ msg.buf.ch_paddr[1] = ch1_paddr;
+ msg.buf.ch_paddr[2] = ch2_paddr;
+ msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_MSG_OUT,
+ &msg);
+ return;
+}
+
+static void vfe40_process_output_path_irq_0(
+ struct axi_ctrl_t *axi_ctrl)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+ uint8_t out_bool = 0;
+ struct msm_free_buf *free_buf = NULL;
+
+ free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+
+ /* we render frames in the following conditions:
+ 1. Continuous mode and the free buffer is avaialable.
+ 2. In snapshot shot mode, free buffer is not always available.
+ when pending snapshot count is <=1, then no need to use
+ free buffer.
+ */
+ out_bool = (
+ (axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STARTED ||
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOP_REQUESTED ||
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOPPED) &&
+ (axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+ free_buf;
+
+ if (out_bool) {
+ ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Channel 0*/
+ ch0_paddr = vfe40_get_ch_addr(
+ ping_pong, axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch0);
+ /* Channel 1*/
+ ch1_paddr = vfe40_get_ch_addr(
+ ping_pong, axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch1);
+ /* Channel 2*/
+ ch2_paddr = vfe40_get_ch_addr(
+ ping_pong, axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch2);
+
+ CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ ch0_paddr, ch1_paddr, ch2_paddr);
+ if (free_buf) {
+ /* Y channel */
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch0,
+ free_buf->ch_paddr[0]);
+ /* Chroma channel */
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch1,
+ free_buf->ch_paddr[1]);
+ if (free_buf->num_planes > 2)
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch2,
+ free_buf->ch_paddr[2]);
+ }
+ if (axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOPPED)
+ axi_ctrl->share_ctrl->outpath.out0.capture_cnt--;
+
+ vfe_send_outmsg(axi_ctrl,
+ MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
+ ch1_paddr, ch2_paddr,
+ axi_ctrl->share_ctrl->outpath.out0.image_mode);
+
+ if (axi_ctrl->share_ctrl->liveshot_state == VFE_STATE_STOPPED)
+ axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+ } else {
+ axi_ctrl->share_ctrl->outpath.out0.frame_drop_cnt++;
+ CDBG("path_irq_0 - no free buffer!\n");
+ }
+}
+
+static void vfe40_process_output_path_irq_1(
+ struct axi_ctrl_t *axi_ctrl)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+ /* this must be snapshot main image output. */
+ uint8_t out_bool = 0;
+ struct msm_free_buf *free_buf = NULL;
+
+ free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
+ out_bool = ((axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB) &&
+ (axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+ free_buf;
+
+ if (out_bool) {
+ ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Y channel */
+ ch0_paddr = vfe40_get_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch0);
+ /* Chroma channel */
+ ch1_paddr = vfe40_get_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch1);
+ ch2_paddr = vfe40_get_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch2);
+
+ CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ __func__, ch0_paddr, ch1_paddr, ch2_paddr);
+ if (free_buf) {
+ /* Y channel */
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch0,
+ free_buf->ch_paddr[0]);
+ /* Chroma channel */
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch1,
+ free_buf->ch_paddr[1]);
+ if (free_buf->num_planes > 2)
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch2,
+ free_buf->ch_paddr[2]);
+ }
+ if (axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB)
+ axi_ctrl->share_ctrl->outpath.out1.capture_cnt--;
+
+ vfe_send_outmsg(axi_ctrl,
+ MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
+ ch1_paddr, ch2_paddr,
+ axi_ctrl->share_ctrl->outpath.out1.image_mode);
+
+ } else {
+ axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
+ CDBG("path_irq_1 - no free buffer!\n");
+ }
+}
+
+static void msm_axi_process_irq(struct v4l2_subdev *sd, void *arg)
+{
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ uint32_t irqstatus = (uint32_t) arg;
+
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return;
+ }
+ /* next, check output path related interrupts. */
+ if (irqstatus &
+ VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+ CDBG("Image composite done 0 irq occured.\n");
+ vfe40_process_output_path_irq_0(axi_ctrl);
+ }
+ if (irqstatus &
+ VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+ CDBG("Image composite done 1 irq occured.\n");
+ vfe40_process_output_path_irq_1(axi_ctrl);
+ }
+ /* in snapshot mode if done then send
+ snapshot done message */
+ if (axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW) {
+ if ((axi_ctrl->share_ctrl->outpath.out0.capture_cnt == 0)
+ && (axi_ctrl->share_ctrl->outpath.out1.
+ capture_cnt == 0)) {
+ msm_camera_io_w_mb(
+ CAMIF_COMMAND_STOP_IMMEDIATELY,
+ axi_ctrl->share_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
+ vfe40_send_isp_msg(&axi_ctrl->subdev,
+ axi_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_SNAPSHOT_DONE);
+ }
+ }
+}
+
+static int msm_axi_buf_cfg(struct v4l2_subdev *sd, void __user *arg)
+{
+ struct msm_camvfe_params *vfe_params =
+ (struct msm_camvfe_params *)arg;
+ struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ void *data = vfe_params->data;
+ int rc = 0;
+
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return -EFAULT;
+ }
+
+ switch (cmd->cmd_type) {
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe40_output_ch *outch =
+ vfe40_get_ch(path, axi_ctrl->share_ctrl);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe40_output_ch *outch =
+ vfe40_get_ch(path, axi_ctrl->share_ctrl);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe40_output_ch *outch =
+ vfe40_get_ch(path, axi_ctrl->share_ctrl);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
+ break;
+ default:
+ pr_err("%s Unsupported AXI Buf config %x ", __func__,
+ cmd->cmd_type);
+ }
+ return rc;
+};
+
+static struct msm_cam_clk_info vfe40_clk_info[] = {
+ {"vfe_clk_src", 266670000},
+ {"camss_vfe_vfe_clk", -1},
+ {"camss_csi_vfe_clk", -1},
+ {"top_clk", -1},
+ {"iface_clk", -1},
+ {"bus_clk", -1},
+};
+
+int msm_axi_subdev_init(struct v4l2_subdev *sd,
+ struct msm_cam_media_controller *mctl)
+{
+ int rc = 0;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ v4l2_set_subdev_hostdata(sd, mctl);
+ spin_lock_init(&axi_ctrl->tasklet_lock);
+ INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
+ spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
+
+ axi_ctrl->share_ctrl->vfebase = ioremap(axi_ctrl->vfemem->start,
+ resource_size(axi_ctrl->vfemem));
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ rc = -ENOMEM;
+ pr_err("%s: vfe ioremap failed\n", __func__);
+ goto remap_failed;
+ }
+
+ if (axi_ctrl->fs_vfe == NULL) {
+ axi_ctrl->fs_vfe =
+ regulator_get(&axi_ctrl->pdev->dev, "vdd");
+ if (IS_ERR(axi_ctrl->fs_vfe)) {
+ pr_err("%s: Regulator FS_VFE get failed %ld\n",
+ __func__, PTR_ERR(axi_ctrl->fs_vfe));
+ axi_ctrl->fs_vfe = NULL;
+ goto fs_failed;
+ } else if (regulator_enable(axi_ctrl->fs_vfe)) {
+ pr_err("%s: Regulator FS_VFE enable failed\n",
+ __func__);
+ regulator_put(axi_ctrl->fs_vfe);
+ axi_ctrl->fs_vfe = NULL;
+ goto fs_failed;
+ }
+ }
+ rc = msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+ axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 1);
+ if (rc < 0)
+ goto clk_enable_failed;
+
+ msm_camio_bus_scale_cfg(
+ mctl->sdata->pdata->cam_bus_scale_table, S_INIT);
+ msm_camio_bus_scale_cfg(
+ mctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+
+ axi_ctrl->share_ctrl->register_total = VFE40_REGISTER_TOTAL;
+
+ enable_irq(axi_ctrl->vfeirq->start);
+
+ return rc;
+clk_enable_failed:
+ regulator_disable(axi_ctrl->fs_vfe);
+ regulator_put(axi_ctrl->fs_vfe);
+ axi_ctrl->fs_vfe = NULL;
+fs_failed:
+ iounmap(axi_ctrl->share_ctrl->vfebase);
+ axi_ctrl->share_ctrl->vfebase = NULL;
+remap_failed:
+ disable_irq(axi_ctrl->vfeirq->start);
+ return rc;
+}
+
+void msm_axi_subdev_release(struct v4l2_subdev *sd)
+{
+ struct msm_cam_media_controller *pmctl =
+ (struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return;
+ }
+
+ CDBG("%s, free_irq\n", __func__);
+ disable_irq(axi_ctrl->vfeirq->start);
+ tasklet_kill(&axi_ctrl->vfe40_tasklet);
+ msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+ axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 0);
+
+ if (axi_ctrl->fs_vfe) {
+ regulator_disable(axi_ctrl->fs_vfe);
+ regulator_put(axi_ctrl->fs_vfe);
+ axi_ctrl->fs_vfe = NULL;
+ }
+ iounmap(axi_ctrl->share_ctrl->vfebase);
+ axi_ctrl->share_ctrl->vfebase = NULL;
+
+ if (atomic_read(&axi_ctrl->share_ctrl->irq_cnt))
+ pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_EXIT);
+}
+
+static long msm_axi_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ int rc = -ENOIOCTLCMD;
+ switch (cmd) {
+ case VIDIOC_MSM_AXI_INIT:
+ rc = msm_axi_subdev_init(sd,
+ (struct msm_cam_media_controller *)arg);
+ break;
+ case VIDIOC_MSM_AXI_CFG:
+ rc = msm_axi_config(sd, arg);
+ break;
+ case VIDIOC_MSM_AXI_IRQ:
+ msm_axi_process_irq(sd, arg);
+ rc = 0;
+ break;
+ case VIDIOC_MSM_AXI_BUF_CFG:
+ msm_axi_buf_cfg(sd, arg);
+ rc = 0;
+ break;
+ case VIDIOC_MSM_AXI_RELEASE:
+ msm_axi_subdev_release(sd);
+ rc = 0;
+ break;
+ default:
+ pr_err("%s: command not found\n", __func__);
+ }
+ return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
+ .ioctl = msm_axi_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = {
+ .s_crystal_freq = msm_axi_subdev_s_crystal_freq,
+};
+
+static const struct v4l2_subdev_ops msm_axi_subdev_ops = {
+ .core = &msm_axi_subdev_core_ops,
+ .video = &msm_axi_subdev_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_axi_internal_ops;
+
+void vfe40_axi_probe(struct axi_ctrl_t *axi_ctrl)
+{
+ struct msm_cam_subdev_info sd_info;
+ v4l2_subdev_init(&axi_ctrl->subdev, &msm_axi_subdev_ops);
+ axi_ctrl->subdev.internal_ops = &msm_axi_internal_ops;
+ axi_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(axi_ctrl->subdev.name,
+ sizeof(axi_ctrl->subdev.name), "axi");
+ v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl);
+
+ sd_info.sdev_type = AXI_DEV;
+ sd_info.sd_index = axi_ctrl->pdev->id;
+ sd_info.irq_num = 0;
+ msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
+}
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index aeda38c..7e59c98 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -169,6 +169,7 @@
dma_addr_t dmov_cmd_dma[2];
struct tsif_xfer xfer[2];
struct tasklet_struct dma_refill;
+ struct tasklet_struct clocks_off;
/* statistics */
u32 stat_rx;
u32 stat_overflow;
@@ -251,18 +252,24 @@
{
if (on) {
if (tsif_device->tsif_clk)
- clk_enable(tsif_device->tsif_clk);
+ clk_prepare_enable(tsif_device->tsif_clk);
if (tsif_device->tsif_pclk)
- clk_enable(tsif_device->tsif_pclk);
- clk_enable(tsif_device->tsif_ref_clk);
+ clk_prepare_enable(tsif_device->tsif_pclk);
+ clk_prepare_enable(tsif_device->tsif_ref_clk);
} else {
if (tsif_device->tsif_clk)
- clk_disable(tsif_device->tsif_clk);
+ clk_disable_unprepare(tsif_device->tsif_clk);
if (tsif_device->tsif_pclk)
- clk_disable(tsif_device->tsif_pclk);
- clk_disable(tsif_device->tsif_ref_clk);
+ clk_disable_unprepare(tsif_device->tsif_pclk);
+ clk_disable_unprepare(tsif_device->tsif_ref_clk);
}
}
+
+static void tsif_clocks_off(unsigned long data)
+{
+ struct msm_tsif_device *tsif_device = (struct msm_tsif_device *) data;
+ tsif_clock(tsif_device, 0);
+}
/* ===clocks end=== */
/* ===gpio begin=== */
@@ -605,17 +612,15 @@
if (tsif_device->state == tsif_state_running) {
tsif_stop_hw(tsif_device);
/*
- * Clocks _may_ be stopped right from IRQ
- * context. This is far from optimal w.r.t
- * latency.
- *
- * But, this branch taken only in case of
+ * This branch is taken only in case of
* severe hardware problem (I don't even know
- * what should happens for DMOV_RSLT_ERROR);
+ * what should happen for DMOV_RSLT_ERROR);
* thus I prefer code simplicity over
* performance.
+ * Clocks are turned off from outside the
+ * interrupt context.
*/
- tsif_clock(tsif_device, 0);
+ tasklet_schedule(&tsif_device->clocks_off);
tsif_device->state = tsif_state_flushing;
}
}
@@ -1313,6 +1318,8 @@
tsif_device->chunks_per_buf = TSIF_CHUNKS_IN_BUF_DEFAULT;
tasklet_init(&tsif_device->dma_refill, tsif_dma_refill,
(unsigned long)tsif_device);
+ tasklet_init(&tsif_device->clocks_off, tsif_clocks_off,
+ (unsigned long)tsif_device);
if (tsif_get_clocks(tsif_device))
goto err_clocks;
/* map I/O memory */
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d13b914..e4d0fc1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1988,11 +1988,15 @@
{
u8 rst_n_function;
- if (!mmc_card_mmc(card))
+ if (mmc_card_sdio(card))
return 0;
- rst_n_function = card->ext_csd.rst_n_function;
- if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
- return 0;
+
+ if (mmc_card_mmc(card)) {
+ rst_n_function = card->ext_csd.rst_n_function;
+ if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) !=
+ EXT_CSD_RST_N_ENABLED)
+ return 0;
+ }
return 1;
}
EXPORT_SYMBOL(mmc_can_reset);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 23cb03d..b22e2f0 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -2385,8 +2385,10 @@
struct msm_mmc_reg_data *vreg_table[2];
curr_slot = host->plat->vreg_data;
- if (!curr_slot)
+ if (!curr_slot) {
+ rc = -EINVAL;
goto out;
+ }
vreg_table[0] = curr_slot->vdd_data;
vreg_table[1] = curr_slot->vdd_io_data;
@@ -3988,6 +3990,51 @@
return rc;
}
+/*
+ * Work around of the unavailability of a power_reset functionality in SD cards
+ * by turning the OFF & back ON the regulators supplying the SD card.
+ */
+void msmsdcc_hw_reset(struct mmc_host *mmc)
+{
+ struct mmc_card *card = mmc->card;
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ int rc;
+
+ /* Write-protection bits would be lost on a hardware reset in emmc */
+ if (!card || !mmc_card_sd(card))
+ return;
+
+ /*
+ * Continuing on failing to disable regulator would lead to a panic
+ * anyway, since the commands would fail and console would be flooded
+ * with prints, eventually leading to a watchdog bark
+ */
+ rc = msmsdcc_setup_vreg(host, false, false);
+ if (rc) {
+ pr_err("%s: %s disable regulator: failed: %d\n",
+ mmc_hostname(mmc), __func__, rc);
+ BUG_ON(rc);
+ }
+
+ /* 10ms delay for the supply to reach the desired voltage level */
+ usleep_range(10000, 12000);
+
+ /*
+ * Continuing on failing to enable regulator would lead to a panic
+ * anyway, since the commands would fail and console would be flooded
+ * with prints, eventually leading to a watchdog bark
+ */
+ rc = msmsdcc_setup_vreg(host, true, false);
+ if (rc) {
+ pr_err("%s: %s enable regulator: failed: %d\n",
+ mmc_hostname(mmc), __func__, rc);
+ BUG_ON(rc);
+ }
+
+ /* 10ms delay for the supply to reach the desired voltage level */
+ usleep_range(10000, 12000);
+}
+
static const struct mmc_host_ops msmsdcc_ops = {
.enable = msmsdcc_enable,
.disable = msmsdcc_disable,
@@ -3998,7 +4045,8 @@
.get_ro = msmsdcc_get_ro,
.enable_sdio_irq = msmsdcc_enable_sdio_irq,
.start_signal_voltage_switch = msmsdcc_switch_io_voltage,
- .execute_tuning = msmsdcc_execute_tuning
+ .execute_tuning = msmsdcc_execute_tuning,
+ .hw_reset = msmsdcc_hw_reset,
};
static unsigned int
@@ -5595,7 +5643,7 @@
mmc->caps |= plat->mmc_bus_width;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
-
+ mmc->caps |= MMC_CAP_HW_RESET;
/*
* If we send the CMD23 before multi block write/read command
* then we need not to send CMD12 at the end of the transfer.
diff --git a/drivers/of/of_slimbus.c b/drivers/of/of_slimbus.c
index 512ca73..8aaef25 100644
--- a/drivers/of/of_slimbus.c
+++ b/drivers/of/of_slimbus.c
@@ -66,6 +66,8 @@
kfree(slim);
return -ENOMEM;
}
+
+ slim->dev.of_node = of_node_get(node);
slim->name = (const char *)name;
binfo[n].bus_num = ctrl->nr;
binfo[n].slim_slave = slim;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index d3edfa8..b7c73de 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -18,13 +18,14 @@
#include <linux/io.h>
#include <linux/stat.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
#include <mach/sps.h>
#include <linux/workqueue.h>
#define USB_SUMMING_THRESHOLD 512
-#define CONNECTIONS_NUM 4
+#define CONNECTIONS_NUM 4
static struct sps_bam_props usb_props;
static struct sps_pipe *sps_pipes[CONNECTIONS_NUM][2];
@@ -43,32 +44,35 @@
struct usb_bam_connect_info {
u8 idx;
- u8 *src_pipe;
- u8 *dst_pipe;
+ u32 *src_pipe;
+ u32 *dst_pipe;
struct usb_bam_wake_event_info peer_event;
bool enabled;
};
static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
+static struct usb_bam_pipe_connect ***msm_usb_bam_connections_info;
+static struct usb_bam_pipe_connect *bam_connection_arr;
+
+static bool device_tree_enabled;
static inline int bam_offset(struct msm_usb_bam_platform_data *pdata)
{
return pdata->usb_active_bam * CONNECTIONS_NUM * 2;
}
-static int connect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
- u8 *usb_pipe_idx)
+static int connect_pipe(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+ u32 *usb_pipe_idx)
{
int ret;
- struct sps_pipe **pipe = &sps_pipes[connection_idx][pipe_dir];
+ struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
struct sps_connect *connection =
- &sps_connections[connection_idx][pipe_dir];
+ &sps_connections[conn_idx][pipe_dir];
struct msm_usb_bam_platform_data *pdata =
- (struct msm_usb_bam_platform_data *)
- (usb_bam_pdev->dev.platform_data);
+ usb_bam_pdev->dev.platform_data;
struct usb_bam_pipe_connect *pipe_connection =
- (struct usb_bam_pipe_connect *)(pdata->connections +
- bam_offset(pdata) + (2*connection_idx+pipe_dir));
+ (struct usb_bam_pipe_connect *)(pdata->connections +
+ bam_offset(pdata) + (2*conn_idx+pipe_dir));
*pipe = sps_alloc_endpoint();
if (*pipe == NULL) {
@@ -105,26 +109,54 @@
*usb_pipe_idx = connection->dest_pipe_index;
}
- ret = sps_setup_bam2bam_fifo(
- &data_mem_buf[connection_idx][pipe_dir],
+ if (!device_tree_enabled) {
+ ret = sps_setup_bam2bam_fifo(
+ &data_mem_buf[conn_idx][pipe_dir],
pipe_connection->data_fifo_base_offset,
pipe_connection->data_fifo_size, 1);
- if (ret) {
- pr_err("%s: data fifo setup failure %d\n", __func__, ret);
- goto fifo_setup_error;
- }
- connection->data = data_mem_buf[connection_idx][pipe_dir];
+ if (ret) {
+ pr_err("%s: data fifo setup failure %d\n", __func__,
+ ret);
+ goto fifo_setup_error;
+ }
- ret = sps_setup_bam2bam_fifo(
- &desc_mem_buf[connection_idx][pipe_dir],
+ ret = sps_setup_bam2bam_fifo(
+ &desc_mem_buf[conn_idx][pipe_dir],
pipe_connection->desc_fifo_base_offset,
pipe_connection->desc_fifo_size, 1);
- if (ret) {
- pr_err("%s: desc. fifo setup failure %d\n", __func__, ret);
- goto fifo_setup_error;
+ if (ret) {
+ pr_err("%s: desc. fifo setup failure %d\n", __func__,
+ ret);
+ goto fifo_setup_error;
+ }
+ } else {
+ data_mem_buf[conn_idx][pipe_dir].phys_base =
+ pipe_connection->data_fifo_base_offset +
+ pdata->usb_base_address;
+ data_mem_buf[conn_idx][pipe_dir].size =
+ pipe_connection->data_fifo_size;
+ data_mem_buf[conn_idx][pipe_dir].base =
+ ioremap(data_mem_buf[conn_idx][pipe_dir].phys_base,
+ data_mem_buf[conn_idx][pipe_dir].size);
+ memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
+ data_mem_buf[conn_idx][pipe_dir].size);
+
+ desc_mem_buf[conn_idx][pipe_dir].phys_base =
+ pipe_connection->desc_fifo_base_offset +
+ pdata->usb_base_address;
+ desc_mem_buf[conn_idx][pipe_dir].size =
+ pipe_connection->desc_fifo_size;
+ desc_mem_buf[conn_idx][pipe_dir].base =
+ ioremap(desc_mem_buf[conn_idx][pipe_dir].phys_base,
+ desc_mem_buf[conn_idx][pipe_dir].size);
+ memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
+ desc_mem_buf[conn_idx][pipe_dir].size);
}
- connection->desc = desc_mem_buf[connection_idx][pipe_dir];
+
+ connection->data = data_mem_buf[conn_idx][pipe_dir];
+ connection->desc = desc_mem_buf[conn_idx][pipe_dir];
connection->event_thresh = 16;
+ connection->options = SPS_O_AUTO_ENABLE;
ret = sps_connect(*pipe, connection);
if (ret < 0) {
@@ -141,7 +173,22 @@
return ret;
}
-int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+
+static int disconnect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
+ u32 *usb_pipe_idx)
+{
+ struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
+ struct sps_connect *connection =
+ &sps_connections[connection_idx][pipe_dir];
+
+ sps_disconnect(pipe);
+ sps_free_endpoint(pipe);
+
+ connection->options &= ~SPS_O_AUTO_ENABLE;
+ return 0;
+}
+
+int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
{
struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
int ret;
@@ -153,7 +200,7 @@
}
if (connection->enabled) {
- pr_info("%s: connection %d was already established\n",
+ pr_debug("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
@@ -161,19 +208,23 @@
connection->dst_pipe = dst_pipe_idx;
connection->idx = idx;
- /* open USB -> Peripheral pipe */
- ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
- connection->src_pipe);
- if (ret) {
- pr_err("%s: src pipe connection failure\n", __func__);
- return ret;
+ if (src_pipe_idx) {
+ /* open USB -> Peripheral pipe */
+ ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
+ connection->src_pipe);
+ if (ret) {
+ pr_err("%s: src pipe connection failure\n", __func__);
+ return ret;
+ }
}
- /* open Peripheral -> USB pipe */
- ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
- connection->dst_pipe);
- if (ret) {
- pr_err("%s: dst pipe connection failure\n", __func__);
- return ret;
+ if (dst_pipe_idx) {
+ /* open Peripheral -> USB pipe */
+ ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
+ connection->dst_pipe);
+ if (ret) {
+ pr_err("%s: dst pipe connection failure\n", __func__);
+ return ret;
+ }
}
connection->enabled = 1;
@@ -232,19 +283,259 @@
return 0;
}
+int usb_bam_disconnect_pipe(u8 idx)
+{
+ struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+ int ret;
+
+ if (idx >= CONNECTIONS_NUM) {
+ pr_err("%s: Invalid connection index\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (!connection->enabled) {
+ pr_debug("%s: connection %d isn't enabled\n",
+ __func__, idx);
+ return 0;
+ }
+
+ if (connection->src_pipe) {
+ /* close USB -> Peripheral pipe */
+ ret = disconnect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
+ connection->src_pipe);
+ if (ret) {
+ pr_err("%s: src pipe connection failure\n", __func__);
+ return ret;
+ }
+
+ }
+ if (connection->dst_pipe) {
+ /* close Peripheral -> USB pipe */
+ ret = disconnect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
+ connection->dst_pipe);
+ if (ret) {
+ pr_err("%s: dst pipe connection failure\n", __func__);
+ return ret;
+ }
+ }
+
+ connection->src_pipe = 0;
+ connection->dst_pipe = 0;
+ connection->enabled = 0;
+
+ return 0;
+}
+
+static int update_connections_info(struct device_node *node, int bam,
+ int conn_num, int dir)
+{
+ u32 rc;
+ char *key = NULL;
+ uint32_t val = 0;
+
+ struct usb_bam_pipe_connect *pipe_connection;
+
+ pipe_connection = &msm_usb_bam_connections_info[bam][conn_num][dir];
+
+ key = "qcom,src-bam-physical-address";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->src_phy_addr = val;
+
+ key = "qcom,src-bam-pipe-index";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->src_pipe_index = val;
+
+ key = "qcom,dst-bam-physical-address";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->dst_phy_addr = val;
+
+ key = "qcom,dst-bam-pipe-index";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->dst_pipe_index = val;
+
+ key = "qcom,data-fifo-offset";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->data_fifo_base_offset = val;
+
+ key = "qcom,data-fifo-size";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->data_fifo_size = val;
+
+ key = "qcom,descriptor-fifo-offset";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->desc_fifo_base_offset = val;
+
+ key = "qcom,descriptor-fifo-size";
+ rc = of_property_read_u32(node, key, &val);
+ if (rc)
+ goto err;
+ pipe_connection->desc_fifo_size = val;
+
+ return 0;
+
+err:
+ pr_err("%s: Error in name %s key %s\n", __func__,
+ node->full_name, key);
+ return -EFAULT;
+}
+
+static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
+ struct platform_device *pdev)
+{
+ struct msm_usb_bam_platform_data *pdata;
+ struct device_node *node = pdev->dev.of_node;
+ u32 i, j;
+ int conn_num, bam;
+ u8 dir;
+ u8 ncolumns = 2;
+ int bam_amount, rc = 0;
+ u32 pipe_entry = 0;
+ char *key = NULL;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("unable to allocate platform data\n");
+ return NULL;
+ }
+
+ rc = of_property_read_u32(node, "qcom,usb-active-bam",
+ &pdata->usb_active_bam);
+ if (rc) {
+ pr_err("Invalid usb active bam property\n");
+ return NULL;
+ }
+
+ rc = of_property_read_u32(node, "qcom,usb-total-bam-num",
+ &pdata->total_bam_num);
+ if (rc) {
+ pr_err("Invalid usb total bam num property\n");
+ return NULL;
+ }
+
+ rc = of_property_read_u32(node, "qcom,usb-bam-num-pipes",
+ &pdata->usb_bam_num_pipes);
+ if (rc) {
+ pr_err("Invalid usb bam num pipes property\n");
+ return NULL;
+ }
+
+ rc = of_property_read_u32(node, "qcom,usb-base-address",
+ &pdata->usb_base_address);
+ if (rc) {
+ pr_err("Invalid usb base address property\n");
+ return NULL;
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, node)
+ pipe_entry++;
+
+ /*
+ * we need to know the number of connection, so we will know
+ * how much memory to allocate
+ */
+ conn_num = pipe_entry / 2;
+ bam_amount = pdata->total_bam_num;
+
+ if (conn_num > 0 && conn_num < pdata->usb_bam_num_pipes) {
+ /* alloc msm_usb_bam_connections_info */
+ bam_connection_arr = devm_kzalloc(&pdev->dev, bam_amount *
+ conn_num * ncolumns *
+ sizeof(struct usb_bam_pipe_connect), GFP_KERNEL);
+
+ if (!bam_connection_arr)
+ goto err;
+
+ msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
+ bam_amount * sizeof(struct usb_bam_pipe_connect **),
+ GFP_KERNEL);
+
+ if (!msm_usb_bam_connections_info)
+ goto err;
+
+ for (j = 0; j < bam_amount; j++) {
+ msm_usb_bam_connections_info[j] =
+ devm_kzalloc(&pdev->dev, conn_num *
+ sizeof(struct usb_bam_pipe_connect *),
+ GFP_KERNEL);
+ for (i = 0; i < conn_num; i++)
+ msm_usb_bam_connections_info[j][i] =
+ bam_connection_arr +
+ (j * conn_num * ncolumns) +
+ (i * ncolumns);
+ }
+
+ /* retrieve device tree parameters */
+ for_each_child_of_node(pdev->dev.of_node, node) {
+ const char *str;
+
+ key = "qcom,usb-bam-type";
+ rc = of_property_read_u32(node, key, &bam);
+ if (rc)
+ goto err;
+
+ rc = of_property_read_string(node, "label", &str);
+ if (rc) {
+ pr_err("Cannot read string\n");
+ goto err;
+ }
+
+ if (strstr(str, "usb-to-peri"))
+ dir = USB_TO_PEER_PERIPHERAL;
+ else if (strstr(str, "peri-to-usb"))
+ dir = PEER_PERIPHERAL_TO_USB;
+ else
+ goto err;
+
+ if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
+ !strcmp(str, "peri-to-usb-qdss-dwc3"))
+ conn_num = 0;
+ else
+ goto err;
+
+ rc = update_connections_info(node, bam, conn_num, dir);
+ if (rc)
+ goto err;
+ }
+
+ pdata->connections = &msm_usb_bam_connections_info[0][0][0];
+
+ } else {
+ goto err;
+ }
+
+ return pdata;
+err:
+ pr_err("%s: failed\n", __func__);
+ return NULL;
+}
+
static int usb_bam_init(void)
{
u32 h_usb;
int ret;
void *usb_virt_addr;
struct msm_usb_bam_platform_data *pdata =
- (struct msm_usb_bam_platform_data *)
- (usb_bam_pdev->dev.platform_data);
+ usb_bam_pdev->dev.platform_data;
struct resource *res;
int irq;
res = platform_get_resource(usb_bam_pdev, IORESOURCE_MEM,
- pdata->usb_active_bam);
+ pdata->usb_active_bam);
if (!res) {
dev_err(&usb_bam_pdev->dev, "Unable to get memory resource\n");
return -ENODEV;
@@ -266,6 +557,7 @@
usb_props.virt_size = resource_size(res);
usb_props.irq = irq;
usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
+ usb_props.event_threshold = 512;
usb_props.num_pipes = pdata->usb_bam_num_pipes;
ret = sps_register_bam_device(&usb_props, &h_usb);
@@ -286,11 +578,10 @@
usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct platform_device *pdev = container_of(dev, struct platform_device,
- dev);
+ struct platform_device *pdev =
+ container_of(dev, struct platform_device, dev);
struct msm_usb_bam_platform_data *pdata =
- (struct msm_usb_bam_platform_data *)
- (usb_bam_pdev->dev.platform_data);
+ usb_bam_pdev->dev.platform_data;
if (!pdev || !pdata)
return 0;
@@ -302,11 +593,10 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct platform_device *pdev = container_of(dev, struct platform_device,
- dev);
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
struct msm_usb_bam_platform_data *pdata =
- (struct msm_usb_bam_platform_data *)
- (usb_bam_pdev->dev.platform_data);
+ usb_bam_pdev->dev.platform_data;
char str[10], *pstr;
int ret, i;
@@ -336,6 +626,7 @@
static int usb_bam_probe(struct platform_device *pdev)
{
int ret, i;
+ struct msm_usb_bam_platform_data *pdata;
dev_dbg(&pdev->dev, "usb_bam_probe\n");
@@ -345,9 +636,19 @@
usb_bam_wake_work);
}
- if (!pdev->dev.platform_data) {
+ if (pdev->dev.of_node) {
+ dev_dbg(&pdev->dev, "device tree enabled\n");
+ device_tree_enabled = 1;
+ pdata = usb_bam_dt_to_pdata(pdev);
+ if (!pdata)
+ return -ENOMEM;
+ pdev->dev.platform_data = pdata;
+ } else if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "missing platform_data\n");
return -ENODEV;
+ } else {
+ pdata = pdev->dev.platform_data;
+ device_tree_enabled = 0;
}
usb_bam_pdev = pdev;
@@ -365,6 +666,32 @@
return ret;
}
+void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+ u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+ struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
+{
+ struct sps_connect *connection =
+ &sps_connections[conn_idx][pipe_dir];
+
+
+ if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
+ *usb_bam_handle = connection->source;
+ *usb_bam_pipe_idx = connection->src_pipe_index;
+ *peer_pipe_idx = connection->dest_pipe_index;
+ } else {
+ *usb_bam_handle = connection->destination;
+ *usb_bam_pipe_idx = connection->dest_pipe_index;
+ *peer_pipe_idx = connection->src_pipe_index;
+ }
+ if (data_fifo)
+ memcpy(data_fifo, &data_mem_buf[conn_idx][pipe_dir],
+ sizeof(struct sps_mem_buffer));
+ if (desc_fifo)
+ memcpy(desc_fifo, &desc_mem_buf[conn_idx][pipe_dir],
+ sizeof(struct sps_mem_buffer));
+}
+EXPORT_SYMBOL(get_bam2bam_connection_info);
+
static int usb_bam_remove(struct platform_device *pdev)
{
destroy_workqueue(usb_bam_wq);
@@ -372,10 +699,20 @@
return 0;
}
+static const struct of_device_id usb_bam_dt_match[] = {
+ { .compatible = "qcom,usb-bam-msm",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, usb_bam_dt_match);
+
static struct platform_driver usb_bam_driver = {
.probe = usb_bam_probe,
.remove = usb_bam_remove,
- .driver = { .name = "usb_bam", },
+ .driver = {
+ .name = "usb_bam",
+ .of_match_table = usb_bam_dt_match,
+ },
};
static int __init init(void)
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index f84e3ac..85b653d 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -248,6 +248,7 @@
bool ext_charging;
bool ext_charge_done;
bool iusb_fine_res;
+ bool dc_unplug_check;
DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
struct work_struct battery_id_valid_work;
int64_t batt_id_min;
@@ -2447,6 +2448,10 @@
}
} else if (active_path & DC_ACTIVE_BIT) {
pr_debug("DC charger active\n");
+ /* Some board designs are not prone to reverse boost on DC
+ * charging path */
+ if (!chip->dc_unplug_check)
+ return;
} else {
/* No charger active */
if (!(is_usb_chg_plugged_in(chip)
@@ -4000,6 +4005,7 @@
chip->warm_temp_dc = INT_MIN;
chip->temp_check_period = pdata->temp_check_period;
+ chip->dc_unplug_check = pdata->dc_unplug_check;
chip->max_bat_chg_current = pdata->max_bat_chg_current;
chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 8cef99e..72564b0 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2949,6 +2949,7 @@
mutex_unlock(&ctrl->sched.m_reconf);
return ret;
}
+EXPORT_SYMBOL_GPL(slim_ctrl_clk_pause);
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 6628b79..0628d2e 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -98,10 +98,10 @@
#define TSENS_THRESHOLD_MIN_CODE 0x0
#define TSENS_CTRL_INIT_DATA1 0x3fffff9
-#define TSENS_GLOBAL_INIT_DATA 0x20013
-#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1ba
+#define TSENS_GLOBAL_INIT_DATA 0x302f16c
+#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
-#define TSENS_SN_REMOTE_CFG_DATA 0xdba
+#define TSENS_SN_REMOTE_CFG_DATA 0x11c3
/* Trips: warm and cool */
enum tsens_trip_type {
@@ -212,7 +212,7 @@
return 0;
}
-EXPORT_SYMBOL(msm_tsens_get_temp);
+EXPORT_SYMBOL(tsens_get_temp);
static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
enum thermal_device_mode *mode)
@@ -474,13 +474,15 @@
static int tsens_calib_sensors(void)
{
- int i, tsens_base1_data, tsens0_point1, tsens1_point1;
- int tsens2_point1, tsens3_point1, tsens4_point1, tsens5_point1;
- int tsens6_point1, tsens7_point1, tsens8_point1, tsens9_point1;
- int tsens10_point1, tsens0_point2, tsens1_point2, tsens2_point2;
- int tsens3_point2, tsens4_point2, tsens5_point2, tsens6_point2;
- int tsens7_point2, tsens8_point2, tsens9_point2, tsens10_point2;
- int tsens_base2_data, tsens_calibration_mode, temp;
+ int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
+ int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
+ int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
+ int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
+ int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
+ int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
+ int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
+ int tsens9_point2 = 0, tsens10_point2 = 0;
+ int tsens_base2_data = 0, tsens_calibration_mode = 0, temp;
uint32_t calib_data[5];
for (i = 0; i < 5; i++)
@@ -492,12 +494,14 @@
temp = (calib_data[3] & TSENS_CAL_SEL_2
>> TSENS_CAL_SEL_SHIFT_2);
tsens_calibration_mode |= temp;
- /* Remove this after bringup */
- tsens_calibration_mode = TSENS_ONE_POINT_CALIB;
if (!tsens_calibration_mode) {
- pr_err("TSENS not calibrated\n");
- return -ENODEV;
+ pr_debug("TSENS is calibrationless mode\n");
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ tmdev->sensor[i].calib_data_point2 = 78000;
+ tmdev->sensor[i].calib_data_point1 = 49200;
+ goto compute_intercept_slope;
+ }
} else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
TSENS_TWO_POINT_CALIB) {
tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
@@ -525,63 +529,72 @@
tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
- } else
+ } else {
pr_debug("Calibration mode is unknown: %d\n",
tsens_calibration_mode);
+ return -ENODEV;
+ }
- tmdev->sensor[0].calib_data_point1 =
+ if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
+ tmdev->sensor[0].calib_data_point1 =
(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[0].calib_data_point2 =
- (((tsens_base2_data + tsens0_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[1].calib_data_point1 =
+ tmdev->sensor[1].calib_data_point1 =
(((tsens_base1_data + tsens1_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[1].calib_data_point2 =
- (((tsens_base2_data + tsens1_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[2].calib_data_point1 =
+ tmdev->sensor[2].calib_data_point1 =
(((tsens_base1_data + tsens2_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[2].calib_data_point2 =
- (((tsens_base2_data + tsens2_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[3].calib_data_point1 =
+ tmdev->sensor[3].calib_data_point1 =
(((tsens_base1_data + tsens3_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[3].calib_data_point2 =
- (((tsens_base2_data + tsens3_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[4].calib_data_point1 =
+ tmdev->sensor[4].calib_data_point1 =
(((tsens_base1_data + tsens4_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[4].calib_data_point2 =
- (((tsens_base2_data + tsens4_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[5].calib_data_point1 =
+ tmdev->sensor[5].calib_data_point1 =
(((tsens_base1_data + tsens5_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[5].calib_data_point2 =
- (((tsens_base2_data + tsens5_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[6].calib_data_point1 =
+ tmdev->sensor[6].calib_data_point1 =
(((tsens_base1_data + tsens6_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[6].calib_data_point2 =
- (((tsens_base2_data + tsens6_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[7].calib_data_point1 =
+ tmdev->sensor[7].calib_data_point1 =
(((tsens_base1_data + tsens7_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[7].calib_data_point2 =
- (((tsens_base2_data + tsens7_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[8].calib_data_point1 =
+ tmdev->sensor[8].calib_data_point1 =
(((tsens_base1_data + tsens8_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[8].calib_data_point2 =
- (((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[9].calib_data_point1 =
+ tmdev->sensor[9].calib_data_point1 =
(((tsens_base1_data + tsens9_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[9].calib_data_point2 =
- (((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
- tmdev->sensor[10].calib_data_point1 =
+ tmdev->sensor[10].calib_data_point1 =
(((tsens_base1_data + tsens10_point1) << 2) | TSENS_BIT_APPEND);
- tmdev->sensor[10].calib_data_point2 =
- (((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
+ }
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ tmdev->sensor[0].calib_data_point2 =
+ (((tsens_base2_data + tsens0_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[1].calib_data_point2 =
+ (((tsens_base2_data + tsens1_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[2].calib_data_point2 =
+ (((tsens_base2_data + tsens2_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[3].calib_data_point2 =
+ (((tsens_base2_data + tsens3_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[4].calib_data_point2 =
+ (((tsens_base2_data + tsens4_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[5].calib_data_point2 =
+ (((tsens_base2_data + tsens5_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[6].calib_data_point2 =
+ (((tsens_base2_data + tsens6_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[7].calib_data_point2 =
+ (((tsens_base2_data + tsens7_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[8].calib_data_point2 =
+ (((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[9].calib_data_point2 =
+ (((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[10].calib_data_point2 =
+ (((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
+ }
+
+compute_intercept_slope:
for (i = 0; i < tmdev->tsens_num_sensor; i++) {
int32_t num = 0, den = 0;
- num = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT2;
- den = tmdev->sensor[i].calib_data_point2 -
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ num = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT2;
+ den = tmdev->sensor[i].calib_data_point2 -
tmdev->sensor[i].calib_data_point1;
- num *= tmdev->tsens_factor;
- if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)
+ num *= tmdev->tsens_factor;
tmdev->sensor[i].slope_mul_tsens_factor = num/den;
+ }
tmdev->sensor[i].offset = (TSENS_CAL_DEGC_POINT1 *
tmdev->tsens_factor)
- (tmdev->sensor[i].calib_data_point1 *
@@ -615,7 +628,7 @@
}
rc = of_property_read_u32_array(of_node,
- "qcom,slope", tsens_slope_data, tsens_num_sensors/sizeof(u32));
+ "qcom,slope", tsens_slope_data, tsens_num_sensors);
if (rc) {
dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
return rc;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 4d15d4d..4d15c55 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -54,6 +54,7 @@
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
+#include <linux/ratelimit.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -74,6 +75,7 @@
*****************************************************************************/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define ATDTW_SET_DELAY 100 /* 100msec delay */
/* ctrl register bank access */
static DEFINE_SPINLOCK(udc_lock);
@@ -1764,6 +1766,7 @@
struct ci13xxx_req *mReqPrev;
int n = hw_ep_bit(mEp->num, mEp->dir);
int tmp_stat;
+ ktime_t start, diff;
mReqPrev = list_entry(mEp->qh.queue.prev,
struct ci13xxx_req, queue);
@@ -1774,9 +1777,20 @@
wmb();
if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto done;
+ start = ktime_get();
do {
hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
+ diff = ktime_sub(ktime_get(), start);
+ /* poll for max. 100ms */
+ if (ktime_to_ms(diff) > ATDTW_SET_DELAY) {
+ if (hw_cread(CAP_USBCMD, USBCMD_ATDTW))
+ break;
+ printk_ratelimited(KERN_ERR
+ "%s:queue failed ep#%d %s\n",
+ __func__, mEp->num, mEp->dir ? "IN" : "OUT");
+ return -EAGAIN;
+ }
} while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
if (tmp_stat)
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 7b6acc6..3d6ceaa 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -572,6 +572,7 @@
#ifdef CONFIG_MODEM_SUPPORT
usb_ep_fifo_flush(gser->notify);
usb_ep_disable(gser->notify);
+ gser->notify->driver_data = NULL;
#endif
gser->online = 0;
}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 1fade88..a9e5d91 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -98,8 +98,8 @@
struct usb_request *rx_req;
struct usb_request *tx_req;
- u8 src_pipe_idx;
- u8 dst_pipe_idx;
+ u32 src_pipe_idx;
+ u32 dst_pipe_idx;
u8 connection_idx;
/* stats */
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 73b4e75..a105f5d 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -50,8 +50,8 @@
struct usb_request *rx_req;
struct usb_request *tx_req;
- u8 src_pipe_idx;
- u8 dst_pipe_idx;
+ u32 src_pipe_idx;
+ u32 dst_pipe_idx;
u8 connection_idx;
};
diff --git a/drivers/usb/gadget/u_ctrl_hsuart.c b/drivers/usb/gadget/u_ctrl_hsuart.c
index 7102d81..a55960e 100644
--- a/drivers/usb/gadget/u_ctrl_hsuart.c
+++ b/drivers/usb/gadget/u_ctrl_hsuart.c
@@ -289,7 +289,7 @@
void ghsuart_ctrl_disconnect(void *gptr, int port_num)
{
- struct gctrl_port *port;
+ struct ghsuart_ctrl_port *port;
struct grmnet *gr = NULL;
unsigned long flags;
@@ -300,7 +300,7 @@
return;
}
- port = gctrl_ports[port_num].port;
+ port = ghsuart_ctrl_ports[port_num].port;
if (!gptr || !port) {
pr_err("%s: grmnet port is null\n", __func__);
@@ -372,7 +372,7 @@
static void ghsuart_ctrl_port_free(int portno)
{
struct ghsuart_ctrl_port *port = ghsuart_ctrl_ports[portno].port;
- struct platform_driver *pdrv = &gctrl_ports[portno].pdrv;
+ struct platform_driver *pdrv = &ghsuart_ctrl_ports[portno].pdrv;
destroy_workqueue(port->wq);
if (pdrv)
diff --git a/drivers/usb/gadget/u_data_hsuart.c b/drivers/usb/gadget/u_data_hsuart.c
index 91b1190..74bb93f 100644
--- a/drivers/usb/gadget/u_data_hsuart.c
+++ b/drivers/usb/gadget/u_data_hsuart.c
@@ -843,12 +843,15 @@
ghsuart_data_free_buffers(port);
/* disable endpoints */
- if (port->in)
+ if (port->in) {
usb_ep_disable(port->in);
+ port->in->driver_data = NULL;
+ }
- if (port->out)
+ if (port->out) {
usb_ep_disable(port->out);
-
+ port->out->driver_data = NULL;
+ }
atomic_set(&port->connected, 0);
if (port->gtype == USB_GADGET_SERIAL) {
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index 5e9b0ec..a604e1e 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -990,8 +990,10 @@
/* disable endpoints, aborting down any active I/O */
usb_ep_disable(gser->out);
+ gser->out->driver_data = NULL;
usb_ep_disable(gser->in);
+ gser->in->driver_data = NULL;
spin_lock_irqsave(&port->port_lock, flags);
gsdio_free_requests(gser->out, &port->read_pool);
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index a5ceaff..ce285a3 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -712,7 +712,9 @@
/* disable endpoints, aborting down any active I/O */
usb_ep_disable(gser->out);
+ gser->out->driver_data = NULL;
usb_ep_disable(gser->in);
+ gser->in->driver_data = NULL;
spin_lock_irqsave(&port->port_lock, flags);
gsmd_free_requests(gser->out, &port->read_pool);
diff --git a/drivers/video/msm/lcdc.c b/drivers/video/msm/lcdc.c
index 863d59d..2170abe 100644
--- a/drivers/video/msm/lcdc.c
+++ b/drivers/video/msm/lcdc.c
@@ -37,6 +37,7 @@
static int lcdc_off(struct platform_device *pdev);
static int lcdc_on(struct platform_device *pdev);
+static void cont_splash_clk_ctrl(int enable);
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
@@ -100,6 +101,8 @@
#endif
mfd = platform_get_drvdata(pdev);
+ cont_splash_clk_ctrl(0);
+
if (lcdc_pdata && lcdc_pdata->lcdc_get_clk)
panel_pixclock_freq = lcdc_pdata->lcdc_get_clk();
@@ -151,6 +154,20 @@
return ret;
}
+static void cont_splash_clk_ctrl(int enable)
+{
+ static int cont_splash_clks_enabled;
+ if (enable && !cont_splash_clks_enabled) {
+ clk_prepare_enable(pixel_mdp_clk);
+ clk_prepare_enable(pixel_lcdc_clk);
+ cont_splash_clks_enabled = 1;
+ } else if (!enable && cont_splash_clks_enabled) {
+ clk_disable_unprepare(pixel_mdp_clk);
+ clk_disable_unprepare(pixel_lcdc_clk);
+ cont_splash_clks_enabled = 0;
+ }
+}
+
static int lcdc_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
@@ -199,6 +216,8 @@
if (!mdp_dev)
return -ENOMEM;
+ cont_splash_clk_ctrl(1);
+
/*
* link to the latest pdev
*/
diff --git a/drivers/video/msm/lcdc_truly_ips3p2335.c b/drivers/video/msm/lcdc_truly_ips3p2335.c
index a4a370e..b2f4ab8 100644
--- a/drivers/video/msm/lcdc_truly_ips3p2335.c
+++ b/drivers/video/msm/lcdc_truly_ips3p2335.c
@@ -148,6 +148,13 @@
static int lcdc_truly_panel_on(struct platform_device *pdev)
{
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+ if (!mfd->cont_splash_done) {
+ mfd->cont_splash_done = 1;
+ return 0;
+ }
+
/* Configure reset GPIO that drives DAC */
if (lcdc_truly_pdata->panel_config_gpio)
lcdc_truly_pdata->panel_config_gpio(1);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index bfaed8d..8e6f347 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2018,6 +2018,17 @@
return ret;
}
+#ifdef CONFIG_FB_MSM_MDP303
+unsigned is_mdp4_hw_reset(void)
+{
+ return 0;
+}
+void mdp4_hw_init(void)
+{
+ /* empty */
+}
+#endif
+
static int mdp_on(struct platform_device *pdev)
{
int ret = 0;
@@ -2044,6 +2055,7 @@
#endif
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
ret = panel_next_on(pdev);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -2321,7 +2333,8 @@
if (!(mdp_pdata->cont_splash_enabled))
mdp4_hw_init();
#else
- mdp_hw_init();
+ if (!(mdp_pdata->cont_splash_enabled))
+ mdp_hw_init();
#endif
#ifdef CONFIG_FB_MSM_OVERLAY
@@ -2359,8 +2372,10 @@
if (mdp_pdata->cont_splash_enabled) {
mfd->cont_splash_done = 0;
if (!contSplash_update_done) {
- mdp_pipe_ctrl(MDP_CMD_BLOCK,
- MDP_BLOCK_POWER_ON, FALSE);
+ if (mfd->panel.type == MIPI_VIDEO_PANEL ||
+ mfd->panel.type == LCDC_PANEL)
+ mdp_pipe_ctrl(MDP_CMD_BLOCK,
+ MDP_BLOCK_POWER_ON, FALSE);
contSplash_update_done = 1;
}
} else
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 1ba5b8d..3d6448f 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -26,6 +26,7 @@
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
+#include "mipi_dsi.h"
#define DSI_VIDEO_BASE 0xF0000
#define DMA_P_BASE 0x90000
@@ -128,6 +129,7 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
/* starting address */
MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x8, (uint32) buf);
@@ -191,6 +193,13 @@
ctrl_polarity = (data_en_polarity << 2) |
(vsync_polarity << 1) | (hsync_polarity);
+ if (!(mfd->cont_splash_done)) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK,
+ MDP_BLOCK_POWER_OFF, FALSE);
+ MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+ mipi_dsi_controller_cfg(0);
+ }
+
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, vsync_pulse_width);
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index c418e9c..f9bf269 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -249,6 +249,12 @@
ctrl_polarity =
(data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
+ if (!(mfd->cont_splash_done)) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK,
+ MDP_BLOCK_POWER_OFF, FALSE);
+ MDP_OUTP(MDP_BASE + timer_base, 0);
+ }
+
MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl);
MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period);
MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period);
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 04178fa..94c24ee 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -482,6 +482,11 @@
mipi = &mfd->panel_info.mipi;
+ if (!mfd->cont_splash_done) {
+ mfd->cont_splash_done = 1;
+ return 0;
+ }
+
if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel)
rotate = mipi_nt35510_pdata->rotate_panel();
diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c
index 17ee976..18e8ac5 100644
--- a/drivers/video/msm/msm_dss_io_7x27a.c
+++ b/drivers/video/msm/msm_dss_io_7x27a.c
@@ -317,6 +317,24 @@
void cont_splash_clk_ctrl(int enable)
{
+ static int cont_splash_clks_enabled;
+ if (enable && !cont_splash_clks_enabled) {
+ clk_prepare_enable(dsi_ref_clk);
+ clk_prepare_enable(mdp_dsi_pclk);
+ clk_prepare_enable(dsi_byte_div_clk);
+ clk_prepare_enable(dsi_esc_clk);
+ clk_prepare_enable(dsi_pixel_clk);
+ clk_prepare_enable(dsi_clk);
+ cont_splash_clks_enabled = 1;
+ } else if (!enable && cont_splash_clks_enabled) {
+ clk_disable_unprepare(dsi_clk);
+ clk_disable_unprepare(dsi_pixel_clk);
+ clk_disable_unprepare(dsi_esc_clk);
+ clk_disable_unprepare(dsi_byte_div_clk);
+ clk_disable_unprepare(mdp_dsi_pclk);
+ clk_disable_unprepare(dsi_ref_clk);
+ cont_splash_clks_enabled = 0;
+ }
}
void mipi_dsi_prepare_clocks(void)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 72e3600..b6f4874 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1483,7 +1483,10 @@
ret = 0;
#ifdef CONFIG_HAS_EARLYSUSPEND
- if (hdmi_prim_display || mfd->panel_info.type != DTV_PANEL) {
+
+ if (hdmi_prim_display ||
+ (mfd->panel_info.type != DTV_PANEL &&
+ mfd->panel_info.type != WRITEBACK_PANEL)) {
mfd->early_suspend.suspend = msmfb_early_suspend;
mfd->early_suspend.resume = msmfb_early_resume;
mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 22eaf4f..72fe2e3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1302,6 +1302,7 @@
ddl_process_decoder_metadata(ddl);
vidc_sm_get_aspect_ratio_info(
&ddl->shared_mem[ddl->command_channel],
+ decoder->codec.codec,
&output_vcd_frm->aspect_ratio_info);
ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
vcd_status, output_frame,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 839a9c1..d45de2d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -205,6 +205,10 @@
#define VIDC_SM_ASPECT_RATIO_INFO_ADDR 0x00c8
#define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK 0xf
#define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT 0x0
+#define VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK 0x000f0000
+#define VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT 16
+#define VIDC_SM_H264_ASPECT_RATIO_INFO_BMSK 0x00000ff0
+#define VIDC_SM_H264_ASPECT_RATIO_INFO_SHFT 4
#define VIDC_SM_EXTENDED_PAR_ADDR 0x00cc
#define VIDC_SM_EXTENDED_PAR_WIDTH_BMSK 0xffff0000
#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT 16
@@ -802,23 +806,160 @@
}
void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
- struct vcd_aspect_ratio *aspect_ratio_info)
+ enum vcd_codec codec, struct vcd_aspect_ratio *aspect_ratio_info)
{
- u32 extended_par_info = 0;
- aspect_ratio_info->aspect_ratio = DDL_MEM_READ_32(shared_mem,
+ u32 extended_par_info = 0, aspect_ratio = 0;
+
+ aspect_ratio = DDL_MEM_READ_32(shared_mem,
VIDC_SM_ASPECT_RATIO_INFO_ADDR);
- if (aspect_ratio_info->aspect_ratio == 0x0f) {
- extended_par_info = DDL_MEM_READ_32(shared_mem,
- VIDC_SM_EXTENDED_PAR_ADDR);
- aspect_ratio_info->extended_par_width =
- VIDC_GETFIELD(extended_par_info,
- VIDC_SM_EXTENDED_PAR_WIDTH_BMSK,
- VIDC_SM_EXTENDED_PAR_WIDTH_SHFT);
- aspect_ratio_info->extended_par_height =
- VIDC_GETFIELD(extended_par_info,
- VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK,
- VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
+ if (codec == VCD_CODEC_H264) {
+ aspect_ratio_info->aspect_ratio =
+ VIDC_GETFIELD(aspect_ratio,
+ VIDC_SM_H264_ASPECT_RATIO_INFO_BMSK,
+ VIDC_SM_H264_ASPECT_RATIO_INFO_SHFT);
+
+ switch (aspect_ratio_info->aspect_ratio) {
+ case 1:
+ aspect_ratio_info->par_width = 1;
+ aspect_ratio_info->par_height = 1;
+ break;
+ case 2:
+ aspect_ratio_info->par_width = 12;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 3:
+ aspect_ratio_info->par_width = 10;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 4:
+ aspect_ratio_info->par_width = 16;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 5:
+ aspect_ratio_info->par_width = 40;
+ aspect_ratio_info->par_height = 33;
+ break;
+ case 6:
+ aspect_ratio_info->par_width = 24;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 7:
+ aspect_ratio_info->par_width = 20;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 8:
+ aspect_ratio_info->par_width = 32;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 9:
+ aspect_ratio_info->par_width = 80;
+ aspect_ratio_info->par_height = 33;
+ break;
+ case 10:
+ aspect_ratio_info->par_width = 18;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 11:
+ aspect_ratio_info->par_width = 15;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 12:
+ aspect_ratio_info->par_width = 64;
+ aspect_ratio_info->par_height = 33;
+ break;
+ case 13:
+ aspect_ratio_info->par_width = 160;
+ aspect_ratio_info->par_height = 99;
+ break;
+ case 14:
+ aspect_ratio_info->par_width = 4;
+ aspect_ratio_info->par_height = 3;
+ break;
+ case 15:
+ aspect_ratio_info->par_width = 3;
+ aspect_ratio_info->par_height = 2;
+ break;
+ case 16:
+ aspect_ratio_info->par_width = 2;
+ aspect_ratio_info->par_height = 1;
+ break;
+ case 255:
+ extended_par_info = DDL_MEM_READ_32(shared_mem,
+ VIDC_SM_EXTENDED_PAR_ADDR);
+ aspect_ratio_info->par_width =
+ VIDC_GETFIELD(extended_par_info,
+ VIDC_SM_EXTENDED_PAR_WIDTH_BMSK,
+ VIDC_SM_EXTENDED_PAR_WIDTH_SHFT);
+ aspect_ratio_info->par_height =
+ VIDC_GETFIELD(extended_par_info,
+ VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK,
+ VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
+ break;
+ default:
+ DDL_MSG_ERROR("Incorrect Aspect Ratio.");
+ aspect_ratio_info->par_width = 1;
+ aspect_ratio_info->par_height = 1;
+ break;
+ }
+ } else if ((codec == VCD_CODEC_MPEG4) ||
+ (codec == VCD_CODEC_DIVX_4) ||
+ (codec == VCD_CODEC_DIVX_5) ||
+ (codec == VCD_CODEC_DIVX_6) ||
+ (codec == VCD_CODEC_XVID) ||
+ (codec == VCD_CODEC_MPEG2)) {
+
+ if (codec == VCD_CODEC_MPEG2) {
+ aspect_ratio_info->aspect_ratio =
+ VIDC_GETFIELD(aspect_ratio,
+ VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK,
+ VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT);
+ } else {
+ aspect_ratio_info->aspect_ratio =
+ VIDC_GETFIELD(aspect_ratio,
+ VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK,
+ VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT);
+ }
+
+ switch (aspect_ratio_info->aspect_ratio) {
+ case 1:
+ aspect_ratio_info->par_width = 1;
+ aspect_ratio_info->par_height = 1;
+ break;
+ case 2:
+ aspect_ratio_info->par_width = 12;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 3:
+ aspect_ratio_info->par_width = 10;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 4:
+ aspect_ratio_info->par_width = 16;
+ aspect_ratio_info->par_height = 11;
+ break;
+ case 5:
+ aspect_ratio_info->par_width = 40;
+ aspect_ratio_info->par_height = 33;
+ break;
+ case 15:
+ extended_par_info = DDL_MEM_READ_32(shared_mem,
+ VIDC_SM_EXTENDED_PAR_ADDR);
+ aspect_ratio_info->par_width =
+ VIDC_GETFIELD(extended_par_info,
+ VIDC_SM_EXTENDED_PAR_WIDTH_BMSK,
+ VIDC_SM_EXTENDED_PAR_WIDTH_SHFT);
+ aspect_ratio_info->par_height =
+ VIDC_GETFIELD(extended_par_info,
+ VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK,
+ VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
+ break;
+ default:
+ DDL_MSG_ERROR("Incorrect Aspect Ratio.");
+ aspect_ratio_info->par_width = 1;
+ aspect_ratio_info->par_height = 1;
+ break;
+ }
}
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 6cd75595..1a46c36 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -180,7 +180,7 @@
struct ddl_buf_addr *shared_mem,
enum vidc_sm_num_stuff_bytes_consume_info consume_info);
void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
- struct vcd_aspect_ratio *aspect_ratio_info);
+ enum vcd_codec codec, struct vcd_aspect_ratio *aspect_ratio_info);
void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
u32 slice_batch_int_enable);
void vidc_sm_get_num_slices_comp(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 634011b..c3803b1 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -334,9 +334,9 @@
output_frame->aspect_ratio_info.aspect_ratio =
vcd_frame_data->aspect_ratio_info.aspect_ratio;
output_frame->aspect_ratio_info.par_width =
- vcd_frame_data->aspect_ratio_info.extended_par_width;
+ vcd_frame_data->aspect_ratio_info.par_width;
output_frame->aspect_ratio_info.par_height =
- vcd_frame_data->aspect_ratio_info.extended_par_height;
+ vcd_frame_data->aspect_ratio_info.par_height;
vdec_msg->vdec_msg_info.msgdatasize =
sizeof(struct vdec_output_frameinfo);
} else {
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index fca8700..b00e050 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -89,6 +89,10 @@
* @get_batt_capacity_percent:
* a board specific function to return battery
* capacity. If null - a default one will be used
+ * @dc_unplug_check: enables the reverse boosting fix for the DC_IN line
+ * however, this should only be enabled for devices which
+ * control the DC OVP FETs otherwise this option should
+ * remain disabled
* @trkl_voltage: the trkl voltage in (mV) below which hw controlled
* trkl charging happens with linear charger
* @weak_voltage: the weak voltage (mV) below which hw controlled
@@ -137,6 +141,7 @@
int64_t batt_id_min;
int64_t batt_id_max;
bool keep_btm_on_suspend;
+ bool dc_unplug_check;
int trkl_voltage;
int weak_voltage;
int trkl_current;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 3b1d06d..6a5231b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -389,21 +389,46 @@
bool core_clk_always_on_workaround;
};
+/**
+ * struct usb_bam_pipe_connect: pipe connection information
+ * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+ * either src BAM or dst BAM
+ * @src_phy_addr: src bam physical address.
+ * @src_pipe_index: src bam pipe index.
+ * @dst_phy_addr: dst bam physical address.
+ * @dst_pipe_index: dst bam pipe index.
+ * @data_fifo_base_offset: data fifo offset.
+ * @data_fifo_size: data fifo size.
+ * @desc_fifo_base_offset: descriptor fifo offset.
+ * @desc_fifo_size: descriptor fifo size.
+ */
struct usb_bam_pipe_connect {
u32 src_phy_addr;
- int src_pipe_index;
+ u32 src_pipe_index;
u32 dst_phy_addr;
- int dst_pipe_index;
+ u32 dst_pipe_index;
u32 data_fifo_base_offset;
u32 data_fifo_size;
u32 desc_fifo_base_offset;
u32 desc_fifo_size;
};
+/**
+ * struct msm_usb_bam_platform_data: pipe connection information
+ * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+ * either src BAM or dst BAM
+ * @connections: holds all pipe connections data.
+ * @usb_active_bam: set USB or HSIC as the active BAM.
+ * @usb_bam_num_pipes: max number of pipes to use.
+ * @active_conn_num: number of active pipe connections.
+ * @usb_base_address: BAM physical address.
+ */
struct msm_usb_bam_platform_data {
struct usb_bam_pipe_connect *connections;
int usb_active_bam;
int usb_bam_num_pipes;
+ u32 total_bam_num;
+ u32 usb_base_address;
};
enum usb_bam {
@@ -411,8 +436,27 @@
HSIC_BAM,
};
+#ifdef CONFIG_USB_DWC3_MSM
int msm_ep_config(struct usb_ep *ep);
int msm_ep_unconfig(struct usb_ep *ep);
-int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size);
+int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
+ u8 dst_pipe_idx);
+#else
+static inline int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
+ u8 dst_pipe_idx)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ep_config(struct usb_ep *ep)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ep_unconfig(struct usb_ep *ep)
+{
+ return -ENODEV;
+}
+#endif
#endif
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index c93b696..7104028 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -55,8 +55,8 @@
struct vcd_aspect_ratio {
u32 aspect_ratio;
- u32 extended_par_width;
- u32 extended_par_height;
+ u32 par_width;
+ u32 par_height;
};
struct vcd_frame_data {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 2a07002..11f7153 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -486,7 +486,8 @@
#define CMD_STATS_BG_BUF_RELEASE 56
#define CMD_STATS_BF_BUF_RELEASE 57
#define CMD_STATS_BHIST_BUF_RELEASE 58
-
+#define CMD_VFE_SOF_COUNT_UPDATE 59
+#define CMD_VFE_COUNT_SOF_ENABLE 60
#define CMD_AXI_CFG_PRIM BIT(8)
#define CMD_AXI_CFG_PRIM_ALL_CHNLS BIT(9)
@@ -497,6 +498,7 @@
#define CMD_AXI_START 0xE1
#define CMD_AXI_STOP 0xE2
+#define CMD_AXI_RESET 0xE3
#define AXI_CMD_PREVIEW BIT(0)
@@ -504,8 +506,7 @@
#define AXI_CMD_RECORD BIT(2)
#define AXI_CMD_ZSL BIT(3)
#define AXI_CMD_RAW_CAPTURE BIT(4)
-
-
+#define AXI_CMD_LIVESHOT BIT(5)
/* vfe config command: config command(from config thread)*/
struct msm_vfe_cfg_cmd {
@@ -1763,6 +1764,7 @@
uint32_t capture_count;
uint32_t skip_abort;
uint16_t port_info;
+ uint32_t inst_handle;
uint16_t cmd_type;
};
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index ab9e70c..9fa5932 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -65,7 +65,9 @@
#define MSG_ID_STATS_BG 46
#define MSG_ID_STATS_BF 47
#define MSG_ID_STATS_BHIST 48
-
+#define MSG_ID_RDI0_UPDATE_ACK 49
+#define MSG_ID_RDI1_UPDATE_ACK 50
+#define MSG_ID_RDI2_UPDATE_ACK 51
/* ISP command IDs */
#define VFE_CMD_DUMMY_0 0
@@ -218,6 +220,19 @@
#define VFE_CMD_STATS_BHIST_START 147
#define VFE_CMD_STATS_BHIST_STOP 148
#define VFE_CMD_RESET_2 149
+#define VFE_CMD_FOV_ENC_CFG 150
+#define VFE_CMD_FOV_VIEW_CFG 151
+#define VFE_CMD_FOV_ENC_UPDATE 152
+#define VFE_CMD_FOV_VIEW_UPDATE 153
+#define VFE_CMD_SCALER_ENC_CFG 154
+#define VFE_CMD_SCALER_VIEW_CFG 155
+#define VFE_CMD_SCALER_ENC_UPDATE 156
+#define VFE_CMD_SCALER_VIEW_UPDATE 157
+#define VFE_CMD_COLORXFORM_ENC_CFG 158
+#define VFE_CMD_COLORXFORM_VIEW_CFG 159
+#define VFE_CMD_COLORXFORM_ENC_UPDATE 160
+#define VFE_CMD_COLORXFORM_VIEW_UPDATE 161
+#define VFE_CMD_TEST_GEN_CFG 162
struct msm_isp_cmd {
int32_t id;
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index adbdada..d7b1340 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -176,6 +176,7 @@
V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI,
V4L2_CID_PRIVATE_SPUR_SELECTION,
V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
+ V4L2_CID_PRIVATE_VALID_CHANNEL,
};
@@ -336,6 +337,16 @@
RDS_AF_JUMP,
};
+/* Band limits */
+#define REGION_US_EU_BAND_LOW 87500
+#define REGION_US_EU_BAND_HIGH 108000
+#define REGION_JAPAN_STANDARD_BAND_LOW 76000
+#define REGION_JAPAN_STANDARD_BAND_HIGH 90000
+#define REGION_JAPAN_WIDE_BAND_LOW 90000
+#define REGION_JAPAN_WIDE_BAND_HIGH 108000
+#define MPX_DCC_BYPASS_REG 0x88C0
+#define MPX_DCC_DATA_REG 0x88C2
+
enum audio_path {
FM_DIGITAL_PATH,
FM_ANALOG_PATH
@@ -534,6 +545,12 @@
#define SPUR_TABLE_START_ADDR (SPUR_TABLE_ADDR + 1)
#define XFR_PEEK_COMPLETE (XFR_PEEK_MODE | READ_COMPLETE)
#define XFR_POKE_COMPLETE (XFR_POKE_MODE)
+#define TUNE_MULT (16)
+#define ADJ_CHANNEL_KHZ (50)
+#define MPX_DCC_UPPER_LIMIT (20000)
+#define MPX_DCC_LIMIT (12566)
+#define INVALID_CHANNEL (0)
+#define VALID_CHANNEL (1)
#define COMPUTE_SPUR(val) ((((val) - (76000)) / (50)))
#define GET_FREQ(val, bit) ((bit == 1) ? ((val) >> 8) : ((val) & 0xFF))
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 8129d97..5e5ad91 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
+#include <linux/netdevice.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
@@ -176,6 +177,7 @@
struct prio_sched_data *q = qdisc_priv(sch);
struct tc_prio_qopt *qopt;
int i;
+ int flow_change = 0;
if (nla_len(opt) < sizeof(*qopt))
return -EINVAL;
@@ -190,7 +192,10 @@
}
sch_tree_lock(sch);
- q->enable_flow = qopt->enable_flow;
+ if (q->enable_flow != qopt->enable_flow) {
+ q->enable_flow = qopt->enable_flow;
+ flow_change = 1;
+ }
q->bands = qopt->bands;
memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
@@ -225,6 +230,13 @@
}
}
}
+
+ /* Schedule qdisc when flow re-enabled */
+ if (flow_change && q->enable_flow) {
+ if (!test_bit(__QDISC_STATE_DEACTIVATED,
+ &sch->state))
+ __netif_schedule(qdisc_root(sch));
+ }
return 0;
}
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 15a5567..571e71c 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -3687,19 +3687,9 @@
return v_hs_max;
}
-static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+static void tabla_codec_calibrate_rel(struct snd_soc_codec *codec)
{
- u8 *n_ready, *n_cic;
- struct tabla_mbhc_btn_detect_cfg *btn_det;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
-
- btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
-
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
- v_ins_hu & 0xFF);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
- (v_ins_hu >> 8) & 0xFF);
snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
tabla->mbhc_data.v_b1_hu & 0xFF);
@@ -3720,6 +3710,23 @@
tabla->mbhc_data.v_brl & 0xFF);
snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
(tabla->mbhc_data.v_brl >> 8) & 0xFF);
+}
+
+static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+{
+ u8 *n_ready, *n_cic;
+ struct tabla_mbhc_btn_detect_cfg *btn_det;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
+
+ btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
+
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
+ v_ins_hu & 0xFF);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
+ (v_ins_hu >> 8) & 0xFF);
+
+ tabla_codec_calibrate_rel(codec);
n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
@@ -5671,15 +5678,55 @@
return r;
}
+static void tabla_mbhc_calc_rel_thres(struct snd_soc_codec *codec, s16 mv)
+{
+ s16 deltamv;
+ struct tabla_priv *tabla;
+ struct tabla_mbhc_btn_detect_cfg *btn_det;
+
+ tabla = snd_soc_codec_get_drvdata(codec);
+ btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
+
+ tabla->mbhc_data.v_b1_h =
+ tabla_codec_v_sta_dce(codec, DCE,
+ mv + btn_det->v_btn_press_delta_cic);
+
+ tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
+
+ tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
+
+ deltamv = mv + btn_det->v_btn_press_delta_sta;
+ tabla->mbhc_data.v_b1_hu = tabla_codec_v_sta_dce(codec, STA, deltamv);
+
+ deltamv = mv + btn_det->v_btn_press_delta_cic;
+ tabla->mbhc_data.v_b1_huc = tabla_codec_v_sta_dce(codec, DCE, deltamv);
+}
+
+static void tabla_mbhc_set_rel_thres(struct snd_soc_codec *codec, s16 mv)
+{
+ tabla_mbhc_calc_rel_thres(codec, mv);
+ tabla_codec_calibrate_rel(codec);
+}
+
+static s16 tabla_mbhc_highest_btn_mv(struct snd_soc_codec *codec)
+{
+ struct tabla_priv *tabla;
+ struct tabla_mbhc_btn_detect_cfg *btn_det;
+ u16 *btn_high;
+
+ tabla = snd_soc_codec_get_drvdata(codec);
+ btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
+ btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
+
+ return btn_high[btn_det->num_btn - 1];
+}
+
static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
{
struct tabla_priv *tabla;
- s16 btn_mv = 0, btn_delta_mv;
struct tabla_mbhc_btn_detect_cfg *btn_det;
struct tabla_mbhc_plug_type_cfg *plug_type;
- u16 *btn_high;
u8 *n_ready;
- int i;
tabla = snd_soc_codec_get_drvdata(codec);
btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
@@ -5730,22 +5777,7 @@
false);
}
- btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
- for (i = 0; i < btn_det->num_btn; i++)
- btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
-
- tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
- btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
- tabla->mbhc_data.v_b1_hu =
- tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
-
- btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
-
- tabla->mbhc_data.v_b1_huc =
- tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
-
- tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
- tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
+ tabla_mbhc_calc_rel_thres(codec, tabla_mbhc_highest_btn_mv(codec));
tabla->mbhc_data.v_no_mic =
tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
@@ -5904,8 +5936,9 @@
{
int i, mask;
short dce, sta;
- s32 mv, mv_s, stamv_s;
+ s32 mv, mv_s, stamv, stamv_s;
bool vddio;
+ u16 *btn_high;
int btn = -1, meas = 0;
struct tabla_priv *priv = data;
const struct tabla_mbhc_btn_detect_cfg *d =
@@ -5918,6 +5951,7 @@
pr_debug("%s: enter\n", __func__);
+ btn_high = tabla_mbhc_cal_btn_det_mp(d, TABLA_BTN_DET_V_BTN_HIGH);
TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
pr_debug("%s: mbhc is being recovered, skip button press\n",
@@ -5954,35 +5988,34 @@
pr_debug("%s: Button is already released shortly after "
"resume\n", __func__);
n_btn_meas = 0;
- } else {
- pr_debug("%s: Button is already released without "
- "resume", __func__);
- sta = tabla_codec_read_sta_result(codec);
- stamv_s = tabla_codec_sta_dce_v(codec, 0, sta);
- if (vddio)
- stamv_s = tabla_scale_v_micb_vddio(priv,
- stamv_s,
- false);
- btn = tabla_determine_button(priv, mv_s);
- if (btn != tabla_determine_button(priv, stamv_s))
- btn = -1;
- goto done;
}
}
- /* determine pressed button */
+ /* save hw dce */
btnmeas[meas++] = tabla_determine_button(priv, mv_s);
- pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n", __func__,
- meas - 1, dce, mv, mv_s, btnmeas[meas - 1]);
- if (n_btn_meas == 0)
- btn = btnmeas[0];
+ pr_debug("%s: meas HW - DCE %x,%d,%d button %d\n", __func__,
+ dce, mv, mv_s, btnmeas[0]);
+ if (n_btn_meas == 0) {
+ sta = tabla_codec_read_sta_result(codec);
+ stamv_s = stamv = tabla_codec_sta_dce_v(codec, 0, sta);
+ if (vddio)
+ stamv_s = tabla_scale_v_micb_vddio(priv, stamv, false);
+ btn = tabla_determine_button(priv, stamv_s);
+ pr_debug("%s: meas HW - STA %x,%d,%d button %d\n", __func__,
+ sta, stamv, stamv_s, btn);
+ BUG_ON(meas != 1);
+ if (btnmeas[0] != btn)
+ btn = -1;
+ }
+
+ /* determine pressed button */
for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
dce = tabla_codec_sta_dce(codec, 1, false);
mv = tabla_codec_sta_dce_v(codec, 1, dce);
mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
btnmeas[meas] = tabla_determine_button(priv, mv_s);
- pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n",
+ pr_debug("%s: meas %d - DCE %x,%d,%d button %d\n",
__func__, meas, dce, mv, mv_s, btnmeas[meas]);
/* if large enough measurements are collected,
* start to check if last all n_btn_con measurements were
@@ -6010,6 +6043,8 @@
"press\n", __func__);
goto done;
}
+ /* narrow down release threshold */
+ tabla_mbhc_set_rel_thres(codec, btn_high[btn]);
mask = tabla_get_button_mask(btn);
priv->buttons_pressed |= mask;
wcd9xxx_lock_sleep(core);
@@ -6115,6 +6150,8 @@
priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
}
+ /* revert narrowed release threshold */
+ tabla_mbhc_calc_rel_thres(codec, tabla_mbhc_highest_btn_mv(codec));
tabla_codec_calibrate_hs_polling(codec);
if (priv->mbhc_cfg.gpio)
diff --git a/sound/soc/msm/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index b18117c..359414b 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -531,6 +531,7 @@
list_first_entry(&prtd->free_in_queue,
struct voip_buf_node, list);
list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
if (prtd->mode == MODE_PCM) {
ret = copy_from_user(&buf_node->frame.voc_pkt,
buf, count);
@@ -538,6 +539,7 @@
} else
ret = copy_from_user(&buf_node->frame,
buf, count);
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
list_add_tail(&buf_node->list, &prtd->in_queue);
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
} else {
@@ -582,6 +584,7 @@
buf_node = list_first_entry(&prtd->out_queue,
struct voip_buf_node, list);
list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
if (prtd->mode == MODE_PCM)
ret = copy_to_user(buf,
&buf_node->frame.voc_pkt,
@@ -595,6 +598,7 @@
__func__, ret);
ret = -EFAULT;
}
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
list_add_tail(&buf_node->list,
&prtd->free_out_queue);
spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);